diff --git a/console/package-lock.json b/console/package-lock.json index de820873e887e..1d6a8f9794e95 100644 --- a/console/package-lock.json +++ b/console/package-lock.json @@ -94,6 +94,12 @@ "supports-color": "^5.3.0" } }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", @@ -252,6 +258,11 @@ "@types/jquery": "*" } }, + "@types/graphql": { + "version": "0.12.6", + "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.12.6.tgz", + "integrity": "sha512-wXAVyLfkG1UMkKOdMijVWFky39+OD/41KftzqfX1Oejd0Gm6dOIKjCihSVECg6X7PHjftxXmfOKA/d1H79ZfvQ==" + }, "@types/jquery": { "version": "3.2.16", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.2.16.tgz", @@ -265,9 +276,9 @@ "dev": true }, "@types/minimatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.1.tgz", - "integrity": "sha512-rUO/jz10KRSyA9SHoCWQ8WX9BICyj5jZYu1/ucKEJKb4KzLZCKMURdYbadP157Q6Zl1x0vHsrU+Z/O0XlhYQDw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", "dev": true }, "@types/mocha": { @@ -293,14 +304,14 @@ } }, "@webassemblyjs/ast": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.5.12.tgz", - "integrity": "sha512-bmTBEKuuhSU6dC95QIW250xO769cdYGx9rWn3uBLTw2pUpud0Z5kVuMw9m9fqbNzGeuOU2HpyuZa+yUt2CTEDA==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.5.13.tgz", + "integrity": "sha512-49nwvW/Hx9i+OYHg+mRhKZfAlqThr11Dqz8TsrvqGKMhdI2ijy3KBJOun2Z4770TPjrIJhR6KxChQIDaz8clDA==", "dev": true, "requires": { - "@webassemblyjs/helper-module-context": "1.5.12", - "@webassemblyjs/helper-wasm-bytecode": "1.5.12", - "@webassemblyjs/wast-parser": "1.5.12", + "@webassemblyjs/helper-module-context": "1.5.13", + "@webassemblyjs/helper-wasm-bytecode": "1.5.13", + "@webassemblyjs/wast-parser": "1.5.13", "debug": "^3.1.0", "mamacro": "^0.0.3" }, @@ -317,21 +328,21 @@ } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.12.tgz", - "integrity": "sha512-epTvkdwOIPpTE9edHS+V+shetYzpTbd91XOzUli1zAS0+NSgSe6ZsNggIqUNzhma1s4bN2f/m8c6B1NMdCERAg==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.13.tgz", + "integrity": "sha512-vrvvB18Kh4uyghSKb0NTv+2WZx871WL2NzwMj61jcq2bXkyhRC+8Q0oD7JGVf0+5i/fKQYQSBCNMMsDMRVAMqA==", "dev": true }, "@webassemblyjs/helper-api-error": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.12.tgz", - "integrity": "sha512-Goxag86JvLq8ucHLXFNSLYzf9wrR+CJr37DsESTAzSnGoqDTgw5eqiXSQVd/D9Biih7+DIn8UIQCxMs8emRRwg==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.13.tgz", + "integrity": "sha512-dBh2CWYqjaDlvMmRP/kudxpdh30uXjIbpkLj9HQe+qtYlwvYjPRjdQXrq1cTAAOUSMTtzqbXIxEdEZmyKfcwsg==", "dev": true }, "@webassemblyjs/helper-buffer": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.12.tgz", - "integrity": "sha512-tJNUjttL5CxiiS/KLxT4/Zk0Nbl/poFhztFxktb46zoQEUWaGHR9ZJ0SnvE7DbFX5PY5JNJDMZ0Li4lm246fWw==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.13.tgz", + "integrity": "sha512-v7igWf1mHcpJNbn4m7e77XOAWXCDT76Xe7Is1VQFXc4K5jRcFrl9D0NrqM4XifQ0bXiuTSkTKMYqDxu5MhNljA==", "dev": true, "requires": { "debug": "^3.1.0" @@ -349,24 +360,24 @@ } }, "@webassemblyjs/helper-code-frame": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.12.tgz", - "integrity": "sha512-0FrJgiST+MQDMvPigzs+UIk1vslLIqGadkEWdn53Lr0NsUC2JbheG9QaO3Zf6ycK2JwsHiUpGaMFcHYXStTPMA==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.13.tgz", + "integrity": "sha512-yN6ScQQDFCiAXnVctdVO/J5NQRbwyTbQzsGzEgXsAnrxhjp0xihh+nNHQTMrq5UhOqTb5LykpJAvEv9AT0jnAQ==", "dev": true, "requires": { - "@webassemblyjs/wast-printer": "1.5.12" + "@webassemblyjs/wast-printer": "1.5.13" } }, "@webassemblyjs/helper-fsm": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.12.tgz", - "integrity": "sha512-QBHZ45VPUJ7UyYKvUFoaxrSS9H5hbkC9U7tdWgFHmnTMutkXSEgDg2gZg3I/QTsiKOCIwx4qJUJwPd7J4D5CNQ==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.13.tgz", + "integrity": "sha512-hSIKzbXjVMRvy3Jzhgu+vDd/aswJ+UMEnLRCkZDdknZO3Z9e6rp1DAs0tdLItjCFqkz9+0BeOPK/mk3eYvVzZg==", "dev": true }, "@webassemblyjs/helper-module-context": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.12.tgz", - "integrity": "sha512-SCXR8hPI4JOG3cdy9HAO8W5/VQ68YXG/Hfs7qDf1cd64zWuMNshyEour5NYnLMVkrrtc0XzfVS/MdeV94woFHA==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.13.tgz", + "integrity": "sha512-zxJXULGPLB7r+k+wIlvGlXpT4CYppRz8fLUM/xobGHc9Z3T6qlmJD9ySJ2jknuktuuiR9AjnNpKYDECyaiX+QQ==", "dev": true, "requires": { "debug": "^3.1.0", @@ -385,21 +396,21 @@ } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.12.tgz", - "integrity": "sha512-0Gz5lQcyvElNVbOTKwjEmIxGwdWf+zpAW/WGzGo95B7IgMEzyyfZU+PrGHDwiSH9c0knol9G7smQnY0ljrSA6g==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.13.tgz", + "integrity": "sha512-0n3SoNGLvbJIZPhtMFq0XmmnA/YmQBXaZKQZcW8maGKwLpVcgjNrxpFZHEOLKjXJYVN5Il8vSfG7nRX50Zn+aw==", "dev": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.12.tgz", - "integrity": "sha512-ge/CKVKBGpiJhFN9PIOQ7sPtGYJhxm/mW1Y3SpG1L6XBunfRz0YnLjW3TmhcOEFozIVyODPS1HZ9f7VR3GBGow==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.13.tgz", + "integrity": "sha512-IJ/goicOZ5TT1axZFSnlAtz4m8KEjYr12BNOANAwGFPKXM4byEDaMNXYowHMG0yKV9a397eU/NlibFaLwr1fbw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.12", - "@webassemblyjs/helper-buffer": "1.5.12", - "@webassemblyjs/helper-wasm-bytecode": "1.5.12", - "@webassemblyjs/wasm-gen": "1.5.12", + "@webassemblyjs/ast": "1.5.13", + "@webassemblyjs/helper-buffer": "1.5.13", + "@webassemblyjs/helper-wasm-bytecode": "1.5.13", + "@webassemblyjs/wasm-gen": "1.5.13", "debug": "^3.1.0" }, "dependencies": { @@ -415,43 +426,51 @@ } }, "@webassemblyjs/ieee754": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.5.12.tgz", - "integrity": "sha512-F+PEv9QBzPi1ThLBouUJbuxhEr+Sy/oua1ftXFKHiaYYS5Z9tKPvK/hgCxlSdq+RY4MSG15jU2JYb/K5pkoybg==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.5.13.tgz", + "integrity": "sha512-TseswvXEPpG5TCBKoLx9tT7+/GMACjC1ruo09j46ULRZWYm8XHpDWaosOjTnI7kr4SRJFzA6MWoUkAB+YCGKKg==", "dev": true, "requires": { "ieee754": "^1.1.11" } }, "@webassemblyjs/leb128": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.5.12.tgz", - "integrity": "sha512-cCOx/LVGiWyCwVrVlvGmTdnwHzIP4+zflLjGkZxWpYCpdNax9krVIJh1Pm7O86Ox/c5PrJpbvZU1cZLxndlPEw==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.5.13.tgz", + "integrity": "sha512-0NRMxrL+GG3eISGZBmLBLAVjphbN8Si15s7jzThaw1UE9e5BY1oH49/+MA1xBzxpf1OW5sf9OrPDOclk9wj2yg==", "dev": true, "requires": { - "leb": "^0.3.0" + "long": "4.0.0" + }, + "dependencies": { + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "dev": true + } } }, "@webassemblyjs/utf8": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.5.12.tgz", - "integrity": "sha512-FX8NYQMiTRU0TfK/tJVntsi9IEKsedSsna8qtsndWVE0x3zLndugiApxdNMIOoElBV9o4j0BUqR+iwU58QfPxQ==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.5.13.tgz", + "integrity": "sha512-Ve1ilU2N48Ew0lVGB8FqY7V7hXjaC4+PeZM+vDYxEd+R2iQ0q+Wb3Rw8v0Ri0+rxhoz6gVGsnQNb4FjRiEH/Ng==", "dev": true }, "@webassemblyjs/wasm-edit": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.12.tgz", - "integrity": "sha512-r/oZAyC4EZl0ToOYJgvj+b0X6gVEKQMLT34pNNbtvWBehQOnaSXvVUA5FIYlH8ubWjFNAFqYaVGgQTjR1yuJdQ==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.5.12", - "@webassemblyjs/helper-buffer": "1.5.12", - "@webassemblyjs/helper-wasm-bytecode": "1.5.12", - "@webassemblyjs/helper-wasm-section": "1.5.12", - "@webassemblyjs/wasm-gen": "1.5.12", - "@webassemblyjs/wasm-opt": "1.5.12", - "@webassemblyjs/wasm-parser": "1.5.12", - "@webassemblyjs/wast-printer": "1.5.12", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.13.tgz", + "integrity": "sha512-X7ZNW4+Hga4f2NmqENnHke2V/mGYK/xnybJSIXImt1ulxbCOEs/A+ZK/Km2jgihjyVxp/0z0hwIcxC6PrkWtgw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.5.13", + "@webassemblyjs/helper-buffer": "1.5.13", + "@webassemblyjs/helper-wasm-bytecode": "1.5.13", + "@webassemblyjs/helper-wasm-section": "1.5.13", + "@webassemblyjs/wasm-gen": "1.5.13", + "@webassemblyjs/wasm-opt": "1.5.13", + "@webassemblyjs/wasm-parser": "1.5.13", + "@webassemblyjs/wast-printer": "1.5.13", "debug": "^3.1.0" }, "dependencies": { @@ -467,28 +486,28 @@ } }, "@webassemblyjs/wasm-gen": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.12.tgz", - "integrity": "sha512-LTu+cr1YRxGGiVIXWhei/35lXXEwTnQU18x4V/gE+qCSJN21QcVTMjJuasTUh8WtmBZtOlqJbOQIeN7fGnHWhg==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.13.tgz", + "integrity": "sha512-yfv94Se8R73zmr8GAYzezFHc3lDwE/lBXQddSiIZEKZFuqy7yWtm3KMwA1uGbv5G1WphimJxboXHR80IgX1hQA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.12", - "@webassemblyjs/helper-wasm-bytecode": "1.5.12", - "@webassemblyjs/ieee754": "1.5.12", - "@webassemblyjs/leb128": "1.5.12", - "@webassemblyjs/utf8": "1.5.12" + "@webassemblyjs/ast": "1.5.13", + "@webassemblyjs/helper-wasm-bytecode": "1.5.13", + "@webassemblyjs/ieee754": "1.5.13", + "@webassemblyjs/leb128": "1.5.13", + "@webassemblyjs/utf8": "1.5.13" } }, "@webassemblyjs/wasm-opt": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.12.tgz", - "integrity": "sha512-LBwG5KPA9u/uigZVyTsDpS3CVxx3AePCnTItVL+OPkRCp5LqmLsOp4a3/c5CQE0Lecm0Ss9hjUTDcbYFZkXlfQ==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.13.tgz", + "integrity": "sha512-IkXSkgzVhQ0QYAdIayuCWMmXSYx0dHGU8Ah/AxJf1gBvstMWVnzJnBwLsXLyD87VSBIcsqkmZ28dVb0mOC3oBg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.12", - "@webassemblyjs/helper-buffer": "1.5.12", - "@webassemblyjs/wasm-gen": "1.5.12", - "@webassemblyjs/wasm-parser": "1.5.12", + "@webassemblyjs/ast": "1.5.13", + "@webassemblyjs/helper-buffer": "1.5.13", + "@webassemblyjs/wasm-gen": "1.5.13", + "@webassemblyjs/wasm-parser": "1.5.13", "debug": "^3.1.0" }, "dependencies": { @@ -504,45 +523,135 @@ } }, "@webassemblyjs/wasm-parser": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.12.tgz", - "integrity": "sha512-xset3+1AtoFYEfMg30nzCGBnhKmTBzbIKvMyLhqJT06TvYV+kA884AOUpUvhSmP6XPF3G+HVZPm/PbCGxH4/VQ==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.13.tgz", + "integrity": "sha512-XnYoIcu2iqq8/LrtmdnN3T+bRjqYFjRHqWbqK3osD/0r/Fcv4d9ecRzjVtC29ENEuNTK4mQ9yyxCBCbK8S/cpg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.12", - "@webassemblyjs/helper-api-error": "1.5.12", - "@webassemblyjs/helper-wasm-bytecode": "1.5.12", - "@webassemblyjs/ieee754": "1.5.12", - "@webassemblyjs/leb128": "1.5.12", - "@webassemblyjs/utf8": "1.5.12" + "@webassemblyjs/ast": "1.5.13", + "@webassemblyjs/helper-api-error": "1.5.13", + "@webassemblyjs/helper-wasm-bytecode": "1.5.13", + "@webassemblyjs/ieee754": "1.5.13", + "@webassemblyjs/leb128": "1.5.13", + "@webassemblyjs/utf8": "1.5.13" } }, "@webassemblyjs/wast-parser": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.5.12.tgz", - "integrity": "sha512-QWUtzhvfY7Ue9GlJ3HeOB6w5g9vNYUUnG+Y96TWPkFHJTxZlcvGfNrUoACCw6eDb9gKaHrjt77aPq41a7y8svg==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.5.13.tgz", + "integrity": "sha512-Lbz65T0LQ1LgzKiUytl34CwuhMNhaCLgrh0JW4rJBN6INnBB8NMwUfQM+FxTnLY9qJ+lHJL/gCM5xYhB9oWi4A==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.12", - "@webassemblyjs/floating-point-hex-parser": "1.5.12", - "@webassemblyjs/helper-api-error": "1.5.12", - "@webassemblyjs/helper-code-frame": "1.5.12", - "@webassemblyjs/helper-fsm": "1.5.12", + "@webassemblyjs/ast": "1.5.13", + "@webassemblyjs/floating-point-hex-parser": "1.5.13", + "@webassemblyjs/helper-api-error": "1.5.13", + "@webassemblyjs/helper-code-frame": "1.5.13", + "@webassemblyjs/helper-fsm": "1.5.13", "long": "^3.2.0", "mamacro": "^0.0.3" } }, "@webassemblyjs/wast-printer": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.5.12.tgz", - "integrity": "sha512-XF9RTeckFgDyl196uRKZWHFFfbkzsMK96QTXp+TC0R9gsV9DMiDGMSIllgy/WdrZ3y3dsQp4fTA5r4GoaOBchA==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.5.13.tgz", + "integrity": "sha512-QcwogrdqcBh8Z+eUF8SG+ag5iwQSXxQJELBEHmLkk790wgQgnIMmntT2sMAMw53GiFNckArf5X0bsCA44j3lWQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.12", - "@webassemblyjs/wast-parser": "1.5.12", + "@webassemblyjs/ast": "1.5.13", + "@webassemblyjs/wast-parser": "1.5.13", "long": "^3.2.0" } }, + "@webpack-contrib/schema-utils": { + "version": "1.0.0-beta.0", + "resolved": "https://registry.npmjs.org/@webpack-contrib/schema-utils/-/schema-utils-1.0.0-beta.0.tgz", + "integrity": "sha512-LonryJP+FxQQHsjGBi6W786TQB1Oym+agTpY0c+Kj8alnIw+DLUJb6SI8Y1GHGhLCH1yPRrucjObUmxNICQ1pg==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "chalk": "^2.3.2", + "strip-ansi": "^4.0.0", + "text-table": "^0.2.0", + "webpack-log": "^1.1.2" + }, + "dependencies": { + "ajv": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", + "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.1" + } + }, + "ajv-keywords": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "abab": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", @@ -730,6 +839,32 @@ "normalize-path": "^2.0.0" } }, + "apollo-link": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.2.tgz", + "integrity": "sha512-Uk/BC09dm61DZRDSu52nGq0nFhq7mcBPTjy5EEH1eunJndtCaNXQhQz/BjkI2NdrfGI+B+i5he6YSoRBhYizdw==", + "requires": { + "@types/graphql": "0.12.6", + "apollo-utilities": "^1.0.0", + "zen-observable-ts": "^0.8.9" + } + }, + "apollo-link-ws": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/apollo-link-ws/-/apollo-link-ws-1.0.8.tgz", + "integrity": "sha512-ucuGvr8CBBwCHl/Rbtyuv9Fn0FN5Qoyvy84KHtuMl2Uux2Sq+jt3bUum+pZ+hZntEd9k8M1OjrrXqRJ4PtEpyA==", + "requires": { + "apollo-link": "^1.2.2" + } + }, + "apollo-utilities": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.16.tgz", + "integrity": "sha512-5oKnElKqkV920KRbitiyISLeG63tUGAyNdotg58bQSX9Omr+smoNDTIRMRLbyIdKOYLaw3LpDaRepOPqljj0NQ==", + "requires": { + "fast-json-stable-stringify": "^2.0.0" + } + }, "app-root-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.1.0.tgz", @@ -770,9 +905,9 @@ } }, "aria-query": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-0.7.1.tgz", - "integrity": "sha1-Jsu1r/ZBRLCoJb4YRuCxbPoAsR4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", "dev": true, "requires": { "ast-types-flow": "0.0.7", @@ -924,8 +1059,7 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", - "dev": true + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" }, "asynckit": { "version": "0.4.0", @@ -1024,9 +1158,9 @@ "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" }, "axobject-query": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-0.1.0.tgz", - "integrity": "sha1-YvWdvFnJ+SQnWco0mWDnov48NsA=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.1.tgz", + "integrity": "sha1-Bd+nBa2orZ25k/polvItOVsLCgc=", "dev": true, "requires": { "ast-types-flow": "0.0.7" @@ -1041,6 +1175,14 @@ "chalk": "^1.1.3", "esutils": "^2.0.2", "js-tokens": "^3.0.2" + }, + "dependencies": { + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + } } }, "babel-core": { @@ -1071,16 +1213,16 @@ } }, "babel-eslint": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.5.tgz", - "integrity": "sha512-TcdEGCHHquOPQOlH6Fe6MLwPWWWJLdeKhcGoLfOTShETpoH8XYWhjWJw38KCKaTca7c/EdxLolnbakixKxnXDg==", + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz", + "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==", "dev": true, "requires": { "@babel/code-frame": "7.0.0-beta.44", "@babel/traverse": "7.0.0-beta.44", "@babel/types": "7.0.0-beta.44", "babylon": "7.0.0-beta.44", - "eslint-scope": "~3.7.1", + "eslint-scope": "3.7.1", "eslint-visitor-keys": "^1.0.0" }, "dependencies": { @@ -1290,9 +1432,9 @@ } }, "babel-loader": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.4.tgz", - "integrity": "sha512-/hbyEvPzBJuGpk9o80R0ZyTej6heEOr59GoEUtn8qFKbnx4cJm9FWES6J/iv644sYgrtVw9JJQkjaLW/bqb5gw==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz", + "integrity": "sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==", "dev": true, "requires": { "find-cache-dir": "^1.0.0", @@ -2060,6 +2202,11 @@ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "dev": true }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -2145,9 +2292,9 @@ "dev": true }, "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "optional": true, "requires": { "tweetnacl": "^0.14.3" @@ -2363,14 +2510,15 @@ } }, "browserify-des": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.1.tgz", - "integrity": "sha512-zy0Cobe3hhgpiOM32Tj7KQ3Vl91m0njwsjzZQK1L+JDf11dzP9qIvjreVinsvXrgfjhStXwUWAEpB9D7Gwmayw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", - "inherits": "^2.0.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "browserify-rsa": { @@ -2528,9 +2676,9 @@ } }, "cachedir": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-1.2.0.tgz", - "integrity": "sha512-i3xIKd9U4ov0hWXYo08oJy0YVz0krZ9dbTZQim41xkg0IiScptkAK0UilZ5M1WE3gnWjXAa9+cMtrJ5dM+THbA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-1.3.0.tgz", + "integrity": "sha512-O1ji32oyON9laVPJL1IZ5bmwd2cB46VfpxkDequezH+15FDzzVddEyrGEeX4WusDSqKxdyFdDQDEG1yo1GoWkg==", "dev": true, "requires": { "os-homedir": "^1.0.1" @@ -2600,15 +2748,15 @@ } }, "caniuse-db": { - "version": "1.0.30000859", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000859.tgz", - "integrity": "sha1-boE6F1fxmpPLNnX2tQN6yoC+oGI=", + "version": "1.0.30000869", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000869.tgz", + "integrity": "sha1-w9pZ+o2UVt+Iokuyku3g43mHmMs=", "dev": true }, "caniuse-lite": { - "version": "1.0.30000859", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000859.tgz", - "integrity": "sha512-BucSdVZocKyKAdThos0fx7Ds941M1jddFazv7U3stFqxyWOc2JrxVn87Qo02DzP9Txb4lw9jIQddh9IT4WA3dQ==", + "version": "1.0.30000865", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz", + "integrity": "sha512-vs79o1mOSKRGv/1pSkp4EXgl4ZviWeYReXw60XfacPU64uQWZwJT6vZNmxRF9O+6zu71sJwMxLK5JXxbzuVrLw==", "dev": true }, "capture-exit": { @@ -2960,9 +3108,9 @@ } }, "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz", + "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==", "dev": true }, "common-tags": { @@ -3321,12 +3469,14 @@ } }, "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "lru-cache": "^4.0.1", + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" } @@ -3512,9 +3662,9 @@ } }, "cssom": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", - "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz", + "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==", "dev": true }, "cssstyle": { @@ -3542,9 +3692,9 @@ "dev": true }, "cypress": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-3.0.1.tgz", - "integrity": "sha512-701AeHFyWe3/LwTMQJfBF+hMoyDBMd/kNTVlLfQIo0ve0lIQt7aOZDabgp95sL9+j0RLQMkcl3xkhH3yQ2blNA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-3.0.2.tgz", + "integrity": "sha512-HoP5FWj2fqtMndKC0Qnc7Xy0v55dx/PQ5uLaKIL9h505H45uFMsc+HR5Qxw24rXaUKaS3oVY5UJaVw9YA2EtLw==", "dev": true, "requires": { "@cypress/listr-verbose-renderer": "0.4.1", @@ -3555,17 +3705,18 @@ "@types/chai-jquery": "1.1.35", "@types/jquery": "3.2.16", "@types/lodash": "4.14.87", - "@types/minimatch": "3.0.1", + "@types/minimatch": "3.0.3", "@types/mocha": "2.2.44", "@types/sinon": "4.0.0", "@types/sinon-chai": "2.7.29", "bluebird": "3.5.0", - "cachedir": "1.2.0", + "cachedir": "1.3.0", "chalk": "2.4.1", "check-more-types": "2.24.0", "commander": "2.11.0", "common-tags": "1.4.0", "debug": "3.1.0", + "execa": "0.10.0", "executable": "4.1.1", "extract-zip": "1.6.6", "fs-extra": "4.0.1", @@ -3580,7 +3731,7 @@ "minimist": "1.2.0", "progress": "1.1.8", "ramda": "0.24.1", - "request": "2.81.0", + "request": "2.87.0", "request-progress": "0.3.1", "supports-color": "5.1.0", "tmp": "0.0.31", @@ -3588,6 +3739,18 @@ "yauzl": "2.8.0" }, "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -3597,6 +3760,18 @@ "color-convert": "^1.9.0" } }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", @@ -3634,6 +3809,44 @@ "ms": "2.0.0" } }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "^5.1.0", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, "lodash": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", @@ -3646,6 +3859,46 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "request": { + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" + } + }, "supports-color": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", @@ -4045,9 +4298,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.50", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.50.tgz", - "integrity": "sha1-dDi3b5K0G5GfP73TUPvQdX2s3fc=", + "version": "1.3.52", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz", + "integrity": "sha1-0tnxJwuko7lnuDHEDvcftNmrXOA=", "dev": true }, "elegant-spinner": { @@ -4107,9 +4360,9 @@ } }, "enhanced-resolve": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz", - "integrity": "sha512-jox/62b2GofV1qTUQTMPEJSDIGycS43evqYzD/KVtEb9OCoki9cnacUPxCrZa7JfPzZSYOCZhu9O9luaMxAX8g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -4220,9 +4473,9 @@ "dev": true }, "escodegen": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.10.0.tgz", - "integrity": "sha512-fjUOf8johsv23WuIKdNQU4P9t9jhQ4Qzx6pC2uW890OloK3Zs1ZAoCNpg/2larNF501jLl3UNy0kIRcF6VI22g==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", + "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", "dev": true, "requires": { "esprima": "^3.1.3", @@ -4331,6 +4584,17 @@ "supports-color": "^5.3.0" } }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -4561,18 +4825,19 @@ } }, "eslint-plugin-jsx-a11y": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.3.tgz", - "integrity": "sha1-VFg9GuRCSDFi4EDhPMMYZUZRAOU=", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.1.tgz", + "integrity": "sha512-JsxNKqa3TwmPypeXNnI75FntkUktGzI1wSa1LgNZdSOMI+B4sxnr1lSF8m8lPiz4mKiC+14ysZQM4scewUrP7A==", "dev": true, "requires": { - "aria-query": "^0.7.0", + "aria-query": "^3.0.0", "array-includes": "^3.0.3", - "ast-types-flow": "0.0.7", - "axobject-query": "^0.1.0", - "damerau-levenshtein": "^1.0.0", - "emoji-regex": "^6.1.0", - "jsx-ast-utils": "^2.0.0" + "ast-types-flow": "^0.0.7", + "axobject-query": "^2.0.1", + "damerau-levenshtein": "^1.0.4", + "emoji-regex": "^6.5.1", + "has": "^1.0.3", + "jsx-ast-utils": "^2.0.1" } }, "eslint-plugin-react": { @@ -4620,9 +4885,9 @@ } }, "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { "version": "1.0.1", @@ -4660,6 +4925,11 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", @@ -4686,12 +4956,12 @@ } }, "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", + "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", "dev": true, "requires": { - "cross-spawn": "^5.0.1", + "cross-spawn": "^6.0.0", "get-stream": "^3.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", @@ -4849,9 +5119,9 @@ } }, "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -4973,8 +5243,7 @@ "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "fast-levenshtein": { "version": "2.0.6", @@ -5057,9 +5326,9 @@ }, "dependencies": { "ajv": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.1.tgz", - "integrity": "sha512-pgZos1vgOHDiC7gKNbZW8eKvCnNXARv2oqrGQT7Hzbq5Azp7aZG6DJzADnkuSq7RH6qkXp4J/m68yPX/2uBHyQ==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", + "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -5653,9 +5922,9 @@ } }, "formidable": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.17.tgz", - "integrity": "sha1-71SRSQ+UM7cF+qdyScmQKa40hVk=" + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.16.tgz", + "integrity": "sha1-SRbP38TL7QILJXpqlQWpqzjCzQ4=" }, "forwarded": { "version": "0.1.2", @@ -5729,82 +5998,64 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "bundled": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "bundled": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "bundled": true, "optional": true, "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.6" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, + "bundled": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "chownr": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", + "bundled": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "bundled": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "bundled": true, "optional": true, "requires": { "ms": "2.0.0" @@ -5812,455 +6063,388 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", - "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", + "bundled": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "bundled": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "bundled": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "bundled": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "bundled": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "bundled": true, "optional": true, "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, "glob": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "bundled": true, "optional": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "bundled": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.21.tgz", - "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", + "bundled": true, "optional": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "^2.1.0" } }, "ignore-walk": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "bundled": true, "optional": true, "requires": { - "minimatch": "3.0.4" + "minimatch": "^3.0.4" } }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "bundled": true, "optional": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "bundled": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "optional": true, + "bundled": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "bundled": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "optional": true, + "bundled": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "optional": true + "bundled": true }, "minipass": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz", - "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", - "optional": true, + "bundled": true, "requires": { - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" } }, "minizlib": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz", - "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", + "bundled": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "optional": true, + "bundled": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "bundled": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.0.tgz", - "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", + "bundled": true, "optional": true, "requires": { - "debug": "2.6.9", - "iconv-lite": "0.4.21", - "sax": "1.2.4" + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" } }, "node-pre-gyp": { "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.0.tgz", - "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", + "bundled": true, "optional": true, "requires": { - "detect-libc": "1.0.3", - "mkdirp": "0.5.1", - "needle": "2.2.0", - "nopt": "4.0.1", - "npm-packlist": "1.1.10", - "npmlog": "4.1.2", - "rc": "1.2.7", - "rimraf": "2.6.2", - "semver": "5.5.0", - "tar": "4.4.1" + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.1.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" } }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "bundled": true, "optional": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "npm-bundled": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz", - "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", + "bundled": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.10.tgz", - "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", + "bundled": true, "optional": true, "requires": { - "ignore-walk": "3.0.1", - "npm-bundled": "1.0.3" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" } }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "bundled": true, "optional": true, "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "bundled": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "optional": true, + "bundled": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "bundled": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "bundled": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "bundled": true, "optional": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "bundled": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "bundled": true, "optional": true }, "rc": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz", - "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", + "bundled": true, "optional": true, "requires": { - "deep-extend": "0.5.1", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "bundled": true, "optional": true } } }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "rimraf": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "bundled": true, "optional": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "safe-buffer": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "bundled": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "bundled": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "bundled": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "bundled": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "bundled": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "optional": true, + "bundled": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "optional": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "optional": true, + "bundled": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "bundled": true, "optional": true }, "tar": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.1.tgz", - "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", + "bundled": true, "optional": true, "requires": { - "chownr": "1.0.1", - "fs-minipass": "1.2.5", - "minipass": "2.2.4", - "minizlib": "1.1.0", - "mkdirp": "0.5.1", - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.1", + "yallist": "^3.0.2" } }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "bundled": true, "optional": true }, "wide-align": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "bundled": true, "optional": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2" } }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "optional": true + "bundled": true }, "yallist": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "optional": true + "bundled": true } } }, @@ -6319,25 +6503,10 @@ "globule": "^1.0.0" } }, - "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true - }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "requires": { - "is-property": "^1.0.0" - } - }, "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, "get-own-enumerable-property-symbols": { @@ -6476,9 +6645,9 @@ } }, "global-modules-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/global-modules-path/-/global-modules-path-2.1.0.tgz", - "integrity": "sha512-3DrmGj2TP+96cABk9TfMp6f3knH/Y46dqvWznTU3Tf6/bDGLDAn15tFluQ7BcloykOcdY16U0WGq0BQblYOxJQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/global-modules-path/-/global-modules-path-2.2.0.tgz", + "integrity": "sha512-IGGoWyy46gnsPYwGeTh53oTfHedfOh9IUI3adk9tCIcli6AG55TugvhIUh99MxMWKSF09tWS40Un9Mt5HYaEOA==", "dev": true }, "globals": { @@ -6785,13 +6954,23 @@ } }, "hash.js": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.4.tgz", - "integrity": "sha512-A6RlQvvZEtFS5fLU43IDu0QUmBy+fDO9VMdTXvufKwIkt/rFfvICAViCax5fbDO4zdNzaC3/27ZhKUok5bAJyw==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", + "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", "dev": true, "requires": { "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "^1.0.1" + } + }, + "hasura-console-graphiql": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/hasura-console-graphiql/-/hasura-console-graphiql-0.0.1.tgz", + "integrity": "sha512-p5y69dbsfj/uU0nDj375GTrBzM53jXuQLqUp2UiL3FNnAcQzujOlGCzuQ04xY/A32PRd5nUg6AULeQ8yUcP6KA==", + "requires": { + "codemirror": "^5.26.0", + "codemirror-graphql": "^0.6.11", + "markdown-it": "^8.4.0" } }, "hawk": { @@ -6806,13 +6985,14 @@ } }, "history": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/history/-/history-3.0.0.tgz", - "integrity": "sha1-As/05vadxi3YEWEQSmP1uF6tDIU=", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-3.3.0.tgz", + "integrity": "sha1-/O3M6PEpdTcVRdc1RhAzV5ptrpw=", "requires": { - "invariant": "^2.0.0", - "query-string": "^4.1.0", - "warning": "^2.0.0" + "invariant": "^2.2.1", + "loose-envify": "^1.2.0", + "query-string": "^4.2.2", + "warning": "^3.0.0" }, "dependencies": { "query-string": { @@ -6823,19 +7003,6 @@ "object-assign": "^4.1.0", "strict-uri-encode": "^1.0.0" } - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" - }, - "warning": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-2.1.0.tgz", - "integrity": "sha1-ISINnGOvx3qMkhEeARr3Bc4MaQE=", - "requires": { - "loose-envify": "^1.0.0" - } } } }, @@ -6871,9 +7038,9 @@ } }, "hosted-git-info": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", - "integrity": "sha512-Ba4+0M4YvIDUUsprMjhVTU1yN9F2/LJSAl69ZpzaLT4l4j5mwTS6jqqW9Ojvj6lKz/veqPzpJBqGbXspOb533A==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, "html-comment-regex": { @@ -7373,9 +7540,9 @@ } }, "is-callable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", - "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", "dev": true }, "is-ci": { @@ -7486,25 +7653,6 @@ "is-path-inside": "^1.0.0" } }, - "is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true - }, - "is-my-json-valid": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", - "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", - "dev": true, - "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" - } - }, "is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", @@ -7599,12 +7747,6 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true - }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", @@ -8531,15 +8673,15 @@ "dev": true }, "js-base64": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.5.tgz", - "integrity": "sha512-aUnNwqMOXw3yvErjMPSQu6qIIzUmT1e5KcU1OZxRDU1g/am6mzBvcrmLAYwzmB59BHPrh5/tKaiF4OPhqRWESQ==", + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.8.tgz", + "integrity": "sha512-hm2nYpDrwoO/OzBhdcqs/XGT6XjSuSSCVEpia+Kl2J6x4CYt5hISlVL/AYU1khoDXv0AQVgxtdJySb9gjAn56Q==", "dev": true }, "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.12.0", @@ -8659,12 +8801,6 @@ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -8745,12 +8881,6 @@ "invert-kv": "^1.0.0" } }, - "leb": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/leb/-/leb-0.3.0.tgz", - "integrity": "sha1-Mr7p+tFoMo1q6oUi2DP0GA7tHaM=", - "dev": true - }, "less": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", @@ -8857,6 +8987,17 @@ "supports-color": "^5.3.0" } }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -9468,11 +9609,11 @@ "dev": true }, "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "requires": { - "js-tokens": "^3.0.0" + "js-tokens": "^3.0.0 || ^4.0.0" } }, "loud-rejection": { @@ -9551,9 +9692,9 @@ } }, "markdown-it": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.1.tgz", - "integrity": "sha512-CzzqSSNkFRUf9vlWvhK1awpJreMRqdCrBvZ8DIoDWTOkESMIF741UPAhuAmbyWmdiFPA6WARNhnu2M6Nrhwa+A==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", "requires": { "argparse": "^1.0.7", "entities": "~1.1.1", @@ -9693,16 +9834,16 @@ "optional": true }, "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" }, "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", "requires": { - "mime-db": "~1.33.0" + "mime-db": "~1.35.0" } }, "mimic-fn": { @@ -9720,11 +9861,12 @@ } }, "mini-css-extract-plugin": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.0.tgz", - "integrity": "sha512-2Zik6PhUZ/MbiboG6SDS9UTPL4XXy4qnyGjSdCIWRrr8xb6PwLtHE+AYOjkXJWdF0OG8vo/yrJ8CgS5WbMpzIg==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.1.tgz", + "integrity": "sha512-XWuB3G61Rtasq/gLe7cp5cuozehE6hN+E4sxCamRR/WDiHTg+f7ZIAS024r8UJQffY+e2gGELXQZgQoFDfNDCg==", "dev": true, "requires": { + "@webpack-contrib/schema-utils": "^1.0.0-beta.0", "loader-utils": "^1.1.0", "webpack-sources": "^1.1.0" } @@ -10026,9 +10168,9 @@ } }, "node-sass": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.0.tgz", - "integrity": "sha512-QFHfrZl6lqRU3csypwviz2XLgGNOoWQbo2GOvtsfQqOfL4cy1BtWnhx/XUeAO9LT3ahBzSRXcEO6DdvAH9DzSg==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.2.tgz", + "integrity": "sha512-LdxoJLZutx0aQXHtWIYwJKMj+9pTjneTcLWJgzf2XbGu0q5pRNqW5QvFCEdm3mc5rJOdru/mzln5d0EZLacf6g==", "dev": true, "requires": { "async-foreach": "^0.1.3", @@ -10046,16 +10188,34 @@ "nan": "^2.10.0", "node-gyp": "^3.3.1", "npmlog": "^4.0.0", - "request": "~2.79.0", + "request": "2.87.0", "sass-graph": "^2.2.4", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" }, "dependencies": { - "caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", "dev": true }, "cross-spawn": { @@ -10068,57 +10228,83 @@ "which": "^1.2.9" } }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "dev": true, "requires": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" + "ajv": "^5.1.0", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, "qs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", - "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, "request": { - "version": "2.79.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", - "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", "dev": true, "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.11.0", + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", "combined-stream": "~1.0.5", - "extend": "~3.0.0", + "extend": "~3.0.1", "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~2.0.6", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "qs": "~6.3.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "~0.4.1", - "uuid": "^3.0.0" + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" } - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true } } }, @@ -10184,12 +10370,6 @@ "object-assign": "^4.1.0", "strict-uri-encode": "^1.0.0" } - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true } } }, @@ -10400,8 +10580,7 @@ }, "align-text": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "bundled": true, "dev": true, "requires": { "kind-of": "^3.0.2", @@ -10411,14 +10590,12 @@ }, "amdefine": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "bundled": true, "dev": true }, "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "bundled": true, "dev": true }, "ansi-styles": { @@ -10432,8 +10609,7 @@ }, "append-transform": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", - "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "bundled": true, "dev": true, "requires": { "default-require-extensions": "^1.0.0" @@ -10441,68 +10617,57 @@ }, "archy": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "bundled": true, "dev": true }, "arr-diff": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "bundled": true, "dev": true }, "arr-flatten": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "bundled": true, "dev": true }, "arr-union": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "bundled": true, "dev": true }, "array-unique": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "bundled": true, "dev": true }, "arrify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "bundled": true, "dev": true }, "assign-symbols": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "bundled": true, "dev": true }, "async": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "bundled": true, "dev": true }, "atob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "bundled": true, "dev": true }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "bundled": true, "dev": true }, "base": { "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", + "bundled": true, "dev": true, "requires": { "cache-base": "^1.0.1", @@ -10516,8 +10681,7 @@ "dependencies": { "define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "bundled": true, "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -10525,8 +10689,7 @@ }, "is-accessor-descriptor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "bundled": true, "dev": true, "requires": { "kind-of": "^6.0.0" @@ -10534,8 +10697,7 @@ }, "is-data-descriptor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "bundled": true, "dev": true, "requires": { "kind-of": "^6.0.0" @@ -10543,8 +10705,7 @@ }, "is-descriptor": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "bundled": true, "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -10554,16 +10715,14 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", + "bundled": true, "dev": true } } }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "bundled": true, "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -10572,8 +10731,7 @@ }, "braces": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", + "bundled": true, "dev": true, "requires": { "arr-flatten": "^1.1.0", @@ -10590,8 +10748,7 @@ "dependencies": { "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "bundled": true, "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -10601,14 +10758,12 @@ }, "builtin-modules": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "bundled": true, "dev": true }, "cache-base": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", + "bundled": true, "dev": true, "requires": { "collection-visit": "^1.0.0", @@ -10624,8 +10779,7 @@ }, "caching-transform": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz", - "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", + "bundled": true, "dev": true, "requires": { "md5-hex": "^1.2.0", @@ -10635,15 +10789,13 @@ }, "camelcase": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "bundled": true, "dev": true, "optional": true }, "center-align": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -10664,8 +10816,7 @@ }, "class-utils": { "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", + "bundled": true, "dev": true, "requires": { "arr-union": "^3.1.0", @@ -10676,8 +10827,7 @@ "dependencies": { "define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "bundled": true, "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -10687,8 +10837,7 @@ }, "cliui": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -10699,8 +10848,7 @@ "dependencies": { "wordwrap": { "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "bundled": true, "dev": true, "optional": true } @@ -10708,14 +10856,12 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "bundled": true, "dev": true }, "collection-visit": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "bundled": true, "dev": true, "requires": { "map-visit": "^1.0.0", @@ -10724,38 +10870,32 @@ }, "commondir": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "bundled": true, "dev": true }, "component-emitter": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "bundled": true, "dev": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "bundled": true, "dev": true }, "convert-source-map": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", + "bundled": true, "dev": true }, "copy-descriptor": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "bundled": true, "dev": true }, "cross-spawn": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "bundled": true, "dev": true, "requires": { "lru-cache": "^4.0.1", @@ -10764,8 +10904,7 @@ }, "debug": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "bundled": true, "dev": true, "requires": { "ms": "2.0.0" @@ -10773,26 +10912,22 @@ }, "debug-log": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", - "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", + "bundled": true, "dev": true }, "decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "bundled": true, "dev": true }, "decode-uri-component": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "bundled": true, "dev": true }, "default-require-extensions": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", - "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "bundled": true, "dev": true, "requires": { "strip-bom": "^2.0.0" @@ -10800,8 +10935,7 @@ }, "define-property": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", + "bundled": true, "dev": true, "requires": { "is-descriptor": "^1.0.2", @@ -10810,8 +10944,7 @@ "dependencies": { "is-accessor-descriptor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "bundled": true, "dev": true, "requires": { "kind-of": "^6.0.0" @@ -10819,8 +10952,7 @@ }, "is-data-descriptor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "bundled": true, "dev": true, "requires": { "kind-of": "^6.0.0" @@ -10828,8 +10960,7 @@ }, "is-descriptor": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "bundled": true, "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -10839,16 +10970,14 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", + "bundled": true, "dev": true } } }, "error-ex": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "bundled": true, "dev": true, "requires": { "is-arrayish": "^0.2.1" @@ -10856,8 +10985,7 @@ }, "execa": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "bundled": true, "dev": true, "requires": { "cross-spawn": "^5.0.1", @@ -10871,8 +10999,7 @@ "dependencies": { "cross-spawn": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "bundled": true, "dev": true, "requires": { "lru-cache": "^4.0.1", @@ -10884,8 +11011,7 @@ }, "expand-brackets": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "bundled": true, "dev": true, "requires": { "debug": "^2.3.3", @@ -10899,8 +11025,7 @@ "dependencies": { "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "bundled": true, "dev": true, "requires": { "ms": "2.0.0" @@ -10908,8 +11033,7 @@ }, "define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "bundled": true, "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -10917,8 +11041,7 @@ }, "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "bundled": true, "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -10928,8 +11051,7 @@ }, "extend-shallow": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "bundled": true, "dev": true, "requires": { "assign-symbols": "^1.0.0", @@ -10938,8 +11060,7 @@ "dependencies": { "is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "bundled": true, "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -10949,8 +11070,7 @@ }, "extglob": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", + "bundled": true, "dev": true, "requires": { "array-unique": "^0.3.2", @@ -10965,8 +11085,7 @@ "dependencies": { "define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "bundled": true, "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -10974,8 +11093,7 @@ }, "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "bundled": true, "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -10983,8 +11101,7 @@ }, "is-accessor-descriptor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "bundled": true, "dev": true, "requires": { "kind-of": "^6.0.0" @@ -10992,8 +11109,7 @@ }, "is-data-descriptor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "bundled": true, "dev": true, "requires": { "kind-of": "^6.0.0" @@ -11001,8 +11117,7 @@ }, "is-descriptor": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "bundled": true, "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -11012,16 +11127,14 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", + "bundled": true, "dev": true } } }, "fill-range": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "bundled": true, "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -11032,8 +11145,7 @@ "dependencies": { "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "bundled": true, "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -11043,8 +11155,7 @@ }, "find-cache-dir": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", - "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "bundled": true, "dev": true, "requires": { "commondir": "^1.0.1", @@ -11054,8 +11165,7 @@ }, "find-up": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "bundled": true, "dev": true, "requires": { "locate-path": "^2.0.0" @@ -11063,14 +11173,12 @@ }, "for-in": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "bundled": true, "dev": true }, "foreground-child": { "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "bundled": true, "dev": true, "requires": { "cross-spawn": "^4", @@ -11079,8 +11187,7 @@ }, "fragment-cache": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "bundled": true, "dev": true, "requires": { "map-cache": "^0.2.2" @@ -11088,32 +11195,27 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "bundled": true, "dev": true }, "get-caller-file": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "bundled": true, "dev": true }, "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "bundled": true, "dev": true }, "get-value": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "bundled": true, "dev": true }, "glob": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "bundled": true, "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -11132,14 +11234,12 @@ }, "graceful-fs": { "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "bundled": true, "dev": true }, "handlebars": { "version": "4.0.11", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", - "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "bundled": true, "dev": true, "requires": { "async": "^1.4.0", @@ -11150,8 +11250,7 @@ "dependencies": { "source-map": { "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "bundled": true, "dev": true, "requires": { "amdefine": ">=0.0.4" @@ -11161,8 +11260,7 @@ }, "has-value": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "bundled": true, "dev": true, "requires": { "get-value": "^2.0.6", @@ -11172,8 +11270,7 @@ }, "has-values": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "bundled": true, "dev": true, "requires": { "is-number": "^3.0.0", @@ -11182,8 +11279,7 @@ "dependencies": { "kind-of": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "bundled": true, "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -11193,20 +11289,17 @@ }, "hosted-git-info": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha1-IyNbKasjDFdqqw1PE/wEawsDgiI=", + "bundled": true, "dev": true }, "imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "bundled": true, "dev": true }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "bundled": true, "dev": true, "requires": { "once": "^1.3.0", @@ -11215,20 +11308,17 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "bundled": true, "dev": true }, "invert-kv": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "bundled": true, "dev": true }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "bundled": true, "dev": true, "requires": { "kind-of": "^3.0.2" @@ -11236,20 +11326,17 @@ }, "is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "bundled": true, "dev": true }, "is-buffer": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", + "bundled": true, "dev": true }, "is-builtin-module": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "bundled": true, "dev": true, "requires": { "builtin-modules": "^1.0.0" @@ -11257,8 +11344,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "bundled": true, "dev": true, "requires": { "kind-of": "^3.0.2" @@ -11266,8 +11352,7 @@ }, "is-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "bundled": true, "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", @@ -11277,28 +11362,24 @@ "dependencies": { "kind-of": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "bundled": true, "dev": true } } }, "is-extendable": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "bundled": true, "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "bundled": true, "dev": true }, "is-number": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "bundled": true, "dev": true, "requires": { "kind-of": "^3.0.2" @@ -11306,8 +11387,7 @@ }, "is-odd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", - "integrity": "sha1-dkZiRnH9fqVYzNmieVGC8pWPGyQ=", + "bundled": true, "dev": true, "requires": { "is-number": "^4.0.0" @@ -11315,16 +11395,14 @@ "dependencies": { "is-number": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", + "bundled": true, "dev": true } } }, "is-plain-object": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "bundled": true, "dev": true, "requires": { "isobject": "^3.0.1" @@ -11332,59 +11410,51 @@ }, "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "bundled": true, "dev": true }, "is-utf8": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "bundled": true, "dev": true }, "is-windows": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", + "bundled": true, "dev": true }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "bundled": true, "dev": true }, "isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "bundled": true, "dev": true }, "isobject": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "bundled": true, "dev": true }, "istanbul-lib-coverage": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", - "integrity": "sha1-99jy5CuX43/nlhFMsPnWi146Q0E=", + "bundled": true, "dev": true }, "istanbul-lib-hook": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz", - "integrity": "sha1-hTjZcDcss3FtU+VVI91UtVeo2Js=", + "bundled": true, "dev": true, "requires": { "append-transform": "^0.4.0" } }, "istanbul-lib-instrument": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-2.3.0.tgz", - "integrity": "sha512-Ie1LGWJVCFDDJKKH4g1ffpFcZTEXEd6ay5l9fE8539y4qPErJnzo4psnGzDH92tcKvdUDdbxrKySYIbt6zB9hw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-2.3.1.tgz", + "integrity": "sha512-h9Vg3nfbxrF0PK0kZiNiMAyL8zXaLiBP/BXniaKSwVvAi1TaumYV2b0wPdmy1CRX3irYbYD1p4Wjbv4uyECiiQ==", "dev": true, "requires": { "@babel/generator": "7.0.0-beta.51", @@ -11392,22 +11462,21 @@ "@babel/template": "7.0.0-beta.51", "@babel/traverse": "7.0.0-beta.51", "@babel/types": "7.0.0-beta.51", - "istanbul-lib-coverage": "^2.0.0", + "istanbul-lib-coverage": "^2.0.1", "semver": "^5.5.0" }, "dependencies": { "istanbul-lib-coverage": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz", - "integrity": "sha512-yMSw5xLIbdaxiVXHk3amfNM2WeBxLrwH/BCyZ9HvA/fylwziAIJOG2rKqWyLqEJqwKT725vxxqidv+SyynnGAA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-nPvSZsVlbG9aLhZYaC3Oi1gT/tpyo3Yt5fNyf6NmcKIayz4VV/txxJFFKAK/gU4dcNn8ehsanBbVHVl0+amOLA==", "dev": true } } }, "istanbul-lib-report": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.3.tgz", - "integrity": "sha1-LfEhiMD6d5kMDSF20tC6M5QYglk=", + "bundled": true, "dev": true, "requires": { "istanbul-lib-coverage": "^1.1.2", @@ -11418,14 +11487,12 @@ "dependencies": { "has-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "bundled": true, "dev": true }, "supports-color": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "bundled": true, "dev": true, "requires": { "has-flag": "^1.0.0" @@ -11435,8 +11502,7 @@ }, "istanbul-lib-source-maps": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.5.tgz", - "integrity": "sha1-/+a+Tnq4bTYD5CkNVJkLFFBvybE=", + "bundled": true, "dev": true, "requires": { "debug": "^3.1.0", @@ -11448,13 +11514,18 @@ }, "istanbul-reports": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.4.1.tgz", - "integrity": "sha1-Ty6OkoqnoF0dpsQn1AmLJlXsczQ=", + "bundled": true, "dev": true, "requires": { "handlebars": "^4.0.3" } }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, "jsesc": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", @@ -11463,8 +11534,7 @@ }, "kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "bundled": true, "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -11472,15 +11542,13 @@ }, "lazy-cache": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "bundled": true, "dev": true, "optional": true }, "lcid": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "bundled": true, "dev": true, "requires": { "invert-kv": "^1.0.0" @@ -11488,8 +11556,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -11501,8 +11568,7 @@ }, "locate-path": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "bundled": true, "dev": true, "requires": { "p-locate": "^2.0.0", @@ -11511,22 +11577,19 @@ "dependencies": { "path-exists": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "bundled": true, "dev": true } } }, "longest": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "bundled": true, "dev": true }, "lru-cache": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha1-oRdc80lt/IQ2wVbDNLSVWZK85pw=", + "bundled": true, "dev": true, "requires": { "pseudomap": "^1.0.2", @@ -11535,14 +11598,12 @@ }, "map-cache": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "bundled": true, "dev": true }, "map-visit": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "bundled": true, "dev": true, "requires": { "object-visit": "^1.0.0" @@ -11550,8 +11611,7 @@ }, "md5-hex": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", - "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", + "bundled": true, "dev": true, "requires": { "md5-o-matic": "^0.1.1" @@ -11559,14 +11619,12 @@ }, "md5-o-matic": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", - "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", + "bundled": true, "dev": true }, "mem": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "bundled": true, "dev": true, "requires": { "mimic-fn": "^1.0.0" @@ -11574,8 +11632,7 @@ }, "merge-source-map": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha1-L93n5gIJOfcJBqaPLXrmheTIxkY=", + "bundled": true, "dev": true, "requires": { "source-map": "^0.6.1" @@ -11583,16 +11640,14 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "bundled": true, "dev": true } } }, "micromatch": { "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "bundled": true, "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -11612,22 +11667,19 @@ "dependencies": { "kind-of": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", + "bundled": true, "dev": true } } }, "mimic-fn": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", + "bundled": true, "dev": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "bundled": true, "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -11635,14 +11687,12 @@ }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "bundled": true, "dev": true }, "mixin-deep": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", + "bundled": true, "dev": true, "requires": { "for-in": "^1.0.2", @@ -11651,8 +11701,7 @@ "dependencies": { "is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "bundled": true, "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -11662,8 +11711,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "bundled": true, "dev": true, "requires": { "minimist": "0.0.8" @@ -11671,14 +11719,12 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "bundled": true, "dev": true }, "nanomatch": { "version": "1.2.9", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", - "integrity": "sha1-h59xUMstq3pHElkGbBBO7m4Pp8I=", + "bundled": true, "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -11697,16 +11743,14 @@ "dependencies": { "kind-of": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", + "bundled": true, "dev": true } } }, "normalize-package-data": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", + "bundled": true, "dev": true, "requires": { "hosted-git-info": "^2.1.4", @@ -11717,8 +11761,7 @@ }, "npm-run-path": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "bundled": true, "dev": true, "requires": { "path-key": "^2.0.0" @@ -11726,20 +11769,17 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "bundled": true, "dev": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "bundled": true, "dev": true }, "object-copy": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "bundled": true, "dev": true, "requires": { "copy-descriptor": "^0.1.0", @@ -11749,8 +11789,7 @@ "dependencies": { "define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "bundled": true, "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -11760,8 +11799,7 @@ }, "object-visit": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "bundled": true, "dev": true, "requires": { "isobject": "^3.0.0" @@ -11769,8 +11807,7 @@ }, "object.pick": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "bundled": true, "dev": true, "requires": { "isobject": "^3.0.1" @@ -11778,8 +11815,7 @@ }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "bundled": true, "dev": true, "requires": { "wrappy": "1" @@ -11787,8 +11823,7 @@ }, "optimist": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "bundled": true, "dev": true, "requires": { "minimist": "~0.0.1", @@ -11797,14 +11832,12 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "bundled": true, "dev": true }, "os-locale": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha1-QrwpAKa1uL0XN2yOiCtlr8zyS/I=", + "bundled": true, "dev": true, "requires": { "execa": "^0.7.0", @@ -11814,14 +11847,12 @@ }, "p-finally": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "bundled": true, "dev": true }, "p-limit": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha1-DpK2vty1nwIsE9DxlJ3ILRWQnxw=", + "bundled": true, "dev": true, "requires": { "p-try": "^1.0.0" @@ -11829,8 +11860,7 @@ }, "p-locate": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "bundled": true, "dev": true, "requires": { "p-limit": "^1.1.0" @@ -11838,14 +11868,12 @@ }, "p-try": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "bundled": true, "dev": true }, "parse-json": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "bundled": true, "dev": true, "requires": { "error-ex": "^1.2.0" @@ -11853,14 +11881,12 @@ }, "pascalcase": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "bundled": true, "dev": true }, "path-exists": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "bundled": true, "dev": true, "requires": { "pinkie-promise": "^2.0.0" @@ -11868,26 +11894,22 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "bundled": true, "dev": true }, "path-key": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "bundled": true, "dev": true }, "path-parse": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "bundled": true, "dev": true }, "path-type": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -11897,20 +11919,17 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "bundled": true, "dev": true }, "pinkie": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "bundled": true, "dev": true }, "pinkie-promise": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "bundled": true, "dev": true, "requires": { "pinkie": "^2.0.0" @@ -11918,8 +11937,7 @@ }, "pkg-dir": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "bundled": true, "dev": true, "requires": { "find-up": "^1.0.0" @@ -11927,8 +11945,7 @@ "dependencies": { "find-up": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "bundled": true, "dev": true, "requires": { "path-exists": "^2.0.0", @@ -11939,20 +11956,17 @@ }, "posix-character-classes": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "bundled": true, "dev": true }, "pseudomap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "bundled": true, "dev": true }, "read-pkg": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "bundled": true, "dev": true, "requires": { "load-json-file": "^1.0.0", @@ -11962,8 +11976,7 @@ }, "read-pkg-up": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "bundled": true, "dev": true, "requires": { "find-up": "^1.0.0", @@ -11972,8 +11985,7 @@ "dependencies": { "find-up": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "bundled": true, "dev": true, "requires": { "path-exists": "^2.0.0", @@ -11984,8 +11996,7 @@ }, "regex-not": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", + "bundled": true, "dev": true, "requires": { "extend-shallow": "^3.0.2", @@ -11994,50 +12005,42 @@ }, "repeat-element": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "bundled": true, "dev": true }, "repeat-string": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "bundled": true, "dev": true }, "require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "bundled": true, "dev": true }, "require-main-filename": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "bundled": true, "dev": true }, "resolve-from": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "bundled": true, "dev": true }, "resolve-url": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "bundled": true, "dev": true }, "ret": { "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", + "bundled": true, "dev": true }, "right-align": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -12046,8 +12049,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", + "bundled": true, "dev": true, "requires": { "glob": "^7.0.5" @@ -12055,8 +12057,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "bundled": true, "dev": true, "requires": { "ret": "~0.1.10" @@ -12064,20 +12065,17 @@ }, "semver": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=", + "bundled": true, "dev": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "bundled": true, "dev": true }, "set-value": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", + "bundled": true, "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -12088,8 +12086,7 @@ "dependencies": { "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "bundled": true, "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -12099,8 +12096,7 @@ }, "shebang-command": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "bundled": true, "dev": true, "requires": { "shebang-regex": "^1.0.0" @@ -12108,26 +12104,22 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "bundled": true, "dev": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "bundled": true, "dev": true }, "slide": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "bundled": true, "dev": true }, "snapdragon": { "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", + "bundled": true, "dev": true, "requires": { "base": "^0.11.1", @@ -12142,8 +12134,7 @@ "dependencies": { "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "bundled": true, "dev": true, "requires": { "ms": "2.0.0" @@ -12151,8 +12142,7 @@ }, "define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "bundled": true, "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -12160,8 +12150,7 @@ }, "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "bundled": true, "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -12171,8 +12160,7 @@ }, "snapdragon-node": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", + "bundled": true, "dev": true, "requires": { "define-property": "^1.0.0", @@ -12182,8 +12170,7 @@ "dependencies": { "define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "bundled": true, "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -12191,8 +12178,7 @@ }, "is-accessor-descriptor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "bundled": true, "dev": true, "requires": { "kind-of": "^6.0.0" @@ -12200,8 +12186,7 @@ }, "is-data-descriptor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "bundled": true, "dev": true, "requires": { "kind-of": "^6.0.0" @@ -12209,8 +12194,7 @@ }, "is-descriptor": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "bundled": true, "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -12220,16 +12204,14 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", + "bundled": true, "dev": true } } }, "snapdragon-util": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", + "bundled": true, "dev": true, "requires": { "kind-of": "^3.2.0" @@ -12237,14 +12219,12 @@ }, "source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "bundled": true, "dev": true }, "source-map-resolve": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha1-cuLMNAlVQ+Q7LGKyxMENSpBU8lk=", + "bundled": true, "dev": true, "requires": { "atob": "^2.1.1", @@ -12256,14 +12236,12 @@ }, "source-map-url": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "bundled": true, "dev": true }, "spawn-wrap": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", - "integrity": "sha1-z/WOc6giRhe2Vhq9wyWG6gyCJIw=", + "bundled": true, "dev": true, "requires": { "foreground-child": "^1.5.6", @@ -12276,8 +12254,7 @@ }, "spdx-correct": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha1-BaW01xU6GVvJLDxCW2nzsqlSTII=", + "bundled": true, "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -12286,14 +12263,12 @@ }, "spdx-exceptions": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha1-LHrmEFbHFKW5ubKyr30xHvXHj+k=", + "bundled": true, "dev": true }, "spdx-expression-parse": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", + "bundled": true, "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -12302,14 +12277,12 @@ }, "spdx-license-ids": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=", + "bundled": true, "dev": true }, "split-string": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", + "bundled": true, "dev": true, "requires": { "extend-shallow": "^3.0.0" @@ -12317,8 +12290,7 @@ }, "static-extend": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "bundled": true, "dev": true, "requires": { "define-property": "^0.2.5", @@ -12327,8 +12299,7 @@ "dependencies": { "define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "bundled": true, "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -12338,8 +12309,7 @@ }, "string-width": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "bundled": true, "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -12348,8 +12318,7 @@ }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "bundled": true, "dev": true, "requires": { "ansi-regex": "^3.0.0" @@ -12357,8 +12326,7 @@ }, "strip-bom": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "bundled": true, "dev": true, "requires": { "is-utf8": "^0.2.0" @@ -12366,8 +12334,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "bundled": true, "dev": true }, "supports-color": { @@ -12381,8 +12348,7 @@ }, "test-exclude": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz", - "integrity": "sha1-36Ii8DSAvKaSB8pyizfXS0X3JPo=", + "bundled": true, "dev": true, "requires": { "arrify": "^1.0.1", @@ -12400,8 +12366,7 @@ }, "to-object-path": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "bundled": true, "dev": true, "requires": { "kind-of": "^3.0.2" @@ -12409,8 +12374,7 @@ }, "to-regex": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", + "bundled": true, "dev": true, "requires": { "define-property": "^2.0.2", @@ -12421,8 +12385,7 @@ }, "to-regex-range": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "bundled": true, "dev": true, "requires": { "is-number": "^3.0.0", @@ -12431,8 +12394,7 @@ }, "uglify-js": { "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -12443,8 +12405,7 @@ "dependencies": { "yargs": { "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -12458,15 +12419,13 @@ }, "uglify-to-browserify": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "bundled": true, "dev": true, "optional": true }, "union-value": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "bundled": true, "dev": true, "requires": { "arr-union": "^3.1.0", @@ -12477,8 +12436,7 @@ "dependencies": { "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "bundled": true, "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -12486,8 +12444,7 @@ }, "set-value": { "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "bundled": true, "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -12500,8 +12457,7 @@ }, "unset-value": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "bundled": true, "dev": true, "requires": { "has-value": "^0.3.1", @@ -12510,8 +12466,7 @@ "dependencies": { "has-value": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "bundled": true, "dev": true, "requires": { "get-value": "^2.0.3", @@ -12521,8 +12476,7 @@ "dependencies": { "isobject": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "bundled": true, "dev": true, "requires": { "isarray": "1.0.0" @@ -12532,22 +12486,19 @@ }, "has-values": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "bundled": true, "dev": true } } }, "urix": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "bundled": true, "dev": true }, "use": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha1-FHFr8D/f79AwQK71jYtLhfOnxUQ=", + "bundled": true, "dev": true, "requires": { "kind-of": "^6.0.2" @@ -12555,16 +12506,14 @@ "dependencies": { "kind-of": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", + "bundled": true, "dev": true } } }, "validate-npm-package-license": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha1-gWQ7y+8b3+zUYjeT3EZIlIupgzg=", + "bundled": true, "dev": true, "requires": { "spdx-correct": "^3.0.0", @@ -12573,8 +12522,7 @@ }, "which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", + "bundled": true, "dev": true, "requires": { "isexe": "^2.0.0" @@ -12582,27 +12530,23 @@ }, "which-module": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "bundled": true, "dev": true }, "window-size": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "bundled": true, "dev": true, "optional": true }, "wordwrap": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "bundled": true, "dev": true }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "bundled": true, "dev": true, "requires": { "string-width": "^1.0.1", @@ -12611,14 +12555,12 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "bundled": true, "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "bundled": true, "dev": true, "requires": { "number-is-nan": "^1.0.0" @@ -12626,8 +12568,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -12637,8 +12578,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "bundled": true, "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -12648,14 +12588,12 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "bundled": true, "dev": true }, "write-file-atomic": { "version": "1.3.4", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", - "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -12665,20 +12603,17 @@ }, "y18n": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "bundled": true, "dev": true }, "yallist": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "bundled": true, "dev": true }, "yargs": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha1-kLhpk07W6HERXqL/WLA/RyTtLXc=", + "bundled": true, "dev": true, "requires": { "cliui": "^4.0.0", @@ -12697,14 +12632,12 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "bundled": true, "dev": true }, "cliui": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha1-NIQi2+gtgAswIu709qwQvy5NG0k=", + "bundled": true, "dev": true, "requires": { "string-width": "^2.1.1", @@ -12714,8 +12647,7 @@ }, "yargs-parser": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "bundled": true, "dev": true, "requires": { "camelcase": "^4.1.0" @@ -12725,8 +12657,7 @@ }, "yargs-parser": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", - "integrity": "sha1-8TdqM7Ziml0GN4KUTacyYx6WaVA=", + "bundled": true, "dev": true, "requires": { "camelcase": "^4.1.0" @@ -12734,8 +12665,7 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "bundled": true, "dev": true } } @@ -12968,6 +12898,34 @@ "execa": "^0.7.0", "lcid": "^1.0.0", "mem": "^1.1.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + } } }, "os-tmpdir": { @@ -13956,9 +13914,9 @@ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" }, "prettier": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.13.6.tgz", - "integrity": "sha512-p5eqCNiohWZN++7aJXUVj0JgLqHCPLf9GLIcLBHGNWs4Y9FJOPs6+KNO2WT0udJIQJTbeZFrJkjzjcb8fkAYYQ==" + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.13.7.tgz", + "integrity": "sha512-KIU72UmYPGk4MujZGYMFwinB7lOf2LsDNGSOC8ufevsrPLISrZbNJlWstRi3m0AMuszbH+EFSQ/r6w56RSPK6w==" }, "pretty-error": { "version": "1.2.0", @@ -14134,6 +14092,13 @@ "requires": { "decode-uri-component": "^0.2.0", "strict-uri-encode": "^2.0.0" + }, + "dependencies": { + "strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" + } } }, "querystring": { @@ -14269,9 +14234,9 @@ "dev": true }, "react-ace": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-6.1.2.tgz", - "integrity": "sha512-AHJCyIWl3P7g0sUAyNKR94e/IaSIbUF3qSPpNLIvP9L3/kNGD7tZUVeNZUSZYduW4czSFiXT2PLRS8uT2d7BEw==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-6.1.4.tgz", + "integrity": "sha512-a8/lAsy2bfi7Ho+3Kaj8hBPR+PEiCTG9xFG9LIjCJrv5WQFYFpeFTiPWA96M3t+LgIDFFltwfVTwD2pmdAVOxQ==", "requires": { "brace": "^0.11.0", "diff-match-patch": "^1.0.0", @@ -14406,9 +14371,9 @@ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "react-modal": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.4.5.tgz", - "integrity": "sha512-fYaGmsvt4z5voC2Bl/9ngIWES4BSRYgGnTljMwuzTuYZ1BBpaZbnXia8xlvj7mF0kg3aPV+5APjZRiMfRG6vyA==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.5.1.tgz", + "integrity": "sha512-GxL7ycOgKC+p641cR+V1bw5dC1faL2N86/AJlzbMVmvt1totoylgkJmn9zvLuHeuarGbB7CLfHMGpeRowaj2jQ==", "requires": { "exenv": "^1.2.0", "prop-types": "^15.5.10", @@ -14515,35 +14480,10 @@ "warning": "^3.0.0" }, "dependencies": { - "history": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/history/-/history-3.3.0.tgz", - "integrity": "sha1-/O3M6PEpdTcVRdc1RhAzV5ptrpw=", - "requires": { - "invariant": "^2.2.1", - "loose-envify": "^1.2.0", - "query-string": "^4.2.2", - "warning": "^3.0.0" - } - }, "hoist-non-react-statics": { "version": "2.5.5", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" - }, - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" } } }, @@ -14779,9 +14719,9 @@ } }, "redux-devtools-instrument": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/redux-devtools-instrument/-/redux-devtools-instrument-1.8.3.tgz", - "integrity": "sha1-xRDWerTl5FJazW5BDCWrRrhaynw=", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/redux-devtools-instrument/-/redux-devtools-instrument-1.9.0.tgz", + "integrity": "sha512-pLFQoja1ojpsSRTWbC9yyc/a+z8uwOD7FPKLp+Abs7qjsah6khA5o8HBE2wa0VipE5vniYINdkNyxV/2iWADKg==", "dev": true, "requires": { "lodash": "^4.2.0", @@ -16228,9 +16168,9 @@ "dev": true }, "strict-uri-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" }, "string-length": { "version": "2.0.0", @@ -16340,9 +16280,9 @@ }, "dependencies": { "ajv": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.1.tgz", - "integrity": "sha512-pgZos1vgOHDiC7gKNbZW8eKvCnNXARv2oqrGQT7Hzbq5Azp7aZG6DJzADnkuSq7RH6qkXp4J/m68yPX/2uBHyQ==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", + "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -16381,6 +16321,18 @@ } } }, + "subscriptions-transport-ws": { + "version": "0.9.12", + "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.12.tgz", + "integrity": "sha512-57Ar8hjr/63fCx1kM3kyDr64FAPQITMguuFuTGgYVx2v1JOaPoTeZyTIenVPgv+7mDYt7E+h+Jyxvznb+UKVWw==", + "requires": { + "backo2": "^1.0.2", + "eventemitter3": "^3.1.0", + "iterall": "^1.2.1", + "symbol-observable": "^1.0.4", + "ws": "^5.2.0" + } + }, "superagent": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/superagent/-/superagent-1.8.5.tgz", @@ -17234,9 +17186,9 @@ }, "dependencies": { "ajv": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.1.tgz", - "integrity": "sha512-pgZos1vgOHDiC7gKNbZW8eKvCnNXARv2oqrGQT7Hzbq5Azp7aZG6DJzADnkuSq7RH6qkXp4J/m68yPX/2uBHyQ==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", + "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -17539,9 +17491,9 @@ }, "dependencies": { "ajv": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.1.tgz", - "integrity": "sha512-pgZos1vgOHDiC7gKNbZW8eKvCnNXARv2oqrGQT7Hzbq5Azp7aZG6DJzADnkuSq7RH6qkXp4J/m68yPX/2uBHyQ==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", + "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -17587,21 +17539,10 @@ } }, "use": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true }, "util": { "version": "0.10.3", @@ -17647,9 +17588,9 @@ "dev": true }, "uuid": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.0.tgz", - "integrity": "sha512-ijO9N2xY/YaOqQ5yz5c4sy2ZjWmA6AR6zASb/gdpeKZ8+948CxwfMW9RrKVk5may6ev8c0/Xguu32e2Llelpqw==" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "v8-compile-cache": { "version": "2.0.0", @@ -18112,23 +18053,23 @@ "dev": true }, "webpack": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.14.0.tgz", - "integrity": "sha512-CgZPUwobJbQlZqpylDNtEazZLfNnGuyFmpk1dHIP2kFchtyMWB+W2wBKPImSnSQ2rbX/WZMKiQax+SZmlUXuQQ==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.16.1.tgz", + "integrity": "sha512-6jpzObU18y7lXDJz7XCLvzgrqcJ0rZ2jhKvnTivza9gM2GvPW93xxtmEll2GgmdC0zVQAtbHrH/9BtyMjSDZfA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.12", - "@webassemblyjs/helper-module-context": "1.5.12", - "@webassemblyjs/wasm-edit": "1.5.12", - "@webassemblyjs/wasm-opt": "1.5.12", - "@webassemblyjs/wasm-parser": "1.5.12", + "@webassemblyjs/ast": "1.5.13", + "@webassemblyjs/helper-module-context": "1.5.13", + "@webassemblyjs/wasm-edit": "1.5.13", + "@webassemblyjs/wasm-opt": "1.5.13", + "@webassemblyjs/wasm-parser": "1.5.13", "acorn": "^5.6.2", "acorn-dynamic-import": "^3.0.0", "ajv": "^6.1.0", "ajv-keywords": "^3.1.0", "chrome-trace-event": "^1.0.0", "enhanced-resolve": "^4.1.0", - "eslint-scope": "^3.7.1", + "eslint-scope": "^4.0.0", "json-parse-better-errors": "^1.0.2", "loader-runner": "^2.3.0", "loader-utils": "^1.1.0", @@ -18203,15 +18144,14 @@ } } }, - "enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "eslint-scope": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "expand-brackets": { @@ -18519,13 +18459,23 @@ "requires": { "has-flag": "^3.0.0" } + }, + "ws": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } } } }, "webpack-cli": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.0.8.tgz", - "integrity": "sha512-KnRLJ0BUaYRqrhAMb9dv3gzdmhmgIMKo0FmdsnmfqbPGtLnnZ6tORZAvmmKfr+A0VgiVpqC60Gv7Ofg0R2CHtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.1.0.tgz", + "integrity": "sha512-p5NeKDtYwjZozUWq6kGNs9w+Gtw/CPvyuXjXn2HMdz8Tie+krjEg8oAtonvIyITZdvpF7XG9xDHwscLr2c+ugQ==", "dev": true, "requires": { "chalk": "^2.4.1", @@ -18538,7 +18488,7 @@ "loader-utils": "^1.1.0", "supports-color": "^5.4.0", "v8-compile-cache": "^2.0.0", - "yargs": "^11.1.0" + "yargs": "^12.0.1" }, "dependencies": { "ansi-escapes": { @@ -18605,17 +18555,13 @@ "wrap-ansi": "^2.0.0" } }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "decamelize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", + "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "xregexp": "4.0.0" } }, "external-editor": { @@ -18638,6 +18584,15 @@ "escape-string-regexp": "^1.0.5" } }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, "inquirer": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.0.0.tgz", @@ -18665,6 +18620,16 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, "onetime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", @@ -18674,6 +18639,30 @@ "mimic-fn": "^1.0.0" } }, + "p-limit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", + "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -18685,9 +18674,9 @@ } }, "rxjs": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.1.tgz", - "integrity": "sha512-OwMxHxmnmHTUpgO+V7dZChf3Tixf4ih95cmXjzzadULziVl/FKhHScGLj4goEw9weePVOH2Q0+GcCBUhKCZc/g==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz", + "integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -18731,14 +18720,14 @@ } }, "yargs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.1.tgz", + "integrity": "sha512-B0vRAp1hRX4jgIOWFtjfNjd9OA9RWYZ6tqGA9/I/IrTMsxmKvtWy+ersM+jzpQqbC3YfLzeABPdeTgcJ9eu1qQ==", "dev": true, "requires": { "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", + "decamelize": "^2.0.0", + "find-up": "^3.0.0", "get-caller-file": "^1.0.1", "os-locale": "^2.0.0", "require-directory": "^2.1.1", @@ -18746,14 +18735,14 @@ "set-blocking": "^2.0.0", "string-width": "^2.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^10.1.0" } }, "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", "dev": true, "requires": { "camelcase": "^4.1.0" @@ -18785,9 +18774,9 @@ } }, "webpack-hot-middleware": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.22.2.tgz", - "integrity": "sha512-uccPS6b/UlXJoNCS+3fuc40z2KZgO0qQhnu+Ne1iZiHTy9s5fMCJAV+Vc8VTVkN203UphsxQmkumxYeHLiQ5jg==", + "version": "2.22.3", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.22.3.tgz", + "integrity": "sha512-mrG3bJGX4jgWbrpY0ghIpPgCmNhZziFMBJBmZfpIe6K/P1rWPkdkbGihbCUIufgQ8ruX4txE5/CKSeFNzDcYOw==", "dev": true, "requires": { "ansi-html": "0.0.7", @@ -19036,13 +19025,11 @@ "dev": true }, "ws": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", - "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", - "dev": true, + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0" + "async-limiter": "~1.0.0" } }, "xml-name-validator": { @@ -19051,6 +19038,12 @@ "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", "dev": true }, + "xregexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", + "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==", + "dev": true + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", @@ -19235,6 +19228,19 @@ "buffer-crc32": "~0.2.3", "fd-slicer": "~1.0.1" } + }, + "zen-observable": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.8.tgz", + "integrity": "sha512-HnhhyNnwTFzS48nihkCZIJGsWGFcYUz+XPDlPK5W84Ifji8SksC6m7sQWOf8zdCGhzQ4tDYuMYGu5B0N1dXTtg==" + }, + "zen-observable-ts": { + "version": "0.8.9", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.9.tgz", + "integrity": "sha512-KJz2O8FxbAdAU5CSc8qZ1K2WYEJb1HxS6XDRF+hOJ1rOYcg6eTMmS9xYHCXzqZZzKw6BbXWyF4UpwSsBQnHJeA==", + "requires": { + "zen-observable": "^0.8.0" + } } } } diff --git a/console/package.json b/console/package.json index c9037f4b9c3ad..97e748c24202e 100644 --- a/console/package.json +++ b/console/package.json @@ -51,11 +51,14 @@ } }, "dependencies": { + "apollo-link": "^1.2.2", + "apollo-link-ws": "^1.0.8", "babel-polyfill": "^6.26.0", "brace": "^0.11.1", "deep-equal": "^1.0.1", "graphiql": "^0.11.11", "graphql": "^0.13.2", + "hasura-console-graphiql": "0.0.1", "history": "^3.0.0", "hoist-non-react-statics": "^1.0.3", "invariant": "^2.2.0", @@ -90,6 +93,7 @@ "redux-logger": "^3.0.6", "redux-thunk": "^2.2.0", "semver": "^5.3.0", + "subscriptions-transport-ws": "^0.9.12", "superagent": "^1.4.0", "uuid": "^3.0.1", "valid-url": "^1.0.9" diff --git a/console/src/components/ApiExplorer/Actions.js b/console/src/components/ApiExplorer/Actions.js index 11eda1c1adc0e..4b97b9cb09a6f 100644 --- a/console/src/components/ApiExplorer/Actions.js +++ b/console/src/components/ApiExplorer/Actions.js @@ -1,5 +1,10 @@ import defaultState from './state'; -import fetch from 'isomorphic-fetch'; +// import fetch from 'isomorphic-fetch'; + +import { SubscriptionClient } from 'subscriptions-transport-ws'; +import { WebSocketLink } from 'apollo-link-ws'; +import { parse } from 'graphql'; +import { execute } from 'apollo-link'; const CHANGE_TAB = 'ApiExplorer/CHANGE_TAB'; const CHANGE_API_SELECTION = 'ApiExplorer/CHANGE_API_SELECTION'; @@ -26,6 +31,11 @@ const API_REQUEST_FAILURE = 'ApiExplorer/API_REQUEST_FAILURE'; const CLEAR_HISTORY = 'ApiExplorer/CLEAR_HISTORY'; const UPDATE_FILE_OBJECT = 'ApiExplorer/UPDATE_FILE_OBJECT'; +const CREATE_WEBSOCKET_CLIENT = 'ApiExplorer/CREATE_WEBSOCKET_CLIENT'; + +const FOCUS_ROLE_HEADER = 'ApiExplorer/FOCUS_ROLE_HEADER'; +const UNFOCUS_ROLE_HEADER = 'ApiExplorer/UNFOCUS_ROLE_HEADER'; + import requestAction from '../Common/makeRequest'; import Endpoints from 'Endpoints'; import { getHeadersAsJSON } from './utils'; @@ -99,6 +109,9 @@ const sendExplorerReq = requestType => { }; }; +const focusHeaderTextbox = () => ({ type: FOCUS_ROLE_HEADER }); +const unfocusTypingHeader = () => ({ type: UNFOCUS_ROLE_HEADER }); + const copyCodeToClipboard = isCopying => { return { type: CODE_GENERATOR_COPY_TO_CLIPBOARD, @@ -156,40 +169,76 @@ const changeRequestParams = newParams => { }; }; -const graphQLFetcherFinal = (graphQLParams, url, headers) => { - const graphqlUrl = url; - const currentHeaders = headers; - const headersFinal = getHeadersAsJSON(currentHeaders); +const createWsClient = (url, headers) => { + const headersFinal = getHeadersAsJSON(headers); + setTimeout(() => null, 500); + const graphqlUrl = `ws://${url.split('//')[1]}`; + const client = new SubscriptionClient(graphqlUrl, { + connectionParams: { + headers: { + ...headersFinal, + }, + }, + }); + return client; +}; - return fetch(graphqlUrl, { - method: 'POST', - headers: headersFinal, - body: JSON.stringify(graphQLParams), - }).then(response => response.json()); +const graphqlSubscriber = (graphQLParams, url, headers) => { + const link = new WebSocketLink(createWsClient(url, headers)); + try { + const fetcher = operation => { + operation.query = parse(operation.query); + return execute(link, operation); + }; + return fetcher(graphQLParams); + } catch (e) { + console.log(e); + return e.json(); + } }; -const changeRequestHeader = (index, key, newValue, isDisabled) => { - return { - type: REQUEST_HEADER_CHANGED, - data: { - index: index, - keyName: key, - newValue: newValue, - isDisabled: isDisabled, - }, - }; +const isSubscription = graphQlParams => { + const queryDoc = parse(graphQlParams.query); + for (const definition of queryDoc.definitions) { + if (definition.kind === 'OperationDefinition') { + const operation = definition.operation; + if (operation === 'subscription') { + return true; + } + } + } + return false; }; -const addRequestHeader = (key, value) => { - return { - type: REQUEST_HEADER_ADDED, - data: { - key: key, - value: value, - }, - }; +const graphQLFetcherFinal = (graphQLParams, url, headers) => { + if (isSubscription(graphQLParams)) { + return graphqlSubscriber(graphQLParams, url, headers); + } + return fetch(url, { + method: 'POST', + headers: getHeadersAsJSON(headers), + body: JSON.stringify(graphQLParams), + }).then(response => response.json()); }; +const changeRequestHeader = (index, key, newValue, isDisabled) => ({ + type: REQUEST_HEADER_CHANGED, + data: { + index: index, + keyName: key, + newValue: newValue, + isDisabled: isDisabled, + }, +}); + +const addRequestHeader = (key, value) => ({ + type: REQUEST_HEADER_ADDED, + data: { + key: key, + value: value, + }, +}); + const removeRequestHeader = index => { return { type: REQUEST_HEADER_REMOVED, @@ -527,6 +576,21 @@ const apiExplorerReducer = (state = defaultState, action) => { enableResponseSection: false, }, }; + case CREATE_WEBSOCKET_CLIENT: + return { + ...state, + webSocketClient: action.data, + }; + case UNFOCUS_ROLE_HEADER: + return { + ...state, + headerFocus: false, + }; + case FOCUS_ROLE_HEADER: + return { + ...state, + headerFocus: true, + }; default: return state; } @@ -553,4 +617,7 @@ export { updateFileObject, editGeneratedJson, graphQLFetcherFinal, + createWsClient, + focusHeaderTextbox, + unfocusTypingHeader, }; diff --git a/console/src/components/ApiExplorer/ApiExplorer.js b/console/src/components/ApiExplorer/ApiExplorer.js index 3a1059e9ea72c..0347b4129bf50 100644 --- a/console/src/components/ApiExplorer/ApiExplorer.js +++ b/console/src/components/ApiExplorer/ApiExplorer.js @@ -66,6 +66,7 @@ class ApiExplorer extends Component { route={this.props.route} dataHeaders={this.props.dataHeaders} numberOfTables={this.props.tables.length} + headerFocus={this.props.headerFocus} /> ); @@ -84,6 +85,7 @@ ApiExplorer.propTypes = { dispatch: PropTypes.func.isRequired, route: PropTypes.object.isRequired, tables: PropTypes.array.isRequierd, + headerFocus: PropTypes.bool.isRequired, }; export default ApiExplorer; diff --git a/console/src/components/ApiExplorer/ApiRequest.js b/console/src/components/ApiExplorer/ApiRequest.js index 43c521689664f..1fcf5f285ae40 100644 --- a/console/src/components/ApiExplorer/ApiRequest.js +++ b/console/src/components/ApiExplorer/ApiRequest.js @@ -12,6 +12,8 @@ import { removeRequestHeader, updateFileObject, editGeneratedJson, + focusHeaderTextbox, + unfocusTypingHeader, } from './Actions'; import GraphiQLWrapper from './GraphiQLWrapper'; @@ -24,6 +26,7 @@ class ApiRequest extends Component { this.state = {}; this.state.bodyAllowedMethods = ['POST']; this.state.tabIndex = 0; + this.timer = null; } componentWillMount() { @@ -69,10 +72,12 @@ class ApiRequest extends Component { } onNewHeaderKeyChanged(e) { + this.handleTypingTimeouts(); this.props.dispatch(addRequestHeader(e.target.value, '')); } onNewHeaderValueChanged(e) { + this.handleTypingTimeouts(); this.props.dispatch(addRequestHeader('', e.target.value)); } @@ -235,6 +240,8 @@ class ApiRequest extends Component { placeholder="Enter Key" data-element-name="key" onChange={this.onHeaderValueChanged.bind(this)} + onFocus={this.handleFocus} + onBlur={this.handleBlur} type="text" /> @@ -258,6 +265,8 @@ class ApiRequest extends Component { placeholder="Enter Value" data-element-name="value" onChange={this.onHeaderValueChanged.bind(this)} + onFocus={this.handleFocus} + onBlur={this.handleBlur} type="text" /> @@ -321,6 +330,8 @@ class ApiRequest extends Component { ); default: @@ -328,6 +339,14 @@ class ApiRequest extends Component { } } + handleFocus = () => { + this.props.dispatch(focusHeaderTextbox()); + }; + + handleBlur = () => { + this.props.dispatch(unfocusTypingHeader()); + }; + handleFileChange(e) { if (e.target.files.length > 0) { this.props.dispatch(updateFileObject(e.target.files[0])); @@ -358,6 +377,7 @@ ApiRequest.propTypes = { bodyType: PropTypes.string.isRequired, route: PropTypes.object.isRequired, numberOfTables: PropTypes.number.isRequired, + headerFocus: PropTypes.bool.isRequired, }; export default ApiRequest; diff --git a/console/src/components/ApiExplorer/ApiRequestWrapper.js b/console/src/components/ApiExplorer/ApiRequestWrapper.js index 59be9bf5b68b5..7f31d028adb10 100644 --- a/console/src/components/ApiExplorer/ApiRequestWrapper.js +++ b/console/src/components/ApiExplorer/ApiRequestWrapper.js @@ -39,6 +39,7 @@ class ApiRequestWrapper extends Component { dispatch={this.props.dispatch} dataHeaders={this.props.dataHeaders} numberOfTables={this.props.numberOfTables} + headerFocus={this.props.headerFocus} /> {this.props.request.bodyType !== 'graphql' ? ( { + if (this.state.headerFocus) { + return null; + } return graphQLFetcherFinal( graphQLParams, - graphqlUrl, + this.props.data.url, this.props.data.headers ); }; @@ -78,6 +77,7 @@ GraphiQLWrapper.propTypes = { dispatch: PropTypes.func.isRequired, data: PropTypes.object.isRequired, numberOfTables: PropTypes.number.isRequired, + headerFocus: PropTypes.bool.isRequired, }; export default GraphiQLWrapper; diff --git a/console/src/components/ApiExplorer/state.js b/console/src/components/ApiExplorer/state.js index f6f47b46cb623..e1aa9098c6b2e 100644 --- a/console/src/components/ApiExplorer/state.js +++ b/console/src/components/ApiExplorer/state.js @@ -62,6 +62,7 @@ const defaultState = { }, explorerData, authApiExpanded: 'Username-password Login', + headerFocus: false, }; export default defaultState; diff --git a/server/.gitignore b/server/.gitignore index 6f3c0d21739cf..1a58f186b6400 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -14,7 +14,7 @@ cabal-dev .cabal-sandbox/ cabal.sandbox.config cabal.config -*.prof +*.prof* *.aux *.hp TAGS diff --git a/server/graphiql/package.json b/server/graphiql/package.json index a1e78ec6fd9ed..a78484795a55b 100644 --- a/server/graphiql/package.json +++ b/server/graphiql/package.json @@ -1,13 +1,16 @@ { - "name": "react-app", + "name": "graphiql", "version": "0.1.0", "private": true, "dependencies": { + "apollo-link": "^1.2.2", + "apollo-link-ws": "^1.0.8", "graphiql": "^0.11.11", "graphql": "^0.13.2", - "react": "^16.2.0", - "react-dom": "^16.2.0", - "react-scripts": "1.1.1" + "react": "^16.4.1", + "react-dom": "^16.4.1", + "react-scripts": "1.1.4", + "subscriptions-transport-ws": "^0.9.12" }, "scripts": { "start": "react-scripts start", diff --git a/server/graphiql/src/App.js b/server/graphiql/src/App.js index 6611ba2a2c847..9e73ed192f786 100644 --- a/server/graphiql/src/App.js +++ b/server/graphiql/src/App.js @@ -1,34 +1,31 @@ import React, { Component } from 'react'; -// import logo from './logo.svg'; import '../node_modules/graphiql/graphiql.css'; import GraphiQL from 'graphiql'; -import fetch from 'isomorphic-fetch'; +import {query, variables} from './graphiql-vars-live'; -import {query, variables} from './graphiql-vars'; - -const { - parse, - buildASTSchema -} = require('graphql'); - -// const ravenUrl = process.env.RAVEN_URL || 'http://localhost:8080'; -// const ravenUrl = window.location.hostname; +import { parse } from 'graphql'; +import { execute } from 'apollo-link'; +import { WebSocketLink } from "apollo-link-ws"; +import { SubscriptionClient } from "subscriptions-transport-ws"; class App extends Component { render() { - const graphQLFetcher = function(graphQLParams) { - return fetch('/v1alpha1/graphql', { - method: 'post', - headers: { 'Content-Type': 'application/json' - }, - body: JSON.stringify(graphQLParams) - }).then(response => response.json()); + const GRAPHQL_ENDPOINT = 'ws://' + window.location.host + "/v1alpha1/graphql"; + + const client = new SubscriptionClient( + GRAPHQL_ENDPOINT, {} + ); + + const link = new WebSocketLink(client); + const fetcher = (operation) => { + operation.query = parse(operation.query); + return execute(link, operation); }; - var content = ; + var content = ; return (
diff --git a/server/graphiql/src/graphiql-vars-live.js b/server/graphiql/src/graphiql-vars-live.js new file mode 100644 index 0000000000000..b43be1dcb3a15 --- /dev/null +++ b/server/graphiql/src/graphiql-vars-live.js @@ -0,0 +1,53 @@ +var query = ` +subscription live_reaction { + country { + name + votes { + count: vote_count + } + comments { + comment + } + } +} + +mutation vote_for_france { + insert_country_vote (objects: {country: "France"}) { + affected_rows + } +} + +mutation vote_for_croatia { + insert_country_vote (objects: {country: "Croatia"}) { + affected_rows + } +} + +mutation comment_on_france { + insert_comment ( + objects: { + country: "France" + comment: "rot in hell" + } + ) { + affected_rows + } +} + +mutation comment_on_croatia { + insert_comment ( + objects: { + country: "Croatia" + comment: "beautiful football" + } + ) { + affected_rows + } +} +`; +var variables=` +{ +} +`; +exports.query = query; +exports.variables = variables; diff --git a/server/graphql-engine.cabal b/server/graphql-engine.cabal index add39a78ea450..d8314ee2ea7f2 100644 --- a/server/graphql-engine.cabal +++ b/server/graphql-engine.cabal @@ -105,7 +105,21 @@ library , yaml , template-haskell >= 2.11 + -- websockets interface related + , websockets + , wai-websockets + , hashtables + , stm + , stm-containers + , list-t + , async + + -- logging related + , base64-bytestring >= 1.0 + , auto-update + exposed-modules: Hasura.Server.App + , Hasura.Server.Auth , Hasura.Server.Init , Hasura.Server.Middleware , Hasura.Server.Logging @@ -139,14 +153,20 @@ library , Hasura.RQL.DML.QueryTemplate , Hasura.RQL.GBoolExp - , Hasura.GraphQL.Execute - , Hasura.GraphQL.Execute.Result + , Hasura.GraphQL.Transport.HTTP.Protocol + , Hasura.GraphQL.Transport.HTTP + , Hasura.GraphQL.Transport.WebSocket.Protocol + , Hasura.GraphQL.Transport.WebSocket.Server + , Hasura.GraphQL.Transport.WebSocket , Hasura.GraphQL.Schema , Hasura.GraphQL.Utils + , Hasura.GraphQL.Validate , Hasura.GraphQL.Validate.Types , Hasura.GraphQL.Validate.Context , Hasura.GraphQL.Validate.Field , Hasura.GraphQL.Validate.InputValue + , Hasura.GraphQL.Resolve + , Hasura.GraphQL.Resolve.LiveQuery , Hasura.GraphQL.Resolve.BoolExp , Hasura.GraphQL.Resolve.Context , Hasura.GraphQL.Resolve.InputValue @@ -156,6 +176,7 @@ library , Data.Text.Extended , Data.Sequence.NonEmpty + , Data.TByteString , Data.HashMap.Strict.InsOrd.Extended , Hasura.SQL.DML @@ -164,6 +185,7 @@ library , Hasura.SQL.GeoJSON , Hasura.SQL.Time , Hasura.Prelude + , Hasura.Logging , Ops , TH @@ -178,7 +200,7 @@ executable graphql-engine default-language: Haskell2010 hs-source-dirs: src-exec build-depends: base - , Spock-core >= 0.11 + , warp >= 3.2 , graphql-engine , aeson >= 1.0 , bytestring >= 0.10 diff --git a/server/src-exec/Main.hs b/server/src-exec/Main.hs index 237dec6a3c61c..4b5124fd5e2fe 100644 --- a/server/src-exec/Main.hs +++ b/server/src-exec/Main.hs @@ -6,10 +6,10 @@ module Main where import Ops import Data.Time.Clock (getCurrentTime) +import qualified Network.Wai.Handler.Warp as Warp import Options.Applicative import System.Environment (lookupEnv) import System.Exit (exitFailure) -import Web.Spock.Core (runSpockNoBanner, spockT) import qualified Data.Aeson as A import qualified Data.ByteString.Char8 as BC @@ -18,11 +18,12 @@ import qualified Data.ByteString.Lazy.Char8 as BLC import qualified Data.Text as T import qualified Data.Yaml as Y +import Hasura.Logging (mkLoggerCtx, defaultLoggerSettings) import Hasura.Prelude import Hasura.RQL.DDL.Metadata (fetchMetadata) -import Hasura.Server.App (AuthMode (..), app, ravenLogGen) +import Hasura.Server.App (mkWaiApp) +import Hasura.Server.Auth (AuthMode (..)) import Hasura.Server.Init -import Hasura.Server.Logging (withStdoutLogger) import qualified Database.PG.Query as Q @@ -99,12 +100,13 @@ mkAuthMode mAccessKey mWebHook = (Just key, Just hook) -> return $ AMAccessKeyAndHook key hook main :: IO () -main = withStdoutLogger ravenLogGen $ \rlogger -> do +main = do (RavenOptions rci ravenMode) <- parseArgs mEnvDbUrl <- lookupEnv "HASURA_GRAPHQL_DATABASE_URL" ci <- either ((>> exitFailure) . putStrLn . connInfoErrModifier) return $ mkConnInfo mEnvDbUrl rci printConnInfo ci + loggerCtx <- mkLoggerCtx defaultLoggerSettings case ravenMode of ROServe (ServeOptions port cp isoL mRootDir mAccessKey corsCfg mWebHook enableConsole) -> do mFinalAccessKey <- considerEnv "HASURA_GRAPHQL_ACCESS_KEY" mAccessKey @@ -117,9 +119,11 @@ main = withStdoutLogger ravenLogGen $ \rlogger -> do initialise ci migrate ci pool <- Q.initPGPool ci cp - runSpockNoBanner port $ do - putStrLn $ "server: running on port " ++ show port - spockT id $ app isoL mRootDir rlogger pool am finalCorsCfg enableConsole + putStrLn $ "server: running on port " ++ show port + app <- mkWaiApp isoL mRootDir loggerCtx pool am finalCorsCfg enableConsole + let warpSettings = Warp.setPort port Warp.defaultSettings + -- Warp.setHost "*" Warp.defaultSettings + Warp.runSettings warpSettings app ROExport -> do res <- runTx ci fetchMetadata either ((>> exitFailure) . printJSON) printJSON res diff --git a/server/src-lib/Data/TByteString.hs b/server/src-lib/Data/TByteString.hs new file mode 100644 index 0000000000000..f5129542f2691 --- /dev/null +++ b/server/src-lib/Data/TByteString.hs @@ -0,0 +1,41 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Data.TByteString + ( TByteString + , fromText + , fromBS + , fromLBS + ) where + +import qualified Data.Aeson as J +import qualified Data.ByteString as B +import qualified Data.ByteString.Base64 as B64 +import qualified Data.ByteString.Lazy as BL +import qualified Data.Text as T +import qualified Data.Text.Encoding as TE + +import Data.Bool (bool) +import Prelude + +newtype TByteString + = TByteString (Bool, T.Text) + deriving (Show, Eq) + +instance J.ToJSON TByteString where + toJSON (TByteString (isBase64, t)) = + bool (J.toJSON t) (J.toJSON ["Base64", t]) isBase64 + +fromText :: T.Text -> TByteString +fromText t = TByteString (False, t) + +fromBS :: B.ByteString -> TByteString +fromBS bs = + TByteString $ + -- if the bs in not utf-8 encoded, encode it to Base64 + case TE.decodeUtf8' bs of + Left _ -> (True, TE.decodeUtf8 $ B64.encode bs) + Right t -> (False, t) + +fromLBS :: BL.ByteString -> TByteString +fromLBS = + fromBS . BL.toStrict diff --git a/server/src-lib/Hasura/GraphQL/Execute.hs b/server/src-lib/Hasura/GraphQL/Execute.hs deleted file mode 100644 index cda39bc23f4ab..0000000000000 --- a/server/src-lib/Hasura/GraphQL/Execute.hs +++ /dev/null @@ -1,249 +0,0 @@ -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TemplateHaskell #-} - -module Hasura.GraphQL.Execute - ( validateGQ - , GraphQLRequest - , runGQ - ) where - -import Data.Has -import Hasura.Prelude - -import qualified Data.Aeson as J -import qualified Data.Aeson.Casing as J -import qualified Data.Aeson.TH as J -import qualified Data.ByteString.Lazy as BL -import qualified Data.HashMap.Strict as Map -import qualified Data.Text as T -import qualified Data.Vector as V -import qualified Database.PG.Query as Q -import qualified Language.GraphQL.Draft.Parser as G -import qualified Language.GraphQL.Draft.Syntax as G -import qualified Hasura.Server.Query as RQ - -import Hasura.GraphQL.Execute.Result -import Hasura.GraphQL.Resolve.Context -import Hasura.GraphQL.Resolve.Introspect -import Hasura.GraphQL.Schema -import Hasura.GraphQL.Validate.Context -import Hasura.GraphQL.Validate.Field -import Hasura.GraphQL.Validate.InputValue -import Hasura.GraphQL.Validate.Types -import Hasura.RQL.Types -import Hasura.SQL.Types - -import qualified Hasura.GraphQL.Resolve.Mutation as RM -import qualified Hasura.GraphQL.Resolve.Select as RS - -newtype GraphQLQuery - = GraphQLQuery { unGraphQLQuery :: [G.ExecutableDefinition] } - deriving (Show, Eq) - -instance J.FromJSON GraphQLQuery where - parseJSON = J.withText "GraphQLQuery" $ \t -> - case G.parseExecutableDoc t of - Left _ -> fail "parsing the graphql query failed" - Right q -> return $ GraphQLQuery $ G.getExecutableDefinitions q - -newtype OperationName - = OperationName { _unOperationName :: G.Name } - deriving (Show, Eq) - -instance J.FromJSON OperationName where - parseJSON v = OperationName . G.Name <$> J.parseJSON v - -type VariableValues = Map.HashMap G.Variable J.Value - -data GraphQLRequest - = GraphQLRequest - { _grOperationName :: !(Maybe OperationName) - , _grQuery :: !GraphQLQuery - , _grVariables :: !(Maybe VariableValues) - } deriving (Show, Eq) - -$(J.deriveFromJSON (J.aesonDrop 3 J.camelCase){J.omitNothingFields=True} - ''GraphQLRequest - ) - -getTypedOp - :: (MonadError QErr m) - => Maybe OperationName - -> [G.SelectionSet] - -> [G.TypedOperationDefinition] - -> m G.TypedOperationDefinition -getTypedOp opNameM selSets opDefs = - case (opNameM, selSets, opDefs) of - (Just opName, [], _) -> do - let n = _unOperationName opName - opDefM = find (\opDef -> G._todName opDef == Just n) opDefs - onNothing opDefM $ throwVE $ - "no such operation found in the document: " <> showName n - (Just _, _, _) -> - throwVE $ "operationName cannot be used when " <> - "an anonymous operation exists in the document" - (Nothing, [selSet], []) -> - return $ G.TypedOperationDefinition - G.OperationTypeQuery Nothing [] [] selSet - (Nothing, [], [opDef]) -> - return opDef - (Nothing, _, _) -> - throwVE $ "exactly one operation has to be present " <> - "in the document when operationName is not specified" - --- For all the variables defined there will be a value in the final map --- If no default, not in variables and nullable, then null value -getAnnVarVals - :: ( MonadReader r m, Has TypeMap r - , MonadError QErr m - ) - => [G.VariableDefinition] - -> VariableValues - -> m AnnVarVals -getAnnVarVals varDefsL inpVals = do - - varDefs <- onLeft (mkMapWith G._vdVariable varDefsL) $ \dups -> - throwVE $ "the following variables are defined more than once: " <> - showVars dups - - let unexpectedVars = filter (not . (`Map.member` varDefs)) $ Map.keys inpVals - - unless (null unexpectedVars) $ - throwVE $ "unexpected variables in variableValues: " <> - showVars unexpectedVars - - forM varDefs $ \(G.VariableDefinition var ty defM) -> do - let baseTy = getBaseTy ty - baseTyInfo <- getTyInfoVE baseTy - -- check that the variable is defined on input types - when (isObjTy baseTyInfo) $ throwVE $ objTyErrMsg baseTy - - let defM' = bool (defM <|> Just G.VCNull) defM $ G.isNotNull ty - annDefM <- withPathK "defaultValue" $ - mapM (validateInputValue constValueParser ty) defM' - let inpValM = Map.lookup var inpVals - annInpValM <- withPathK "variableValues" $ - mapM (validateInputValue jsonParser ty) inpValM - let varValM = annInpValM <|> annDefM - onNothing varValM $ throwVE $ "expecting a value for non-null type: " - <> G.showGT ty <> " in variableValues" - where - objTyErrMsg namedTy = - "variables can only be defined on input types" - <> "(enums, scalars, input objects), but " - <> showNamedTy namedTy <> " is an object type" - - showVars :: (Functor f, Foldable f) => f G.Variable -> Text - showVars = showNames . fmap G.unVariable - -validateFrag - :: (MonadError QErr m, MonadReader r m, Has TypeMap r) - => G.FragmentDefinition -> m FragDef -validateFrag (G.FragmentDefinition n onTy dirs selSet) = do - unless (null dirs) $ throwVE - "unexpected directives at fragment definition" - tyInfo <- getTyInfoVE onTy - objTyInfo <- onNothing (getObjTyM tyInfo) $ throwVE - "fragments can only be defined on object types" - return $ FragDef n objTyInfo selSet - -{-# SCC validateGQ #-} -validateGQ - :: (MonadError QErr m, MonadReader GCtx m) - => GraphQLRequest - -> m SelSet -validateGQ (GraphQLRequest opNameM q varValsM) = do - - -- get the operation that needs to be evaluated - opDef <- getTypedOp opNameM selSets opDefs - - ctx <- ask - -- get the operation root - opRoot <- case G._todType opDef of - G.OperationTypeQuery -> return $ _gQueryRoot ctx - G.OperationTypeMutation -> onNothing (_gMutRoot ctx) $ throwVE - "no mutations exist" - _ -> throwVE "subscriptions are not supported" - - -- annotate the variables of this operation - annVarVals <- getAnnVarVals (G._todVariableDefinitions opDef) $ - fromMaybe Map.empty varValsM - - -- annotate the fragments - fragDefs <- onLeft (mkMapWith G._fdName fragDefsL) $ \dups -> - throwVE $ "the following fragments are defined more than once: " <> - showNames dups - annFragDefs <- mapM validateFrag fragDefs - - -- build a validation ctx - let valCtx = ValidationCtx (_gTypes ctx) annVarVals annFragDefs - - flip runReaderT valCtx $ denormSelSet [] opRoot $ G._todSelectionSet opDef - - where - (selSets, opDefs, fragDefsL) = G.partitionExDefs $ unGraphQLQuery q - -{-# SCC buildTx #-} -buildTx :: UserInfo -> GCtx -> Field -> Q.TxE QErr BL.ByteString -buildTx userInfo gCtx fld = do - opCxt <- getOpCtx $ _fName fld - tx <- fmap fst $ runConvert (fldMap, orderByCtx) $ case opCxt of - - OCSelect tn permFilter hdrs -> - validateHdrs hdrs >> RS.convertSelect tn permFilter fld - OCInsert tn vn cols hdrs -> - validateHdrs hdrs >> RM.convertInsert (tn, vn) cols fld - OCUpdate tn permFilter hdrs -> - validateHdrs hdrs >> RM.convertUpdate tn permFilter fld - OCDelete tn permFilter hdrs -> - validateHdrs hdrs >> RM.convertDelete tn permFilter fld - tx - where - opCtxMap = _gOpCtxMap gCtx - fldMap = _gFields gCtx - orderByCtx = _gOrdByEnums gCtx - - getOpCtx f = - onNothing (Map.lookup f opCtxMap) $ throw500 $ - "lookup failed: opctx: " <> showName f - - validateHdrs hdrs = do - let receivedHdrs = map fst $ userHeaders userInfo - forM_ hdrs $ \hdr -> - unless (hdr `elem` map T.toLower receivedHdrs) $ - throw400 NotFound $ hdr <<> " header is expected but not found" - -{-# SCC resolveFld #-} -resolveFld - :: (MonadIO m, MonadError QErr m) - => Q.PGPool -> Q.TxIsolation - -> UserInfo -> GCtx - -> Field -> m BL.ByteString -resolveFld pool isoL userInfo gCtx fld = - case _fName fld of - "__type" -> J.encode <$> runReaderT (typeR fld) gCtx - "__schema" -> J.encode <$> runReaderT (schemaR fld) gCtx - "__typename" -> return $ J.encode J.Null - _ -> runTx $ buildTx userInfo gCtx fld - where - runTx tx = - Q.runTx pool (isoL, Nothing) $ - RQ.setHeadersTx userInfo >> tx - -runGQ - :: (MonadIO m, MonadError QErr m) - => Q.PGPool -> Q.TxIsolation - -> UserInfo -> GCtxMap - -> GraphQLRequest - -> m BL.ByteString -runGQ pool isoL userInfo gCtxMap req = do - fields <- runReaderT (validateGQ req) gCtx - -- putLText $ J.encodeToLazyText $ J.toJSON fields - respFlds <- fmap V.fromList $ forM (toList fields) $ \fld -> do - fldResp <- resolveFld pool isoL userInfo gCtx fld - return (G.unName $ G.unAlias $ _fAlias fld, fldResp) - return $ encodeGQResp $ GQSuccess $ mkJSONObj respFlds - where - gCtx = getGCtx (userRole userInfo) gCtxMap diff --git a/server/src-lib/Hasura/GraphQL/Execute/Result.hs b/server/src-lib/Hasura/GraphQL/Execute/Result.hs deleted file mode 100644 index fe5624e9b2776..0000000000000 --- a/server/src-lib/Hasura/GraphQL/Execute/Result.hs +++ /dev/null @@ -1,54 +0,0 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE OverloadedStrings #-} - -module Hasura.GraphQL.Execute.Result - ( encodeGQErr - , encodeJSONObject - , encodeGQResp - , mkJSONObj - , GQResp(..) - ) where - -import Hasura.Prelude - -import qualified Data.Aeson as J -import qualified Data.ByteString.Builder as BB -import qualified Data.ByteString.Lazy as BL -import qualified Data.Text.Encoding as TE -import qualified Data.Vector as V - -import Hasura.RQL.Types - -encodeGQErr :: Text -> QErr -> J.Value -encodeGQErr role qErr = - J.object [ "errors" J..= [encodeQErr role qErr]] - -data GQResp - = GQSuccess BL.ByteString - | GQPreExecError [J.Value] - | GQExecError [J.Value] - deriving (Show, Eq) - -encodeJSONObject :: V.Vector (Text, BL.ByteString) -> BB.Builder -encodeJSONObject xs - | V.null xs = BB.char7 '{' <> BB.char7 '}' - | otherwise = BB.char7 '{' <> builder' (V.unsafeHead xs) <> - V.foldr go (BB.char7 '}') (V.unsafeTail xs) - where - go v b = BB.char7 ',' <> builder' v <> b - -- builds "key":value from (key,value) - builder' (t, v) = - BB.char7 '"' <> TE.encodeUtf8Builder t <> BB.string7 "\":" - <> BB.lazyByteString v - -encodeGQResp :: GQResp -> BL.ByteString -encodeGQResp gqResp = - buildBS $ case gqResp of - GQSuccess r -> V.singleton ("data", r) - GQPreExecError e -> V.singleton ("errors", J.encode e) - GQExecError e -> V.fromList [("data", "null"), ("errors", J.encode e)] - where - buildBS = BB.toLazyByteString . encodeJSONObject - -mkJSONObj :: V.Vector (Text, BL.ByteString) -> BL.ByteString -mkJSONObj = BB.toLazyByteString . encodeJSONObject diff --git a/server/src-lib/Hasura/GraphQL/Resolve.hs b/server/src-lib/Hasura/GraphQL/Resolve.hs new file mode 100644 index 0000000000000..f71b08fe56c57 --- /dev/null +++ b/server/src-lib/Hasura/GraphQL/Resolve.hs @@ -0,0 +1,89 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} + +module Hasura.GraphQL.Resolve + ( resolveSelSet + ) where + +import Hasura.Prelude + +import qualified Data.Aeson as J +import qualified Data.ByteString.Lazy as BL +import qualified Data.HashMap.Strict as Map +import qualified Database.PG.Query as Q +import qualified Language.GraphQL.Draft.Syntax as G + +import Hasura.GraphQL.Resolve.Context +import Hasura.GraphQL.Resolve.Introspect +import Hasura.GraphQL.Schema +import Hasura.GraphQL.Transport.HTTP.Protocol +import Hasura.GraphQL.Validate.Field +import Hasura.RQL.Types +import Hasura.SQL.Types + +import qualified Hasura.GraphQL.Resolve.Mutation as RM +import qualified Hasura.GraphQL.Resolve.Select as RS + +-- {-# SCC buildTx #-} +buildTx :: UserInfo -> GCtx -> Field -> Q.TxE QErr BL.ByteString +buildTx userInfo gCtx fld = do + opCxt <- getOpCtx $ _fName fld + join $ fmap fst $ runConvert (fldMap, orderByCtx) $ case opCxt of + + OCSelect tn permFilter hdrs -> + validateHdrs hdrs >> RS.convertSelect tn permFilter fld + -- RS.convertSelect tn permFilter fld + OCInsert tn vn cols hdrs -> + validateHdrs hdrs >> RM.convertInsert (tn, vn) cols fld + -- RM.convertInsert (tn, vn) cols fld + OCUpdate tn permFilter hdrs -> + validateHdrs hdrs >> RM.convertUpdate tn permFilter fld + -- RM.convertUpdate tn permFilter fld + OCDelete tn permFilter hdrs -> + validateHdrs hdrs >> RM.convertDelete tn permFilter fld + -- RM.convertDelete tn permFilter fld + where + opCtxMap = _gOpCtxMap gCtx + fldMap = _gFields gCtx + orderByCtx = _gOrdByEnums gCtx + + getOpCtx f = + onNothing (Map.lookup f opCtxMap) $ throw500 $ + "lookup failed: opctx: " <> showName f + + validateHdrs hdrs = do + let receivedHdrs = userHeaders userInfo + forM_ hdrs $ \hdr -> + unless (Map.member hdr receivedHdrs) $ + throw400 NotFound $ hdr <<> " header is expected but not found" + +-- {-# SCC resolveFld #-} +resolveFld + :: UserInfo -> GCtx + -> G.OperationType + -> Field + -> Q.TxE QErr BL.ByteString +resolveFld userInfo gCtx opTy fld = + case _fName fld of + "__type" -> J.encode <$> runReaderT (typeR fld) gCtx + "__schema" -> J.encode <$> runReaderT (schemaR fld) gCtx + "__typename" -> return $ J.encode $ mkRootTypeName opTy + _ -> buildTx userInfo gCtx fld + where + mkRootTypeName :: G.OperationType -> Text + mkRootTypeName = \case + G.OperationTypeQuery -> "query_root" + G.OperationTypeMutation -> "mutation_root" + G.OperationTypeSubscription -> "subscription_root" + +resolveSelSet + :: UserInfo -> GCtx + -> G.OperationType + -> SelSet + -> Q.TxE QErr BL.ByteString +resolveSelSet userInfo gCtx opTy fields = + fmap mkJSONObj $ forM (toList fields) $ \fld -> do + fldResp <- resolveFld userInfo gCtx opTy fld + return (G.unName $ G.unAlias $ _fAlias fld, fldResp) diff --git a/server/src-lib/Hasura/GraphQL/Resolve/Introspect.hs b/server/src-lib/Hasura/GraphQL/Resolve/Introspect.hs index c2f9feefa52a0..1cae7ef246797 100644 --- a/server/src-lib/Hasura/GraphQL/Resolve/Introspect.hs +++ b/server/src-lib/Hasura/GraphQL/Resolve/Introspect.hs @@ -280,6 +280,7 @@ schemaR fld = sortBy (comparing getNamedTy) $ Map.elems tyMap "queryType" -> J.toJSON <$> namedTypeR (G.NamedType "query_root") subFld "mutationType" -> typeR' "mutation_root" subFld + "subscriptionType" -> typeR' "subscription_root" subFld "directives" -> J.toJSON <$> mapM (directiveR subFld) (sortBy (comparing _diName) defaultDirectives) _ -> return J.Null diff --git a/server/src-lib/Hasura/GraphQL/Resolve/LiveQuery.hs b/server/src-lib/Hasura/GraphQL/Resolve/LiveQuery.hs new file mode 100644 index 0000000000000..a0c9d17cea42a --- /dev/null +++ b/server/src-lib/Hasura/GraphQL/Resolve/LiveQuery.hs @@ -0,0 +1,170 @@ +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE FlexibleContexts #-} + +module Hasura.GraphQL.Resolve.LiveQuery + ( LiveQuery(..) + , LiveQueryMap + , newLiveQueryMap + , addLiveQuery + , removeLiveQuery + ) where + +import qualified Control.Concurrent.Async as A +import qualified Control.Concurrent.STM as STM +import qualified Data.ByteString.Lazy as BL +import qualified ListT +import qualified STMContainers.Map as STMMap + +import Control.Concurrent (threadDelay) + +import Hasura.GraphQL.Resolve.Context (RespTx) +import Hasura.GraphQL.Transport.HTTP.Protocol +import Hasura.Prelude +import Hasura.RQL.Types + +data LiveQuery + = LiveQuery + { _lqUser :: !UserInfo + , _lqRequest :: !GraphQLRequest + } deriving (Show, Eq, Generic) + +instance Hashable LiveQuery + +type OnChange k = GQResp -> IO () + +data LQHandler k + = LQHandler + -- the tx to be executed + { _lqhRespTx :: !RespTx + -- previous result + , _lqhPrevRes :: !(STM.TVar (Maybe GQResp)) + -- the actions that have been run previously + -- we run these if the response changes + , _lqhCurOps :: !(STMMap.Map k (OnChange k)) + -- we run these operations regardless + -- and then merge them with current operations + , _lqhNewOps :: !(STMMap.Map k (OnChange k)) + } + +type ThreadTM = STM.TMVar (A.Async ()) +type LiveQueryMap k = STMMap.Map LiveQuery (LQHandler k, ThreadTM) + +newLiveQueryMap :: STM.STM (LiveQueryMap k) +newLiveQueryMap = STMMap.new + +type TxRunner = RespTx -> IO (Either QErr BL.ByteString) + +removeLiveQuery + :: (Eq k, Hashable k) + => LiveQueryMap k + -- the query and the associated operation + -> LiveQuery + -> k + -> IO () +removeLiveQuery lqMap liveQ k = do + + -- clean the handler's state + threadRefM <- STM.atomically $ do + lqHandlerM <- STMMap.lookup liveQ lqMap + maybe (return Nothing) cleanLQHandler lqHandlerM + + -- cancel the polling thread + onJust threadRefM A.cancel + + where + cleanLQHandler (handler, threadRef) = do + let curOps = _lqhCurOps handler + newOps = _lqhNewOps handler + STMMap.delete k curOps + STMMap.delete k newOps + cancelPollThread <- (&&) + <$> STMMap.null curOps + <*> STMMap.null newOps + -- if this happens to be the last operation, take the + -- ref for the polling thread to cancel it + if cancelPollThread then do + STMMap.delete liveQ lqMap + Just <$> STM.takeTMVar threadRef + else return Nothing + +onJust :: (Monad m) => Maybe a -> (a -> m ()) -> m () +onJust m action = maybe (return ()) action m + +addLiveQuery + :: (Eq k, Hashable k) + => TxRunner + -> LiveQueryMap k + -- the query + -> LiveQuery + -- the transaction associated with this query + -> RespTx + -- a unique operation id + -> k + -- the action to be executed when result changes + -> OnChange k + -> IO () +addLiveQuery txRunner lqMap liveQ respTx k onResultAction= do + + -- a handler is returned only when it is newly created + handlerM <- STM.atomically $ do + lqHandlerM <- STMMap.lookup liveQ lqMap + maybe newHandler addToExistingHandler lqHandlerM + + -- we can then attach a polling thread if it is new + -- the livequery can only be cancelled after putTMVar + onJust handlerM $ \(handler, pollerThreadTM) -> do + threadRef <- A.async $ forever $ do + pollQuery txRunner handler + threadDelay $ 1 * 1000 * 1000 + STM.atomically $ STM.putTMVar pollerThreadTM threadRef + + where + + addToExistingHandler (handler, _) = do + STMMap.insert onResultAction k $ _lqhNewOps handler + return Nothing + + newHandler = do + handler <- LQHandler + <$> return respTx + <*> STM.newTVar Nothing + <*> STMMap.new + <*> STMMap.new + STMMap.insert onResultAction k $ _lqhNewOps handler + asyncRefTM <- STM.newEmptyTMVar + STMMap.insert (handler, asyncRefTM) liveQ lqMap + return $ Just (handler, asyncRefTM) + +pollQuery + :: (Eq k, Hashable k) + => TxRunner + -> LQHandler k + -> IO () +pollQuery runTx (LQHandler respTx respTV curOpsTV newOpsTV) = do + + res <- runTx respTx + + let resp = case res of + Left e -> GQExecError [encodeGQErr False e] + Right bs -> GQSuccess bs + + -- extract the current and new operations + (curOps, newOps) <- STM.atomically $ do + curOpsL <- ListT.toList $ STMMap.stream curOpsTV + newOpsL <- ListT.toList $ STMMap.stream newOpsTV + forM_ newOpsL $ \(k, action) -> STMMap.insert action k curOpsTV + STMMap.deleteAll newOpsTV + return (curOpsL, newOpsL) + + runOperations resp newOps + + -- write to the current websockets if needed + prevRespM <- STM.readTVarIO respTV + when (isExecError resp || Just resp /= prevRespM) $ do + runOperations resp curOps + STM.atomically $ STM.writeTVar respTV $ Just resp + + where + runOperation resp action = action resp + runOperations resp = + void . A.mapConcurrently (runOperation resp . snd) diff --git a/server/src-lib/Hasura/GraphQL/Schema.hs b/server/src-lib/Hasura/GraphQL/Schema.hs index 993dd17f8aa29..a50c2e4c1feec 100644 --- a/server/src-lib/Hasura/GraphQL/Schema.hs +++ b/server/src-lib/Hasura/GraphQL/Schema.hs @@ -39,7 +39,6 @@ import qualified Hasura.SQL.DML as S defaultTypes :: [TypeInfo] defaultTypes = $(fromSchemaDocQ defaultSchema) --- defaultTypes = undefined type OpCtxMap = Map.HashMap G.Name OpCtx @@ -61,6 +60,7 @@ data GCtx , _gOrdByEnums :: !OrdByResolveCtx , _gQueryRoot :: !ObjTyInfo , _gMutRoot :: !(Maybe ObjTyInfo) + , _gSubRoot :: !(Maybe ObjTyInfo) , _gOpCtxMap :: !OpCtxMap } deriving (Show, Eq) @@ -818,9 +818,14 @@ mkGCtx (TyAgg tyInfos fldInfos ordByEnums) (RootFlds flds) = scalarTys = map (TIScalar . mkScalarTyInfo) colTys compTys = map (TIInpObj . mkCompExpInp) colTys allTys = Map.union tyInfos $ mkTyInfoMap $ - catMaybes [Just $ TIObj queryRoot, TIObj <$> mutRootM] <> + catMaybes [ Just $ TIObj queryRoot + , TIObj <$> mutRootM + , TIObj <$> subRootM + ] <> scalarTys <> compTys <> defaultTypes - in GCtx allTys fldInfos ordByEnums queryRoot mutRootM $ Map.map fst flds + -- for now subscription root is query root + in GCtx allTys fldInfos ordByEnums queryRoot mutRootM (Just queryRoot) $ + Map.map fst flds where mkMutRoot = @@ -829,6 +834,12 @@ mkGCtx (TyAgg tyInfos fldInfos ordByEnums) (RootFlds flds) = mutRootM = bool (Just $ mkMutRoot mFlds) Nothing $ null mFlds + mkSubRoot = + mkObjTyInfo (Just "subscription root") (G.NamedType "subscription_root") . + mapFromL _fiName + + subRootM = bool (Just $ mkSubRoot qFlds) Nothing $ null qFlds + (qFlds, mFlds) = partitionEithers $ map snd $ Map.elems flds schemaFld = ObjFldInfo Nothing "__schema" Map.empty $ G.toGT $ diff --git a/server/src-lib/Hasura/GraphQL/Transport/HTTP.hs b/server/src-lib/Hasura/GraphQL/Transport/HTTP.hs new file mode 100644 index 0000000000000..0c8bd6055fdb5 --- /dev/null +++ b/server/src-lib/Hasura/GraphQL/Transport/HTTP.hs @@ -0,0 +1,39 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} + +module Hasura.GraphQL.Transport.HTTP + ( runGQ + ) where + +import Hasura.Prelude + +import qualified Data.ByteString.Lazy as BL +import qualified Database.PG.Query as Q +import qualified Language.GraphQL.Draft.Syntax as G + +import Hasura.GraphQL.Schema +import Hasura.GraphQL.Transport.HTTP.Protocol +import Hasura.RQL.Types + +import qualified Hasura.GraphQL.Resolve as R +import qualified Hasura.GraphQL.Validate as VQ +import qualified Hasura.Server.Query as RQ + +runGQ + :: (MonadIO m, MonadError QErr m) + => Q.PGPool -> Q.TxIsolation + -> UserInfo -> GCtxMap + -> GraphQLRequest + -> m BL.ByteString +runGQ pool isoL userInfo gCtxMap req = do + (opTy, fields) <- runReaderT (VQ.validateGQ req) gCtx + when (opTy == G.OperationTypeSubscription) $ throw400 UnexpectedPayload + "subscriptions are not supported over HTTP, use websockets instead" + resp <- runTx $ R.resolveSelSet userInfo gCtx opTy fields + return $ encodeGQResp $ GQSuccess resp + where + gCtx = getGCtx (userRole userInfo) gCtxMap + runTx tx = + Q.runTx pool (isoL, Nothing) $ + RQ.setHeadersTx userInfo >> tx diff --git a/server/src-lib/Hasura/GraphQL/Transport/HTTP/Protocol.hs b/server/src-lib/Hasura/GraphQL/Transport/HTTP/Protocol.hs new file mode 100644 index 0000000000000..c7df6a2dc8820 --- /dev/null +++ b/server/src-lib/Hasura/GraphQL/Transport/HTTP/Protocol.hs @@ -0,0 +1,107 @@ +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} + +module Hasura.GraphQL.Transport.HTTP.Protocol + ( GraphQLRequest(..) + , GraphQLQuery(..) + , OperationName(..) + , VariableValues + , encodeGQErr + , encodeJSONObject + , encodeGQResp + , mkJSONObj + , GQResp(..) + , isExecError + ) where + +import Hasura.Prelude + +import qualified Data.Aeson as J +import qualified Data.Aeson.Casing as J +import qualified Data.Aeson.TH as J +import qualified Data.ByteString.Builder as BB +import qualified Data.ByteString.Lazy as BL +import qualified Data.HashMap.Strict as Map +import qualified Data.Text.Encoding as TE +import qualified Data.Vector as V +import qualified Language.GraphQL.Draft.Parser as G +import qualified Language.GraphQL.Draft.Syntax as G + +import Hasura.RQL.Types + +newtype GraphQLQuery + = GraphQLQuery { unGraphQLQuery :: [G.ExecutableDefinition] } + deriving (Show, Eq, Hashable) + +instance J.FromJSON GraphQLQuery where + parseJSON = J.withText "GraphQLQuery" $ \t -> + case G.parseExecutableDoc t of + Left _ -> fail "parsing the graphql query failed" + Right q -> return $ GraphQLQuery $ G.getExecutableDefinitions q + +instance J.ToJSON GraphQLQuery where + -- TODO, add pretty printer in graphql-parser + toJSON _ = J.String "toJSON not implemented for GraphQLQuery" + +newtype OperationName + = OperationName { _unOperationName :: G.Name } + deriving (Show, Eq, Hashable, J.ToJSON) + +instance J.FromJSON OperationName where + parseJSON v = OperationName . G.Name <$> J.parseJSON v + +type VariableValues = Map.HashMap G.Variable J.Value + +data GraphQLRequest + = GraphQLRequest + { _grOperationName :: !(Maybe OperationName) + , _grQuery :: !GraphQLQuery + , _grVariables :: !(Maybe VariableValues) + } deriving (Show, Eq, Generic) + +$(J.deriveJSON (J.aesonDrop 3 J.camelCase){J.omitNothingFields=True} + ''GraphQLRequest + ) + +instance Hashable GraphQLRequest + +encodeGQErr :: Bool -> QErr -> J.Value +encodeGQErr includeInternal qErr = + J.object [ "errors" J..= [encodeQErr includeInternal qErr]] + +data GQResp + = GQSuccess BL.ByteString + | GQPreExecError [J.Value] + | GQExecError [J.Value] + deriving (Show, Eq) + +isExecError :: GQResp -> Bool +isExecError = \case + GQExecError _ -> True + _ -> False + +encodeJSONObject :: V.Vector (Text, BL.ByteString) -> BB.Builder +encodeJSONObject xs + | V.null xs = BB.char7 '{' <> BB.char7 '}' + | otherwise = BB.char7 '{' <> builder' (V.unsafeHead xs) <> + V.foldr go (BB.char7 '}') (V.unsafeTail xs) + where + go v b = BB.char7 ',' <> builder' v <> b + -- builds "key":value from (key,value) + builder' (t, v) = + BB.char7 '"' <> TE.encodeUtf8Builder t <> BB.string7 "\":" + <> BB.lazyByteString v + +encodeGQResp :: GQResp -> BL.ByteString +encodeGQResp gqResp = + mkJSONObj $ case gqResp of + GQSuccess r -> [("data", r)] + GQPreExecError e -> [("errors", J.encode e)] + GQExecError e -> [("data", "null"), ("errors", J.encode e)] + +mkJSONObj :: [(Text, BL.ByteString)] -> BL.ByteString +mkJSONObj = BB.toLazyByteString . encodeJSONObject . V.fromList diff --git a/server/src-lib/Hasura/GraphQL/Transport/WebSocket.hs b/server/src-lib/Hasura/GraphQL/Transport/WebSocket.hs new file mode 100644 index 0000000000000..492eb60023880 --- /dev/null +++ b/server/src-lib/Hasura/GraphQL/Transport/WebSocket.hs @@ -0,0 +1,307 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TemplateHaskell #-} + +module Hasura.GraphQL.Transport.WebSocket + ( createWSServerApp + , createWSServerEnv + ) where + +import qualified Control.Concurrent.Async as A +import qualified Control.Concurrent.STM as STM +import qualified Data.Aeson as J +import qualified Data.Aeson.Casing as J +import qualified Data.Aeson.TH as J +import qualified Data.ByteString.Lazy as BL +import qualified Data.CaseInsensitive as CI +import qualified Data.HashMap.Strict as Map +import qualified Data.TByteString as TBS +import qualified Data.Text as T +import qualified Data.Text.Encoding as TE +import qualified Language.GraphQL.Draft.Syntax as G +import qualified ListT +import qualified Network.HTTP.Client as H +import qualified Network.HTTP.Types.Status as H +import qualified Network.WebSockets as WS +import qualified STMContainers.Map as STMMap + +import Control.Concurrent (threadDelay) +import qualified Data.IORef as IORef + +import Hasura.GraphQL.Resolve (resolveSelSet) +import Hasura.GraphQL.Resolve.Context (RespTx) +import qualified Hasura.GraphQL.Resolve.LiveQuery as LQ +import Hasura.GraphQL.Schema (GCtxMap, getGCtx) +import Hasura.GraphQL.Transport.HTTP.Protocol +import Hasura.GraphQL.Transport.WebSocket.Protocol +import qualified Hasura.GraphQL.Transport.WebSocket.Server as WS +import Hasura.GraphQL.Validate (validateGQ) +import qualified Hasura.Logging as L +import Hasura.Prelude +import Hasura.RQL.Types +import Hasura.Server.Auth (AuthMode, + getUserInfo) + +-- uniquely identifies an operation +type GOperationId = (WS.WSId, OperationId) + +type TxRunner = RespTx -> IO (Either QErr BL.ByteString) + +type OperationMap + = STMMap.Map OperationId LQ.LiveQuery + +data WSConnData + = WSConnData + -- the role and headers are set only on connection_init message + { _wscUser :: !(IORef.IORef (Maybe UserInfo)) + -- we only care about subscriptions, + -- the other operations (query/mutations) + -- are not tracked here + , _wscOpMap :: !OperationMap + } + +type LiveQueryMap = LQ.LiveQueryMap GOperationId +type WSServer = WS.WSServer WSConnData + +type WSConn = WS.WSConn WSConnData +sendMsg :: (MonadIO m) => WSConn -> ServerMsg -> m () +sendMsg wsConn = + liftIO . WS.sendMsg wsConn . encodeServerMsg + +data SubsDetail + = SDStarted + | SDStopped + deriving (Show, Eq) +$(J.deriveToJSON + J.defaultOptions { J.constructorTagModifier = J.snakeCase . drop 2 + , J.sumEncoding = J.TaggedObject "type" "detail" + } + ''SubsDetail) + +data OpDetail + = ODCompleted + | ODError !QErr + deriving (Show, Eq) +$(J.deriveToJSON + J.defaultOptions { J.constructorTagModifier = J.snakeCase . drop 2 + , J.sumEncoding = J.TaggedObject "type" "detail" + } + ''OpDetail) + +data WSEvent + = EAccepted + | ERejected !QErr + | EProtocolError !TBS.TByteString !ConnErrMsg + | EOperation !OperationId !OpDetail + | ESubscription !OperationId !SubsDetail + | EClosed + deriving (Show, Eq) +$(J.deriveToJSON + J.defaultOptions { J.constructorTagModifier = J.snakeCase . drop 1 + , J.sumEncoding = J.TaggedObject "type" "detail" + } + ''WSEvent) + +data WSLog + = WSLog + { _wslWebsocketId :: !WS.WSId + , _wslEvent :: !WSEvent + } deriving (Show, Eq) +$(J.deriveToJSON (J.aesonDrop 4 J.snakeCase) ''WSLog) + +instance L.ToEngineLog WSLog where + toEngineLog wsLog = + (L.LevelInfo, "ws-handler", J.toJSON wsLog) + +data WSServerEnv + = WSServerEnv + { _wseLogger :: !L.Logger + , _wseServer :: !WSServer + , _wseRunTx :: !TxRunner + , _wseLiveQMap :: !LiveQueryMap + , _wseGCtxMap :: !(IORef.IORef (SchemaCache, GCtxMap)) + , _wseHManager :: !H.Manager + } + +onConn :: L.Logger -> WS.OnConnH WSConnData +onConn logger wsId requestHead = do + res <- runExceptT checkPath + either reject accept res + where + + keepAliveAction wsConn = forever $ do + sendMsg wsConn SMConnKeepAlive + threadDelay $ 5 * 1000 * 1000 + + accept _ = do + logger $ WSLog wsId EAccepted + connData <- WSConnData <$> IORef.newIORef Nothing <*> STMMap.newIO + let acceptRequest = WS.defaultAcceptRequest + { WS.acceptSubprotocol = Just "graphql-ws"} + return $ Right (connData, acceptRequest, Just keepAliveAction) + + reject qErr = do + logger $ WSLog wsId $ ERejected qErr + return $ Left $ WS.RejectRequest + (H.statusCode $ qeStatus qErr) + (H.statusMessage $ qeStatus qErr) [] + (BL.toStrict $ J.encode $ encodeQErr False qErr) + + checkPath = + when (WS.requestPath requestHead /= "/v1alpha1/graphql") $ + throw404 "only /v1alpha1/graphql is supported on websockets" + +onStart :: WSServerEnv -> WSConn -> StartMsg -> IO () +onStart serverEnv wsConn msg@(StartMsg opId q) = catchAndSend $ do + + opM <- liftIO $ STM.atomically $ STMMap.lookup opId opMap + + when (isJust opM) $ withExceptT preExecErr $ loggingQErr $ + throw400 UnexpectedPayload $ + "an operation already exists with this id: " <> unOperationId opId + + userInfoM <- liftIO $ IORef.readIORef userInfoR + userInfo <- case userInfoM of + Just userInfo -> return userInfo + Nothing -> do + let err = "start received before the connection is initialised" + liftIO $ logger $ WSLog wsId $ + -- TODO: we are encoding the start msg back into a bytestring + -- should we be throwing protocol error here? + EProtocolError (TBS.fromLBS $ J.encode msg) err + throwError $ SMConnErr err + + -- validate and build tx + gCtxMap <- fmap snd $ liftIO $ IORef.readIORef gCtxMapRef + let gCtx = getGCtx (userRole userInfo) gCtxMap + (opTy, fields) <- withExceptT preExecErr $ loggingQErr $ + runReaderT (validateGQ q) gCtx + let qTx = resolveSelSet userInfo gCtx opTy fields + + case opTy of + G.OperationTypeSubscription -> do + let lq = LQ.LiveQuery userInfo q + liftIO $ STM.atomically $ STMMap.insert lq opId opMap + liftIO $ LQ.addLiveQuery runTx lqMap lq + qTx (wsId, opId) liveQOnChange + liftIO $ logger $ WSLog wsId $ ESubscription opId SDStarted + + _ -> withExceptT postExecErr $ loggingQErr $ do + resp <- ExceptT $ runTx qTx + sendMsg wsConn $ SMData $ DataMsg opId $ GQSuccess resp + sendMsg wsConn $ SMComplete $ CompletionMsg opId + liftIO $ logger $ WSLog wsId $ EOperation opId ODCompleted + + where + (WSServerEnv logger _ runTx lqMap gCtxMapRef _) = serverEnv + wsId = WS.getWSId wsConn + (WSConnData userInfoR opMap) = WS.getData wsConn + + -- on change, send message on the websocket + liveQOnChange resp = WS.sendMsg wsConn $ encodeServerMsg $ SMData $ + DataMsg opId resp + + loggingQErr m = catchError m $ \qErr -> do + liftIO $ logger $ WSLog wsId $ EOperation opId $ ODError qErr + throwError qErr + + preExecErr qErr = SMErr $ ErrorMsg opId $ encodeQErr False qErr + postExecErr qErr = SMData $ DataMsg opId $ GQExecError + [encodeQErr False qErr] + + catchAndSend :: ExceptT ServerMsg IO () -> IO () + catchAndSend m = do + res <- runExceptT m + either (sendMsg wsConn) return res + +onMessage + :: AuthMode + -> WSServerEnv + -> WSConn -> BL.ByteString -> IO () +onMessage authMode serverEnv wsConn msgRaw = + case J.eitherDecode msgRaw of + Left e -> do + let err = ConnErrMsg $ "parsing ClientMessage failed: " <> T.pack e + liftIO $ logger $ WSLog (WS.getWSId wsConn) $ + EProtocolError (TBS.fromLBS msgRaw) err + sendMsg wsConn $ SMConnErr err + + Right msg -> case msg of + CMConnInit params -> onConnInit (_wseHManager serverEnv) + wsConn authMode params + CMStart startMsg -> onStart serverEnv wsConn startMsg + CMStop stopMsg -> onStop serverEnv wsConn stopMsg + CMConnTerm -> WS.closeConn wsConn "GQL_CONNECTION_TERMINATE received" + where + logger = _wseLogger serverEnv + +onStop :: WSServerEnv -> WSConn -> StopMsg -> IO () +onStop serverEnv wsConn (StopMsg opId) = do + -- probably wrap the whole thing in a single tx? + opM <- liftIO $ STM.atomically $ STMMap.lookup opId opMap + case opM of + Just liveQ -> do + liftIO $ logger $ WSLog wsId $ ESubscription opId SDStopped + LQ.removeLiveQuery lqMap liveQ (wsId, opId) + Nothing -> return () + STM.atomically $ STMMap.delete opId opMap + where + logger = _wseLogger serverEnv + lqMap = _wseLiveQMap serverEnv + wsId = WS.getWSId wsConn + opMap = _wscOpMap $ WS.getData wsConn + +onConnInit + :: (MonadIO m) + => H.Manager -> WSConn -> AuthMode -> ConnParams -> m () +onConnInit manager wsConn authMode connParams = do + res <- runExceptT $ getUserInfo manager headers authMode + case res of + Left e -> + liftIO $ WS.closeConn wsConn $ + BL.fromStrict $ TE.encodeUtf8 $ qeError e + Right userInfo -> do + liftIO $ IORef.writeIORef (_wscUser $ WS.getData wsConn) $ Just userInfo + sendMsg wsConn SMConnAck + -- TODO: send it periodically? Why doesn't apollo's protocol use + -- ping/pong frames of websocket spec? + sendMsg wsConn SMConnKeepAlive + where + headers = [ (CI.mk $ TE.encodeUtf8 h, TE.encodeUtf8 v) + | (h, v) <- maybe [] Map.toList $ _cpHeaders connParams + ] + +onClose + :: L.Logger + -> LiveQueryMap + -> WS.ConnectionException + -> WSConn + -> IO () +onClose logger lqMap _ wsConn = do + logger $ WSLog wsId EClosed + operations <- STM.atomically $ ListT.toList $ STMMap.stream opMap + void $ A.forConcurrently operations $ \(opId, liveQ) -> + LQ.removeLiveQuery lqMap liveQ (wsId, opId) + where + wsId = WS.getWSId wsConn + opMap = _wscOpMap $ WS.getData wsConn + +createWSServerEnv + :: L.Logger + -> H.Manager -> IORef.IORef (SchemaCache, GCtxMap) + -> TxRunner -> IO WSServerEnv +createWSServerEnv logger httpManager gCtxMapRef runTx = do + (wsServer, lqMap) <- + STM.atomically $ (,) <$> WS.createWSServer logger <*> LQ.newLiveQueryMap + return $ WSServerEnv logger wsServer runTx lqMap gCtxMapRef httpManager + +createWSServerApp :: AuthMode -> WSServerEnv -> WS.ServerApp +createWSServerApp authMode serverEnv = + WS.createServerApp (_wseServer serverEnv) handlers + where + handlers = + WS.WSHandlers + (onConn $ _wseLogger serverEnv) + (onMessage authMode serverEnv) + (onClose (_wseLogger serverEnv) $ _wseLiveQMap serverEnv) diff --git a/server/src-lib/Hasura/GraphQL/Transport/WebSocket/Protocol.hs b/server/src-lib/Hasura/GraphQL/Transport/WebSocket/Protocol.hs new file mode 100644 index 0000000000000..0274d65162e7e --- /dev/null +++ b/server/src-lib/Hasura/GraphQL/Transport/WebSocket/Protocol.hs @@ -0,0 +1,154 @@ +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} + +module Hasura.GraphQL.Transport.WebSocket.Protocol + ( OperationId(..) + , ConnParams(..) + , StartMsg(..) + , StopMsg(..) + , ClientMsg(..) + , ServerMsg(..) + , encodeServerMsg + , DataMsg(..) + , ErrorMsg(..) + , ConnErrMsg(..) + , CompletionMsg(..) + ) where + +import qualified Data.Aeson as J +import qualified Data.Aeson.Casing as J +import qualified Data.Aeson.TH as J +import qualified Data.ByteString.Lazy as BL +import qualified Data.HashMap.Strict as Map + +import Hasura.GraphQL.Transport.HTTP.Protocol +import Hasura.Prelude + +newtype OperationId + = OperationId { unOperationId :: Text } + deriving (Show, Eq, J.ToJSON, J.FromJSON, Hashable) + +data StartMsg + = StartMsg + { _smId :: !OperationId + , _smPayload :: !GraphQLRequest + } deriving (Show, Eq) +$(J.deriveJSON (J.aesonDrop 3 J.snakeCase) ''StartMsg) + +data StopMsg + = StopMsg + { _stId :: OperationId + } deriving (Show, Eq) +$(J.deriveJSON (J.aesonDrop 3 J.snakeCase) ''StopMsg) + +data ClientMsg + = CMConnInit !ConnParams + | CMStart !StartMsg + | CMStop !StopMsg + | CMConnTerm + deriving (Show, Eq) + +data ConnParams + = ConnParams + { _cpHeaders :: Maybe (Map.HashMap Text Text) + } deriving (Show, Eq) +$(J.deriveJSON (J.aesonDrop 3 J.snakeCase) ''ConnParams) + +instance J.FromJSON ClientMsg where + parseJSON = J.withObject "ClientMessage" $ \obj -> do + t <- obj J..: "type" + case t of + "connection_init" -> CMConnInit <$> obj J..: "payload" + "start" -> CMStart <$> J.parseJSON (J.Object obj) + "stop" -> CMStop <$> J.parseJSON (J.Object obj) + "connection_terminate" -> return CMConnTerm + _ -> fail $ "unexpected type for ClientMessage: " <> t + +-- server to client messages + +data DataMsg + = DataMsg + { _dmId :: !OperationId + , _dmPayload :: !GQResp + } deriving (Show, Eq) + +data ErrorMsg + = ErrorMsg + { _emId :: !OperationId + , _emPayload :: !J.Value + } deriving (Show, Eq) + +newtype CompletionMsg + = CompletionMsg { unCompletionMsg :: OperationId } + deriving (Show, Eq) + +newtype ConnErrMsg + = ConnErrMsg { unConnErrMsg :: Text } + deriving (Show, Eq, J.ToJSON, J.FromJSON, IsString) + +data ServerMsg + = SMConnAck + | SMConnKeepAlive + | SMConnErr !ConnErrMsg + | SMData !DataMsg + | SMErr !ErrorMsg + | SMComplete !CompletionMsg + deriving (Show, Eq) + +data ServerMsgType + = SMT_GQL_CONNECTION_ACK + | SMT_GQL_CONNECTION_KEEP_ALIVE + | SMT_GQL_CONNECTION_ERROR + | SMT_GQL_DATA + | SMT_GQL_ERROR + | SMT_GQL_COMPLETE + deriving (Eq) + +instance Show ServerMsgType where + show = \case + SMT_GQL_CONNECTION_ACK -> "connection_ack" + SMT_GQL_CONNECTION_KEEP_ALIVE -> "ka" + SMT_GQL_CONNECTION_ERROR -> "connection_error" + SMT_GQL_DATA -> "data" + SMT_GQL_ERROR -> "error" + SMT_GQL_COMPLETE -> "complete" + +instance J.ToJSON ServerMsgType where + toJSON = J.toJSON . show + +encodeServerMsg :: ServerMsg -> BL.ByteString +encodeServerMsg msg = + mkJSONObj $ case msg of + + SMConnAck -> + [encTy SMT_GQL_CONNECTION_ACK] + + SMConnKeepAlive -> + [encTy SMT_GQL_CONNECTION_KEEP_ALIVE] + + SMConnErr connErr -> + [ encTy SMT_GQL_CONNECTION_ERROR + , ("payload", J.encode connErr) + ] + + SMData (DataMsg opId payload) -> + [ encTy SMT_GQL_DATA + , ("id", J.encode opId) + , ("payload", encodeGQResp payload) + ] + + SMErr (ErrorMsg opId payload) -> + [ encTy SMT_GQL_ERROR + , ("id", J.encode opId) + , ("payload", J.encode payload) + ] + + SMComplete compMsg -> + [ encTy SMT_GQL_COMPLETE + , ("id", J.encode $ unCompletionMsg compMsg) + ] + + where + encTy ty = ("type", J.encode ty) diff --git a/server/src-lib/Hasura/GraphQL/Transport/WebSocket/Server.hs b/server/src-lib/Hasura/GraphQL/Transport/WebSocket/Server.hs new file mode 100644 index 0000000000000..79f9a77903719 --- /dev/null +++ b/server/src-lib/Hasura/GraphQL/Transport/WebSocket/Server.hs @@ -0,0 +1,190 @@ +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TemplateHaskell #-} + +module Hasura.GraphQL.Transport.WebSocket.Server + ( WSId(..) + + , WSConn + , getData + , getWSId + , closeConn + , sendMsg + + , OnConnH + , OnCloseH + , OnMessageH + , WSHandlers(..) + + , WSServer + , createWSServer + , closeAll + , createServerApp + ) where + +import qualified Control.Concurrent.Async as A +import qualified Control.Concurrent.STM as STM +import qualified Data.Aeson as J +import qualified Data.Aeson.Casing as J +import qualified Data.Aeson.TH as J +import qualified Data.ByteString.Lazy as BL +import qualified Data.TByteString as TBS +import qualified Data.UUID as UUID +import qualified Data.UUID.V4 as UUID +import qualified ListT +import qualified Network.WebSockets as WS +import qualified STMContainers.Map as STMMap + +import Control.Exception (try) +import qualified Hasura.Logging as L +import Hasura.Prelude + +newtype WSId + = WSId { unWSId :: UUID.UUID } + deriving (Show, Eq, Hashable) + +instance J.ToJSON WSId where + toJSON (WSId uuid) = + J.toJSON $ UUID.toText uuid + +data WSEvent + = EConnectionRequest + | EAccepted + | ERejected + | EMessageReceived !TBS.TByteString + | EMessageSent !TBS.TByteString + | ECloseReceived + | ECloseSent !TBS.TByteString + | EClosed + deriving (Show, Eq) +$(J.deriveToJSON + J.defaultOptions { J.constructorTagModifier = J.snakeCase . drop 1 + , J.sumEncoding = J.TaggedObject "type" "detail" + } + ''WSEvent) + +data WSLog + = WSLog + { _wslWebsocketId :: !WSId + , _wslEvent :: !WSEvent + } deriving (Show, Eq) +$(J.deriveToJSON (J.aesonDrop 4 J.snakeCase) ''WSLog) + +instance L.ToEngineLog WSLog where + toEngineLog wsLog = + (L.LevelDebug, "ws-server", J.toJSON wsLog) + +data WSConn a + = WSConn + { _wcConnId :: !WSId + , _wcLogger :: !L.Logger + , _wcConnRaw :: !WS.Connection + , _wcSendQ :: !(STM.TQueue BL.ByteString) + , _wcExtraData :: !a + } + +getData :: WSConn a -> a +getData = _wcExtraData + +getWSId :: WSConn a -> WSId +getWSId = _wcConnId + +closeConn :: WSConn a -> BL.ByteString -> IO () +closeConn wsConn bs = do + _wcLogger wsConn $ WSLog (_wcConnId wsConn) $ ECloseSent $ TBS.fromLBS bs + WS.sendClose (_wcConnRaw wsConn) bs + +-- writes to a queue instead of the raw connection +-- so that sendMsg doesn't block +sendMsg :: WSConn a -> BL.ByteString -> IO () +sendMsg wsConn msg = + STM.atomically $ STM.writeTQueue (_wcSendQ wsConn) msg + +type ConnMap a = STMMap.Map WSId (WSConn a) + +data WSServer a + = WSServer + { _wssLogger :: L.Logger + , _wssConnMap :: ConnMap a + } + +createWSServer :: L.Logger -> STM.STM (WSServer a) +createWSServer logger = WSServer logger <$> STMMap.new + +closeAll :: WSServer a -> BL.ByteString -> IO () +closeAll (WSServer writeLog connMap) msg = do + writeLog $ L.debugT "closing all connections" + conns <- STM.atomically $ do + conns <- ListT.toList $ STMMap.stream connMap + STMMap.deleteAll connMap + return conns + void $ A.mapConcurrently (flip closeConn msg . snd) conns + +type AcceptWith a = (a, WS.AcceptRequest, Maybe (WSConn a -> IO ())) +type OnConnH a = WSId -> WS.RequestHead -> + IO (Either WS.RejectRequest (AcceptWith a)) +type OnCloseH a = WS.ConnectionException -> WSConn a -> IO () +type OnMessageH a = WSConn a -> BL.ByteString -> IO () + +data WSHandlers a + = WSHandlers + { _hOnConn :: OnConnH a + , _hOnMessage :: OnMessageH a + , _hOnClose :: OnCloseH a + } + +createServerApp + :: WSServer a + -- user provided handlers + -> WSHandlers a + -- aka WS.ServerApp + -> WS.PendingConnection -> IO () +createServerApp (WSServer writeLog connMap) wsHandlers pendingConn = do + wsId <- WSId <$> UUID.nextRandom + writeLog $ WSLog wsId EConnectionRequest + let reqHead = WS.pendingRequest pendingConn + onConnRes <- _hOnConn wsHandlers wsId reqHead + either (onReject wsId) (onAccept wsId) onConnRes + + where + onReject wsId rejectRequest = do + WS.rejectRequestWith pendingConn rejectRequest + writeLog $ WSLog wsId ERejected + + onAccept wsId (a, acceptWithParams, keepAliveM) = do + conn <- WS.acceptRequestWith pendingConn acceptWithParams + writeLog $ WSLog wsId EAccepted + + sendQ <- STM.newTQueueIO + let wsConn = WSConn wsId writeLog conn sendQ a + STM.atomically $ STMMap.insert wsConn wsId connMap + + rcvRef <- A.async $ forever $ do + msg <- WS.receiveData conn + writeLog $ WSLog wsId $ EMessageReceived $ TBS.fromLBS msg + _hOnMessage wsHandlers wsConn msg + + sendRef <- A.async $ forever $ do + msg <- STM.atomically $ STM.readTQueue sendQ + WS.sendTextData conn msg + writeLog $ WSLog wsId $ EMessageSent $ TBS.fromLBS msg + + keepAliveRefM <- forM keepAliveM $ \action -> A.async $ action wsConn + + -- terminates on WS.ConnectionException + let waitOnRefs = maybeToList keepAliveRefM <> [rcvRef, sendRef] + res <- try $ A.waitAnyCancel waitOnRefs + + case res of + Left e -> do + writeLog $ WSLog (_wcConnId wsConn) ECloseReceived + onConnClose e wsConn + -- this will never happen as both the threads never finish + Right _ -> return () + + onConnClose e wsConn = do + STM.atomically $ STMMap.delete (_wcConnId wsConn) connMap + _hOnClose wsHandlers e wsConn + writeLog $ WSLog (_wcConnId wsConn) EClosed diff --git a/server/src-lib/Hasura/GraphQL/Validate.hs b/server/src-lib/Hasura/GraphQL/Validate.hs new file mode 100644 index 0000000000000..d9bea05c44dd4 --- /dev/null +++ b/server/src-lib/Hasura/GraphQL/Validate.hs @@ -0,0 +1,141 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} + +module Hasura.GraphQL.Validate + ( validateGQ + , GraphQLRequest + ) where + +import Data.Has +import Hasura.Prelude + +import qualified Data.HashMap.Strict as Map +import qualified Language.GraphQL.Draft.Syntax as G + +import Hasura.GraphQL.Schema +import Hasura.GraphQL.Transport.HTTP.Protocol +import Hasura.GraphQL.Validate.Context +import Hasura.GraphQL.Validate.Field +import Hasura.GraphQL.Validate.InputValue +import Hasura.GraphQL.Validate.Types +import Hasura.RQL.Types + +getTypedOp + :: (MonadError QErr m) + => Maybe OperationName + -> [G.SelectionSet] + -> [G.TypedOperationDefinition] + -> m G.TypedOperationDefinition +getTypedOp opNameM selSets opDefs = + case (opNameM, selSets, opDefs) of + (Just opName, [], _) -> do + let n = _unOperationName opName + opDefM = find (\opDef -> G._todName opDef == Just n) opDefs + onNothing opDefM $ throwVE $ + "no such operation found in the document: " <> showName n + (Just _, _, _) -> + throwVE $ "operationName cannot be used when " <> + "an anonymous operation exists in the document" + (Nothing, [selSet], []) -> + return $ G.TypedOperationDefinition + G.OperationTypeQuery Nothing [] [] selSet + (Nothing, [], [opDef]) -> + return opDef + (Nothing, _, _) -> + throwVE $ "exactly one operation has to be present " <> + "in the document when operationName is not specified" + +-- For all the variables defined there will be a value in the final map +-- If no default, not in variables and nullable, then null value +getAnnVarVals + :: ( MonadReader r m, Has TypeMap r + , MonadError QErr m + ) + => [G.VariableDefinition] + -> VariableValues + -> m AnnVarVals +getAnnVarVals varDefsL inpVals = do + + varDefs <- onLeft (mkMapWith G._vdVariable varDefsL) $ \dups -> + throwVE $ "the following variables are defined more than once: " <> + showVars dups + + let unexpectedVars = filter (not . (`Map.member` varDefs)) $ Map.keys inpVals + + unless (null unexpectedVars) $ + throwVE $ "unexpected variables in variableValues: " <> + showVars unexpectedVars + + forM varDefs $ \(G.VariableDefinition var ty defM) -> do + let baseTy = getBaseTy ty + baseTyInfo <- getTyInfoVE baseTy + -- check that the variable is defined on input types + when (isObjTy baseTyInfo) $ throwVE $ objTyErrMsg baseTy + + let defM' = bool (defM <|> Just G.VCNull) defM $ G.isNotNull ty + annDefM <- withPathK "defaultValue" $ + mapM (validateInputValue constValueParser ty) defM' + let inpValM = Map.lookup var inpVals + annInpValM <- withPathK "variableValues" $ + mapM (validateInputValue jsonParser ty) inpValM + let varValM = annInpValM <|> annDefM + onNothing varValM $ throwVE $ "expecting a value for non-null type: " + <> G.showGT ty <> " in variableValues" + where + objTyErrMsg namedTy = + "variables can only be defined on input types" + <> "(enums, scalars, input objects), but " + <> showNamedTy namedTy <> " is an object type" + + showVars :: (Functor f, Foldable f) => f G.Variable -> Text + showVars = showNames . fmap G.unVariable + +validateFrag + :: (MonadError QErr m, MonadReader r m, Has TypeMap r) + => G.FragmentDefinition -> m FragDef +validateFrag (G.FragmentDefinition n onTy dirs selSet) = do + unless (null dirs) $ throwVE + "unexpected directives at fragment definition" + tyInfo <- getTyInfoVE onTy + objTyInfo <- onNothing (getObjTyM tyInfo) $ throwVE + "fragments can only be defined on object types" + return $ FragDef n objTyInfo selSet + +-- {-# SCC validateGQ #-} +validateGQ + :: (MonadError QErr m, MonadReader GCtx m) + => GraphQLRequest + -> m (G.OperationType, SelSet) +validateGQ (GraphQLRequest opNameM q varValsM) = do + + -- get the operation that needs to be evaluated + opDef <- getTypedOp opNameM selSets opDefs + + ctx <- ask + -- get the operation root + opRoot <- case G._todType opDef of + G.OperationTypeQuery -> return $ _gQueryRoot ctx + G.OperationTypeMutation -> + onNothing (_gMutRoot ctx) $ throwVE "no mutations exist" + G.OperationTypeSubscription -> + onNothing (_gSubRoot ctx) $ throwVE "no subscriptions exist" + + -- annotate the variables of this operation + annVarVals <- getAnnVarVals (G._todVariableDefinitions opDef) $ + fromMaybe Map.empty varValsM + + -- annotate the fragments + fragDefs <- onLeft (mkMapWith G._fdName fragDefsL) $ \dups -> + throwVE $ "the following fragments are defined more than once: " <> + showNames dups + annFragDefs <- mapM validateFrag fragDefs + + -- build a validation ctx + let valCtx = ValidationCtx (_gTypes ctx) annVarVals annFragDefs + + selSet <- flip runReaderT valCtx $ denormSelSet [] opRoot $ + G._todSelectionSet opDef + return (G._todType opDef, selSet) + where + (selSets, opDefs, fragDefsL) = G.partitionExDefs $ unGraphQLQuery q diff --git a/server/src-lib/Hasura/Logging.hs b/server/src-lib/Hasura/Logging.hs new file mode 100644 index 0000000000000..376db192b0c5e --- /dev/null +++ b/server/src-lib/Hasura/Logging.hs @@ -0,0 +1,146 @@ +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TemplateHaskell #-} + +module Hasura.Logging + ( LoggerSettings(..) + , defaultLoggerSettings + , EngineLog(..) + , EngineLogType + , ToEngineLog(..) + , debugT + , debugBS + , debugLBS + , Logger + , LogLevel(..) + , mkLogger + , LoggerCtx + , mkLoggerCtx + , cleanLoggerCtx + ) where + +import Hasura.Prelude + +import qualified Control.AutoUpdate as Auto +import qualified Data.Aeson as J +import qualified Data.Aeson.Casing as J +import qualified Data.Aeson.TH as J +import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as BL +import qualified Data.TByteString as TBS +import qualified Data.Text as T +import qualified Data.Time.Clock as Time +import qualified Data.Time.Format as Format +import qualified Data.Time.LocalTime as Time +import qualified System.Log.FastLogger as FL + +newtype FormattedTime + = FormattedTime { _unFormattedTime :: Text } + deriving (Show, Eq, J.ToJSON) + +newtype EngineLogType + = EngineLogType { _unEngineLogType :: Text } + deriving (Show, Eq, J.ToJSON, J.FromJSON, IsString) + +data LogLevel + = LevelDebug + | LevelInfo + | LevelWarn + | LevelError + | LevelOther Text + deriving (Show, Eq, Ord) + +instance J.ToJSON LogLevel where + toJSON = J.toJSON . \case + LevelDebug -> "debug" + LevelInfo -> "info" + LevelWarn -> "warn" + LevelError -> "error" + LevelOther t -> t + +data EngineLog + = EngineLog + { _elTimestamp :: !FormattedTime + , _elLevel :: !LogLevel + , _elType :: !EngineLogType + , _elDetail :: !J.Value + } deriving (Show, Eq) +$(J.deriveToJSON (J.aesonDrop 3 J.snakeCase) ''EngineLog) + + +newtype UnstructuredLog + = UnstructuredLog { _unUnstructuredLog :: TBS.TByteString } + deriving (Show, Eq) + +debugT :: Text -> UnstructuredLog +debugT = UnstructuredLog . TBS.fromText + +debugBS :: B.ByteString -> UnstructuredLog +debugBS = UnstructuredLog . TBS.fromBS + +debugLBS :: BL.ByteString -> UnstructuredLog +debugLBS = UnstructuredLog . TBS.fromLBS + +instance ToEngineLog UnstructuredLog where + toEngineLog (UnstructuredLog t) = + (LevelDebug, "unstructured", J.toJSON t) + +class ToEngineLog a where + toEngineLog :: a -> (LogLevel, EngineLogType, J.Value) + +data LoggerCtx + = LoggerCtx + { _lcLoggerSet :: !FL.LoggerSet + , _lcLogLevel :: !LogLevel + , _lcTimeGetter :: !(IO FormattedTime) + } + +data LoggerSettings + = LoggerSettings + -- should current time be cached (refreshed every sec) + { _lsCachedTimestamp :: !Bool + , _lsTimeZone :: !(Maybe Time.TimeZone) + , _lsLevel :: !LogLevel + } deriving (Show, Eq) + +defaultLoggerSettings :: LoggerSettings +defaultLoggerSettings = + LoggerSettings True Nothing LevelInfo + +getFormattedTime :: Maybe Time.TimeZone -> IO FormattedTime +getFormattedTime tzM = do + tz <- maybe Time.getCurrentTimeZone return tzM + t <- Time.getCurrentTime + let zt = Time.utcToZonedTime tz t + return $ FormattedTime $ T.pack $ formatTime zt + where + formatTime = Format.formatTime Format.defaultTimeLocale format + format = "%FT%T%z" + -- format = Format.iso8601DateFormat (Just "%H:%M:%S") + +mkLoggerCtx :: LoggerSettings -> IO LoggerCtx +mkLoggerCtx (LoggerSettings cacheTime tzM logLevel) = do + loggerSet <- FL.newStdoutLoggerSet FL.defaultBufSize + timeGetter <- bool (return $ getFormattedTime tzM) cachedTimeGetter cacheTime + return $ LoggerCtx loggerSet logLevel timeGetter + where + cachedTimeGetter = + Auto.mkAutoUpdate Auto.defaultUpdateSettings { + Auto.updateAction = getFormattedTime tzM + } + +cleanLoggerCtx :: LoggerCtx -> IO () +cleanLoggerCtx = + FL.rmLoggerSet . _lcLoggerSet + +type Logger = forall a. (ToEngineLog a) => a -> IO () + +mkLogger :: LoggerCtx -> Logger +mkLogger (LoggerCtx loggerSet serverLogLevel timeGetter) l = do + localTime <- timeGetter + let (logLevel, logTy, logDet) = toEngineLog l + when (logLevel >= serverLogLevel) $ + FL.pushLogStrLn loggerSet $ FL.toLogStr $ + J.encode $ EngineLog localTime logLevel logTy logDet diff --git a/server/src-lib/Hasura/Prelude.hs b/server/src-lib/Hasura/Prelude.hs index 641e98a655d87..94b0782abb2eb 100644 --- a/server/src-lib/Hasura/Prelude.hs +++ b/server/src-lib/Hasura/Prelude.hs @@ -12,12 +12,14 @@ import Data.Bool as M (bool) import Data.Either as M (lefts, partitionEithers, rights) import Data.Foldable as M (toList) import Data.Hashable as M (Hashable) -import Data.List as M (foldl', group, sortBy, find) +import Data.List as M (find, foldl', group, sortBy) import Data.Maybe as M (catMaybes, fromMaybe, isJust, listToMaybe, mapMaybe, maybeToList) import Data.Ord as M (comparing) import Data.Semigroup as M (Semigroup (..)) +import Data.String as M (IsString) import Data.Text as M (Text) +import GHC.Generics as M (Generic) import Prelude as M hiding (fail, init, lookup) import Text.Read as M (readEither, readMaybe) diff --git a/server/src-lib/Hasura/RQL/DML/Internal.hs b/server/src-lib/Hasura/RQL/DML/Internal.hs index fe0b60f32098f..83af333b6cbca 100644 --- a/server/src-lib/Hasura/RQL/DML/Internal.hs +++ b/server/src-lib/Hasura/RQL/DML/Internal.hs @@ -242,7 +242,7 @@ mkColExtrAl alM (c, pct) = -- validate headers validateHeaders :: (P1C m) => [T.Text] -> m () validateHeaders depHeaders = do - headers <- (map fst) . userHeaders <$> askUserInfo + headers <- M.keys . userHeaders <$> askUserInfo forM_ depHeaders $ \hdr -> unless (hdr `elem` map T.toLower headers) $ throw400 NotFound $ hdr <<> " header is expected but not found" diff --git a/server/src-lib/Hasura/RQL/Types/Error.hs b/server/src-lib/Hasura/RQL/Types/Error.hs index 8e0e2564077e4..33db692041d04 100644 --- a/server/src-lib/Hasura/RQL/Types/Error.hs +++ b/server/src-lib/Hasura/RQL/Types/Error.hs @@ -6,7 +6,7 @@ module Hasura.RQL.Types.Error ( Code(..) , QErr(..) , encodeQErr - , nonAdminQErrEnc + , noInternalQErrEnc , err400 , err404 , err401 @@ -121,17 +121,18 @@ instance ToJSON QErr where , "internal" .= ie ] -nonAdminQErrEnc :: QErr -> Value -nonAdminQErrEnc (QErr jPath _ msg code _) = +noInternalQErrEnc :: QErr -> Value +noInternalQErrEnc (QErr jPath _ msg code _) = object [ "path" .= encodeJSONPath jPath , "error" .= msg , "code" .= show code ] -encodeQErr :: T.Text -> QErr -> Value -encodeQErr "admin" = toJSON -encodeQErr _ = nonAdminQErrEnc +-- whether internal should be included or not +encodeQErr :: Bool -> QErr -> Value +encodeQErr True = toJSON +encodeQErr _ = noInternalQErrEnc encodeJSONPath :: JSONPath -> String encodeJSONPath = format "$" @@ -171,8 +172,8 @@ type QErrM m = (MonadError QErr m) throw400 :: (QErrM m) => Code -> T.Text -> m a throw400 c t = throwError $ err400 c t -throw404 :: (QErrM m) => Code -> T.Text -> m a -throw404 c t = throwError $ err404 c t +throw404 :: (QErrM m) => T.Text -> m a +throw404 t = throwError $ err404 NotFound t throw401 :: (QErrM m) => T.Text -> m a throw401 t = throwError $ err401 AccessDenied t diff --git a/server/src-lib/Hasura/RQL/Types/Permission.hs b/server/src-lib/Hasura/RQL/Types/Permission.hs index a262c93fe6517..ca313b0b79cbb 100644 --- a/server/src-lib/Hasura/RQL/Types/Permission.hs +++ b/server/src-lib/Hasura/RQL/Types/Permission.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveLift #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} @@ -14,8 +15,8 @@ module Hasura.RQL.Types.Permission , PermId(..) ) where -import Hasura.SQL.Types import Hasura.Prelude +import Hasura.SQL.Types import qualified Database.PG.Query as Q @@ -25,6 +26,7 @@ import Data.Word import Instances.TH.Lift () import Language.Haskell.TH.Syntax (Lift) +import qualified Data.HashMap.Strict as Map import qualified Data.Text as T import qualified PostgreSQL.Binary.Decoding as PD @@ -45,11 +47,13 @@ newtype UserId = UserId { getUserId :: Word64 } data UserInfo = UserInfo { userRole :: !RoleName - , userHeaders :: ![(T.Text, T.Text)] - } deriving (Show, Eq) + , userHeaders :: !(Map.HashMap T.Text T.Text) + } deriving (Show, Eq, Generic) + +instance Hashable UserInfo adminUserInfo :: UserInfo -adminUserInfo = UserInfo adminRole [("X-Hasura-User-Id", "0")] +adminUserInfo = UserInfo adminRole Map.empty data PermType = PTInsert diff --git a/server/src-lib/Hasura/SQL/Types.hs b/server/src-lib/Hasura/SQL/Types.hs index 83b31d93cef76..c2850c650cb5c 100644 --- a/server/src-lib/Hasura/SQL/Types.hs +++ b/server/src-lib/Hasura/SQL/Types.hs @@ -12,7 +12,6 @@ import Hasura.Prelude import Data.Aeson import Data.Aeson.Encoding (text) -import GHC.Generics import Instances.TH.Lift () import Language.Haskell.TH.Syntax (Lift) diff --git a/server/src-lib/Hasura/Server/App.hs b/server/src-lib/Hasura/Server/App.hs index a5331ee97253f..bc0eff007f24d 100644 --- a/server/src-lib/Hasura/Server/App.hs +++ b/server/src-lib/Hasura/Server/App.hs @@ -2,64 +2,57 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} module Hasura.Server.App where import Control.Concurrent.MVar -import Control.Exception (try) -import Control.Lens hiding ((.=)) -import Data.Char (isSpace) import Data.IORef -import Crypto.Hash (Digest, SHA1, hash) -import Data.Aeson hiding (json) -import qualified Data.ByteString.Lazy as BL -import Data.CaseInsensitive (CI (..), original) -import qualified Data.HashMap.Strict as M -import qualified Data.String.Conversions as CS -import qualified Data.Text as T -import qualified Data.Text.Lazy as TL -import qualified Data.Text.Lazy.Encoding as TLE -import Data.Time.Clock (UTCTime, - getCurrentTime) -import qualified Network.Connection as NC -import qualified Network.HTTP.Client as H -import qualified Network.HTTP.Client.TLS as HT -import Network.Wai (strictRequestBody) -import qualified Network.Wreq as Wq -import qualified Network.Wreq.Types as WqT -import qualified Text.Mustache as M -import qualified Text.Mustache.Compile as M +import Data.Aeson hiding (json) +import qualified Data.ByteString.Lazy as BL +import qualified Data.HashMap.Strict as M +import qualified Data.Text as T +import Data.Time.Clock (UTCTime, + getCurrentTime) +import Network.Wai (requestHeaders, + strictRequestBody) +import qualified Text.Mustache as M +import qualified Text.Mustache.Compile as M import Web.Spock.Core -import qualified Network.HTTP.Types as N -import qualified Network.Wai.Internal as WI -import qualified Network.Wai.Middleware.Static as MS +import qualified Network.HTTP.Client as HTTP +import qualified Network.HTTP.Client.TLS as HTTP +import qualified Network.Wai.Middleware.Static as MS -import qualified Data.Text.Encoding.Error as TE -import qualified Database.PG.Query as Q -import qualified Hasura.GraphQL.Execute as GE -import qualified Hasura.GraphQL.Execute.Result as GE -import qualified Hasura.GraphQL.Schema as GS +import qualified Database.PG.Query as Q +import qualified Hasura.GraphQL.Schema as GS +import qualified Hasura.GraphQL.Transport.HTTP as GH +import qualified Hasura.GraphQL.Transport.HTTP.Protocol as GH +import qualified Hasura.GraphQL.Transport.WebSocket as WS +import qualified Network.Wai as Wai +import qualified Network.Wai.Handler.WebSockets as WS +import qualified Network.WebSockets as WS -import Hasura.Prelude hiding (get, put) +import Hasura.Prelude hiding (get, put) import Hasura.RQL.DDL.Schema.Table import Hasura.RQL.DML.Explain import Hasura.RQL.DML.QueryTemplate import Hasura.RQL.Types import Hasura.Server.Init import Hasura.Server.Logging -import Hasura.Server.Middleware (corsMiddleware, - mkDefaultCorsPolicy) +import Hasura.Server.Middleware (corsMiddleware, + mkDefaultCorsPolicy) import Hasura.Server.Query import Hasura.Server.Utils import Hasura.Server.Version import Hasura.SQL.Types -type RavenLogger = ServerLogger (BL.ByteString, Either QErr BL.ByteString) +import qualified Hasura.Logging as L +import Hasura.Server.Auth (AuthMode, getUserInfo) consoleTmplt :: M.Template consoleTmplt = $(M.embedSingleTemplate "src-rsr/console.html") @@ -73,50 +66,27 @@ mkConsoleHTML = errMsg = "Fatal Error : console template rendering failed" ++ show errs -ravenLogGen :: LogDetailG (BL.ByteString, Either QErr BL.ByteString) -ravenLogGen _ (reqBody, res) = - - (status, toJSON <$> logDetail, Just qh, Just size) - where - status = either qeStatus (const N.status200) res - logDetail = either (Just . qErrToLogDetail) (const Nothing) res - reqBodyTxt = TL.filter (not . isSpace) $ decodeLBS reqBody - qErrToLogDetail qErr = - LogDetail reqBodyTxt $ toJSON qErr - size = BL.length $ either encode id res - qh = T.pack . show $ sha1 reqBody - sha1 :: BL.ByteString -> Digest SHA1 - sha1 = hash . BL.toStrict - -decodeLBS :: BL.ByteString -> TL.Text -decodeLBS = TLE.decodeUtf8With TE.lenientDecode - -data AuthMode - = AMNoAuth - | AMAccessKey !T.Text - | AMAccessKeyAndHook !T.Text !T.Text - deriving (Show, Eq) - data ServerCtx = ServerCtx - { scIsolation :: Q.TxIsolation - , scPGPool :: Q.PGPool - , scLogger :: RavenLogger - , scCacheRef :: IORef (SchemaCache, GS.GCtxMap) - , scCacheLock :: MVar () - , scServerMode :: AuthMode + { scIsolation :: Q.TxIsolation + , scPGPool :: Q.PGPool + , scLogger :: L.Logger + , scCacheRef :: IORef (SchemaCache, GS.GCtxMap) + , scCacheLock :: MVar () + , scAuthMode :: AuthMode + , scManager :: HTTP.Manager } data HandlerCtx = HandlerCtx { hcServerCtx :: ServerCtx , hcReqBody :: BL.ByteString - , hcHeaders :: [(T.Text, T.Text)] + , hcUser :: UserInfo } type Handler = ExceptT QErr (ReaderT HandlerCtx IO) -{-# SCC parseBody #-} +-- {-# SCC parseBody #-} parseBody :: (FromJSON a) => Handler a parseBody = do reqBody <- hcReqBody <$> ask @@ -129,107 +99,19 @@ filterHeaders hdrs = flip filter hdrs $ \(h, _) -> isXHasuraTxt h && (T.toLower h /= userRoleHeader) && (T.toLower h /= accessKeyHeader) -parseUserInfo :: Handler UserInfo -parseUserInfo = do - headers <- hcHeaders <$> ask - let mUserRoleTuple = flip find headers $ \hdr -> - userRoleHeader == T.toLower (fst hdr) - mUserRoleV = snd <$> mUserRoleTuple - userRoleV = fromMaybe "admin" mUserRoleV - return $ UserInfo (RoleName userRoleV) $ filterHeaders headers - onlyAdmin :: Handler () onlyAdmin = do - (UserInfo uRole _) <- parseUserInfo + uRole <- asks (userRole . hcUser) when (uRole /= adminRole) $ throw400 AccessDenied "You have to be an admin to access this endpoint" buildQCtx :: Handler QCtx buildQCtx = do scRef <- scCacheRef . hcServerCtx <$> ask - userInfo <- parseUserInfo + userInfo <- asks hcUser cache <- liftIO $ readIORef scRef return $ QCtx userInfo $ fst cache -httpToQErr :: H.HttpException -> QErr -httpToQErr e = case e of - H.InvalidUrlException _ _ -> err500 Unexpected "Invalid Webhook Url" - H.HttpExceptionRequest _ H.ConnectionTimeout -> err500 Unexpected - "Webhook : Connection timeout" - H.HttpExceptionRequest _ H.ResponseTimeout -> err500 Unexpected - "Webhook : Response timeout" - _ -> err500 Unexpected "HTTP Exception from Webhook" - -fromWebHook - :: (MonadIO m) - => T.Text - -> [N.Header] - -> ExceptT QErr m [(T.Text, T.Text)] -fromWebHook urlT reqHeaders = do - manager <- liftIO $ - H.newManager $ HT.mkManagerSettings tlsSimple Nothing - let options = Wq.defaults - { WqT.headers = filteredHeaders - , WqT.checkResponse = Just (\_ _ -> return ()) - , WqT.manager = Right manager - } - respWithExcept <- liftIO $ try $ Wq.getWith options $ T.unpack urlT - resp <- either (throwError . httpToQErr) return respWithExcept - let status = resp ^. Wq.responseStatus - validateStatus status - webHookResp <- decodeBS $ resp ^. Wq.responseBody - return $ M.toList webHookResp - - where - filteredHeaders = flip filter reqHeaders $ \(n, _) -> - n /= "Content-Length" && n /= "User-Agent" && n /= "Host" - && n /= "Origin" && n /= "Referer" - tlsSimple = NC.TLSSettingsSimple True False False - - validateStatus statusCode - | statusCode == N.status200 = return () - | statusCode == N.status401 = throw401 - "Authentication hook unauthorized this request" - | otherwise = throw500 - "Invalid response from authorization hook" - - decodeBS bs = case eitherDecode bs of - Left e -> throw500 $ - "Invalid response from authorization hook; " <> T.pack e - Right a -> return a - -fetchHeaders - :: (MonadIO m) - => WI.Request - -> Maybe T.Text - -> AuthMode - -> ExceptT QErr m [(T.Text, T.Text)] -fetchHeaders req mReqAccessKey authMode = - case authMode of - AMNoAuth -> return headers - - AMAccessKey accKey -> do - reqAccessKey <- maybe accessKeyAuthErr return mReqAccessKey - validateKeyAndReturnHeaders accKey reqAccessKey - - AMAccessKeyAndHook accKey hook -> - maybe (fromWebHook hook rawHeaders) - (validateKeyAndReturnHeaders accKey) - mReqAccessKey - where - rawHeaders = WI.requestHeaders req - headers = headersTxt rawHeaders - - validateKeyAndReturnHeaders key reqKey = do - when (reqKey /= key) accessKeyAuthErr - return headers - - accessKeyAuthErr = throw401 "access keys don't match or not found" - - headersTxt hdrsRaw = - flip map hdrsRaw $ \(hdrName, hdrVal) -> - (CS.cs $ original hdrName, CS.cs hdrVal) - logResult :: (MonadIO m) => ServerCtx @@ -239,7 +121,7 @@ logResult logResult sc res qTime = do req <- request reqBody <- liftIO $ strictRequestBody req - liftIO $ logger req (reqBody, res) qTime + liftIO $ logger $ mkAccessLog req (reqBody, res) qTime where logger = scLogger sc @@ -248,21 +130,21 @@ logError sc qErr = logResult sc (Left qErr) Nothing mkSpockAction :: (MonadIO m) - => (T.Text -> QErr -> Value) + => (Bool -> QErr -> Value) -> ServerCtx -> Handler BL.ByteString -> ActionT m () mkSpockAction qErrEncoder serverCtx handler = do req <- request reqBody <- liftIO $ strictRequestBody req - role <- fromMaybe "admin" <$> header userRoleHeader + let headers = requestHeaders req + authMode = scAuthMode serverCtx + manager = scManager serverCtx - accKeyHeader <- header accessKeyHeader - headersRes <- runExceptT $ - fetchHeaders req accKeyHeader $ scServerMode serverCtx - headers <- either (logAndThrow role) return headersRes + userInfoE <- liftIO $ runExceptT $ getUserInfo manager headers authMode + userInfo <- either (logAndThrow False) return userInfoE - let handlerState = HandlerCtx serverCtx reqBody headers + let handlerState = HandlerCtx serverCtx reqBody userInfo t1 <- liftIO getCurrentTime -- for measuring response time purposes result <- liftIO $ runReaderT (runExceptT handler) handlerState @@ -270,22 +152,22 @@ mkSpockAction qErrEncoder serverCtx handler = do -- log result logResult serverCtx result $ Just (t1, t2) - either (qErrToResp role) resToResp result + either (qErrToResp $ userRole userInfo == adminRole) resToResp result + where -- encode error response - qErrToResp role qErr = do + qErrToResp includeInternal qErr = do setStatus $ qeStatus qErr - json $ qErrEncoder role qErr + json $ qErrEncoder includeInternal qErr - logAndThrow role qErr = do + logAndThrow includeInternal qErr = do logError serverCtx qErr - qErrToResp role qErr + qErrToResp includeInternal qErr resToResp resp = do uncurry setHeader jsonHeader lazyBytes resp - withLock :: (MonadIO m, MonadError e m) => MVar () -> m a -> m a withLock lk action = do @@ -298,21 +180,21 @@ withLock lk action = do acquireLock = liftIO $ takeMVar lk releaseLock = liftIO $ putMVar lk () -v1ExplainHandler :: RQLExplain -> Handler BL.ByteString -v1ExplainHandler expQuery = dbAction - where - dbAction = do - onlyAdmin - scRef <- scCacheRef . hcServerCtx <$> ask - schemaCache <- liftIO $ readIORef scRef - pool <- scPGPool . hcServerCtx <$> ask - isoL <- scIsolation . hcServerCtx <$> ask - runExplainQuery pool isoL userInfo (fst schemaCache) selectQ - - selectQ = rqleQuery expQuery - role = rqleRole expQuery - headers = M.toList $ rqleHeaders expQuery - userInfo = UserInfo role headers +-- v1ExplainHandler :: RQLExplain -> Handler BL.ByteString +-- v1ExplainHandler expQuery = dbAction +-- where +-- dbAction = do +-- onlyAdmin +-- scRef <- scCacheRef . hcServerCtx <$> ask +-- schemaCache <- liftIO $ readIORef scRef +-- pool <- scPGPool . hcServerCtx <$> ask +-- isoL <- scIsolation . hcServerCtx <$> ask +-- runExplainQuery pool isoL userInfo (fst schemaCache) selectQ + +-- selectQ = rqleQuery expQuery +-- role = rqleRole expQuery +-- headers = M.toList $ rqleHeaders expQuery +-- userInfo = UserInfo role headers v1QueryHandler :: RQLQuery -> Handler BL.ByteString v1QueryHandler query = do @@ -322,7 +204,7 @@ v1QueryHandler query = do where -- Hit postgres dbAction = do - userInfo <- parseUserInfo + userInfo <- asks hcUser scRef <- scCacheRef . hcServerCtx <$> ask schemaCache <- liftIO $ readIORef scRef pool <- scPGPool . hcServerCtx <$> ask @@ -337,14 +219,14 @@ v1QueryHandler query = do liftIO $ writeIORef scRef (newSc, newGCtxMap) return resp -v1Alpha1GQHandler :: GE.GraphQLRequest -> Handler BL.ByteString +v1Alpha1GQHandler :: GH.GraphQLRequest -> Handler BL.ByteString v1Alpha1GQHandler query = do - userInfo <- parseUserInfo + userInfo <- asks hcUser scRef <- scCacheRef . hcServerCtx <$> ask cache <- liftIO $ readIORef scRef pool <- scPGPool . hcServerCtx <$> ask isoL <- scIsolation . hcServerCtx <$> ask - GE.runGQ pool isoL userInfo (snd cache) query + GH.runGQ pool isoL userInfo (snd cache) query -- v1Alpha1GQSchemaHandler :: Handler BL.ByteString -- v1Alpha1GQSchemaHandler = do @@ -377,31 +259,46 @@ legacyQueryHandler :: TableName -> T.Text -> Handler BL.ByteString legacyQueryHandler tn queryType = case M.lookup queryType queryParsers of Just queryParser -> getQueryParser queryParser qt >>= v1QueryHandler - Nothing -> throw404 NotFound "No such resource exists" + Nothing -> throw404 "No such resource exists" where qt = QualifiedTable publicSchema tn -app +mkWaiApp :: Q.TxIsolation -> Maybe String - -> RavenLogger + -> L.LoggerCtx -> Q.PGPool -> AuthMode -> CorsConfig -> Bool - -> SpockT IO () -app isoLevel mRootDir logger pool mode corsCfg enableConsole = do - cacheRef <- lift $ do + -> IO Wai.Application +mkWaiApp isoLevel mRootDir loggerCtx pool mode corsCfg enableConsole = do + cacheRef <- do pgResp <- liftIO $ runExceptT $ Q.runTx pool (Q.Serializable, Nothing) $ do Q.catchE defaultTxErrorHandler initStateTx sc <- buildSchemaCache (,) sc <$> GS.mkGCtxMap (scTables sc) either initErrExit return pgResp >>= newIORef - cacheLock <- lift $ newMVar () + httpManager <- HTTP.newManager HTTP.tlsManagerSettings + + cacheLock <- newMVar () + + let serverCtx = + ServerCtx isoLevel pool (L.mkLogger loggerCtx) cacheRef + cacheLock mode httpManager + + spockApp <- spockAsApp $ spockT id $ + httpApp mRootDir corsCfg serverCtx enableConsole + + let runTx tx = runExceptT $ Q.runTx pool (isoLevel, Nothing) tx - let serverCtx = ServerCtx isoLevel pool logger cacheRef cacheLock mode + wsServerEnv <- WS.createWSServerEnv (scLogger serverCtx) httpManager cacheRef runTx + let wsServerApp = WS.createWSServerApp mode wsServerEnv + return $ WS.websocketsOr WS.defaultConnectionOptions wsServerApp spockApp +httpApp :: Maybe String -> CorsConfig -> ServerCtx -> Bool -> SpockT IO () +httpApp mRootDir corsCfg serverCtx enableConsole = do liftIO $ putStrLn "HasuraDB is now waiting for connections" -- cors middleware @@ -416,20 +313,20 @@ app isoLevel mRootDir logger pool mode corsCfg enableConsole = do get "v1/version" getVersion - get ("v1/template" var) $ tmpltGetOrDeleteH serverCtx - post ("v1/template" var) $ tmpltPutOrPostH serverCtx - put ("v1/template" var) $ tmpltPutOrPostH serverCtx - delete ("v1/template" var) $ tmpltGetOrDeleteH serverCtx + get ("v1/template" var) tmpltGetOrDeleteH + post ("v1/template" var) tmpltPutOrPostH + put ("v1/template" var) tmpltPutOrPostH + delete ("v1/template" var) tmpltGetOrDeleteH post "v1/query" $ mkSpockAction encodeQErr serverCtx $ do query <- parseBody v1QueryHandler query - post "v1/query/explain" $ mkSpockAction encodeQErr serverCtx $ do - expQuery <- parseBody - v1ExplainHandler expQuery + -- post "v1/query/explain" $ mkSpockAction encodeQErr serverCtx $ do + -- expQuery <- parseBody + -- v1ExplainHandler expQuery - post "v1alpha1/graphql" $ mkSpockAction GE.encodeGQErr serverCtx $ do + post "v1alpha1/graphql" $ mkSpockAction GH.encodeGQErr serverCtx $ do query <- parseBody v1Alpha1GQHandler query @@ -437,7 +334,8 @@ app isoLevel mRootDir logger pool mode corsCfg enableConsole = do -- mkSpockAction encodeQErr serverCtx v1Alpha1GQSchemaHandler post ("api/1/table" var var) $ \tableName queryType -> - mkSpockAction encodeQErr serverCtx $ legacyQueryHandler (TableName tableName) queryType + mkSpockAction encodeQErr serverCtx $ + legacyQueryHandler (TableName tableName) queryType hookAny GET $ \_ -> do let qErr = err404 NotFound "resource does not exist" @@ -446,11 +344,11 @@ app isoLevel mRootDir logger pool mode corsCfg enableConsole = do lazyBytes $ encode qErr where - tmpltGetOrDeleteH serverCtx tmpltName = do + tmpltGetOrDeleteH tmpltName = do tmpltArgs <- tmpltArgsFromQueryParams mkSpockAction encodeQErr serverCtx $ mkQTemplateAction tmpltName tmpltArgs - tmpltPutOrPostH serverCtx tmpltName = do + tmpltPutOrPostH tmpltName = do tmpltArgs <- tmpltArgsFromQueryParams mkSpockAction encodeQErr serverCtx $ do bodyTmpltArgs <- parseBody diff --git a/server/src-lib/Hasura/Server/Auth.hs b/server/src-lib/Hasura/Server/Auth.hs new file mode 100644 index 0000000000000..f6568e4899b28 --- /dev/null +++ b/server/src-lib/Hasura/Server/Auth.hs @@ -0,0 +1,135 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Hasura.Server.Auth + ( getUserInfo + , AuthMode(..) + ) where + +import Control.Exception (try) +import Control.Lens +import Data.Aeson +import Data.CaseInsensitive (CI (..), original) + +import qualified Data.ByteString as B +import qualified Data.HashMap.Strict as M +import qualified Data.Text as T +import qualified Data.Text.Encoding as TE +import qualified Data.Text.Encoding.Error as TE +import qualified Network.HTTP.Client as H +import qualified Network.HTTP.Types as N +import qualified Network.Wreq as Wreq + +import Hasura.Prelude +import Hasura.RQL.Types + +bsToTxt :: B.ByteString -> T.Text +bsToTxt = TE.decodeUtf8With TE.lenientDecode + +data AuthMode + = AMNoAuth + | AMAccessKey !T.Text + | AMAccessKeyAndHook !T.Text !T.Text + deriving (Show, Eq) + +httpToQErr :: H.HttpException -> QErr +httpToQErr e = case e of + H.InvalidUrlException _ _ -> err500 Unexpected "Invalid Webhook Url" + H.HttpExceptionRequest _ H.ConnectionTimeout -> err500 Unexpected + "Webhook : Connection timeout" + H.HttpExceptionRequest _ H.ResponseTimeout -> err500 Unexpected + "Webhook : Response timeout" + _ -> err500 Unexpected "HTTP Exception from Webhook" + +userRoleHeader :: T.Text +userRoleHeader = "x-hasura-role" + +userInfoFromWebhook + :: (MonadIO m, MonadError QErr m) + => H.Manager + -> T.Text + -> [N.Header] + -> m UserInfo +userInfoFromWebhook manager urlT reqHeaders = do + let options = + Wreq.defaults + & Wreq.headers .~ filteredHeaders + & Wreq.checkResponse ?~ (\_ _ -> return ()) + & Wreq.manager .~ Right manager + + res <- liftIO $ try $ Wreq.getWith options $ T.unpack urlT + resp <- either (throwError . httpToQErr) return res + let status = resp ^. Wreq.responseStatus + + validateStatus status + rawHeaders <- decodeResp $ resp ^. Wreq.responseBody + + let headers = M.fromList [(T.toLower k, v) | (k, v) <- M.toList rawHeaders] + + case M.lookup userRoleHeader headers of + Nothing -> throw500 "missing x-hasura-role key in webhook response: " + Just v -> return $ UserInfo (RoleName v) headers + + where + filteredHeaders = flip filter reqHeaders $ \(n, _) -> + n /= "Content-Length" && n /= "User-Agent" && n /= "Host" + && n /= "Origin" && n /= "Referer" + + validateStatus statusCode + | statusCode == N.status200 = return () + | statusCode == N.status401 = + throw401 "Authentication hook unauthorized this request" + | otherwise = + throw500 "Invalid response from authorization hook" + + decodeResp bs = case eitherDecode bs of + Left e -> throw500 $ + "Invalid response from authorization hook: " <> T.pack e + Right a -> return a + +accessKeyHeader :: T.Text +accessKeyHeader = "x-hasura-access-key" + +getUserInfo + :: (MonadIO m, MonadError QErr m) + => H.Manager + -> [N.Header] + -> AuthMode + -> m UserInfo +getUserInfo manager rawHeaders = \case + + AMNoAuth -> return userInfoFromHeaders + + AMAccessKey accKey -> + case getHeader accessKeyHeader of + Just givenAccKey -> userInfoWhenAccessKey accKey givenAccKey + Nothing -> throw401 "x-hasura-access-key required, but not found" + + AMAccessKeyAndHook accKey hook -> + maybe + (userInfoFromWebhook manager hook rawHeaders) + (userInfoWhenAccessKey accKey) $ + getHeader accessKeyHeader + + where + + headers = + M.fromList $ filter (T.isPrefixOf "x-hasura-" . fst) $ + flip map rawHeaders $ + \(hdrName, hdrVal) -> + (T.toLower $ bsToTxt $ original hdrName, bsToTxt hdrVal) + + getHeader h = M.lookup h headers + + userInfoFromHeaders = + case M.lookup "x-hasura-role" headers of + Just v -> UserInfo (RoleName v) headers + Nothing -> UserInfo adminRole M.empty + + userInfoWhenAccessKey key reqKey = do + when (reqKey /= key) $ throw401 "invalid x-hasura-access-key" + return userInfoFromHeaders diff --git a/server/src-lib/Hasura/Server/Logging.hs b/server/src-lib/Hasura/Server/Logging.hs index 3b24a24b9a0a4..1556536dd5cd9 100644 --- a/server/src-lib/Hasura/Server/Logging.hs +++ b/server/src-lib/Hasura/Server/Logging.hs @@ -5,30 +5,26 @@ -- This is taken from wai-logger and customised for our use module Hasura.Server.Logging - ( ServerLogger - , withStdoutLogger - , ServerLog(..) - , LogDetail(..) - , LogDetailG - , getRequestHeader - ) where - -import Control.Exception (bracket) + ( mkAccessLog + , getRequestHeader + ) where + +import Crypto.Hash (Digest, SHA1, hash) import Data.Aeson import Data.Bits (shift, (.&.)) import Data.ByteString.Char8 (ByteString) +import qualified Data.ByteString.Lazy as BL import Data.Int (Int64) import Data.List (find) +import qualified Data.TByteString as TBS import qualified Data.Text as T import qualified Data.Text.Encoding as TE import qualified Data.Text.Encoding.Error as TE -import qualified Data.Text.Lazy as TL import Data.Time.Clock import Data.Word (Word32) import Network.Socket (SockAddr (..)) import Network.Wai (Request (..)) import System.ByteOrder (ByteOrder (..), byteOrder) -import System.Log.FastLogger import Text.Printf (printf) import qualified Data.ByteString.Char8 as BS @@ -36,51 +32,51 @@ import qualified Data.CaseInsensitive as CI import qualified Data.HashMap.Strict as M import qualified Network.HTTP.Types as N +import qualified Hasura.Logging as L import Hasura.Prelude +import Hasura.RQL.Types.Error import Hasura.Server.Utils - -data ServerLog - = ServerLog - { slStatus :: !N.Status - , slMethod :: !T.Text - , slSource :: !T.Text - , slPath :: !T.Text - , slTimestamp :: !T.Text - , slHttpVersion :: !N.HttpVersion - , slDetail :: !(Maybe Value) - , slRequestId :: !(Maybe T.Text) - -- , slHasuraId :: !(Maybe T.Text) - , slHasuraRole :: !(Maybe T.Text) - , slHasuraMetadata :: !(Maybe Value) - , slQueryHash :: !(Maybe T.Text) - , slResponseSize :: !(Maybe Int64) - , slResponseTime :: !(Maybe T.Text) +data AccessLog + = AccessLog + { alStatus :: !N.Status + , alMethod :: !T.Text + , alSource :: !T.Text + , alPath :: !T.Text + , alHttpVersion :: !N.HttpVersion + , alDetail :: !(Maybe Value) + , alRequestId :: !(Maybe T.Text) + , alHasuraRole :: !(Maybe T.Text) + , alHasuraMetadata :: !(Maybe Value) + , alQueryHash :: !(Maybe T.Text) + , alResponseSize :: !(Maybe Int64) + , alResponseTime :: !(Maybe T.Text) } deriving (Show, Eq) -instance ToJSON ServerLog where - toJSON (ServerLog st met src path ts hv det reqId hRole hMd qh rs rt) = +instance L.ToEngineLog AccessLog where + toEngineLog accessLog = + (L.LevelInfo, "http-log", toJSON accessLog) + +instance ToJSON AccessLog where + toJSON (AccessLog st met src path hv det reqId hRole hMd qh rs rt) = object [ "status" .= N.statusCode st , "method" .= met , "ip" .= src , "url" .= path - , "timestamp" .= ts , "http_version" .= show hv , "detail" .= det , "request_id" .= reqId - -- , "hasura_id" .= hId , "hasura_role" .= hRole , "hasura_metadata" .= hMd , "query_hash" .= qh , "response_size" .= rs - -- , "response_time" .= rt , "query_execution_time" .= rt ] data LogDetail = LogDetail - { ldQuery :: !TL.Text - , ldError :: !Value + { _ldQuery :: !TBS.TByteString + , _ldError :: !Value } deriving (Show, Eq) instance ToJSON LogDetail where @@ -90,52 +86,64 @@ instance ToJSON LogDetail where ] -- type ServerLogger = Request -> BL.ByteString -> Either QErr BL.ByteString -> IO () -type ServerLogger r = Request -> r -> Maybe (UTCTime, UTCTime) -> IO () - -type LogDetailG r = Request -> r -> (N.Status, Maybe Value, Maybe T.Text, Maybe Int64) - -withStdoutLogger :: LogDetailG r -> (ServerLogger r -> IO a) -> IO a -withStdoutLogger detailF appf = - bracket setup teardown $ \(rlogger, _) -> appf rlogger +-- type ServerLogger r = Request -> r -> Maybe (UTCTime, UTCTime) -> IO () + +-- type LogDetailG r = Request -> r -> (N.Status, Maybe Value, Maybe T.Text, Maybe Int64) + +-- withStdoutLogger :: LogDetailG r -> (ServerLogger r -> IO a) -> IO a +-- withStdoutLogger detailF appf = +-- bracket setup teardown $ \(rlogger, _) -> appf rlogger +-- where +-- setup = do +-- getter <- newTimeCache "%FT%T%z" +-- lgrset <- newStdoutLoggerSet defaultBufSize +-- let logger req env timeT = do +-- zdata <- getter +-- let serverLog = mkAccessLog detailF zdata req env timeT +-- pushLogStrLn lgrset $ toLogStr $ encode serverLog +-- when (isJust $ slDetail serverLog) $ flushLogStr lgrset +-- remover = rmLoggerSet lgrset +-- return (logger, remover) +-- teardown (_, remover) = void remover + +ravenLogGen + :: (BL.ByteString, Either QErr BL.ByteString) + -> (N.Status, Maybe Value, Maybe T.Text, Maybe Int64) +ravenLogGen (reqBody, res) = + (status, toJSON <$> logDetail, Just qh, Just size) where - setup = do - getter <- newTimeCache "%FT%T%z" - lgrset <- newStdoutLoggerSet defaultBufSize - let logger req env timeT = do - zdata <- getter - let serverLog = mkServerLog detailF zdata req env timeT - pushLogStrLn lgrset $ toLogStr $ encode serverLog - when (isJust $ slDetail serverLog) $ flushLogStr lgrset - remover = rmLoggerSet lgrset - return (logger, remover) - teardown (_, remover) = void remover - -mkServerLog - :: LogDetailG r - -> FormattedTime - -> Request - -> r + status = either qeStatus (const N.status200) res + logDetail = either (Just . qErrToLogDetail) (const Nothing) res + reqBodyTxt = TBS.fromLBS reqBody + qErrToLogDetail qErr = + LogDetail reqBodyTxt $ toJSON qErr + size = BL.length $ either encode id res + qh = T.pack . show $ sha1 reqBody + sha1 :: BL.ByteString -> Digest SHA1 + sha1 = hash . BL.toStrict + +mkAccessLog + :: Request + -> (BL.ByteString, Either QErr BL.ByteString) -> Maybe (UTCTime, UTCTime) - -> ServerLog -mkServerLog detailF tmstr req r mTimeT = - ServerLog - { slStatus = status - , slMethod = decodeBS $ requestMethod req - , slSource = decodeBS $ getSourceFromFallback req - , slPath = decodeBS $ rawPathInfo req - , slTimestamp = decodeBS tmstr - , slHttpVersion = httpVersion req - , slDetail = mDetail - , slRequestId = decodeBS <$> getRequestId req - -- , slHasuraId = decodeBS <$> getHasuraId req - , slHasuraRole = decodeBS <$> getHasuraRole req - , slHasuraMetadata = getHasuraMetadata req - , slResponseSize = size - , slResponseTime = T.pack . show <$> diffTime - , slQueryHash = queryHash + -> AccessLog +mkAccessLog req r mTimeT = + AccessLog + { alStatus = status + , alMethod = decodeBS $ requestMethod req + , alSource = decodeBS $ getSourceFromFallback req + , alPath = decodeBS $ rawPathInfo req + , alHttpVersion = httpVersion req + , alDetail = mDetail + , alRequestId = decodeBS <$> getRequestId req + , alHasuraRole = decodeBS <$> getHasuraRole req + , alHasuraMetadata = getHasuraMetadata req + , alResponseSize = size + , alResponseTime = T.pack . show <$> diffTime + , alQueryHash = queryHash } where - (status, mDetail, queryHash, size) = detailF req r + (status, mDetail, queryHash, size) = ravenLogGen r diffTime = case mTimeT of Nothing -> Nothing Just (t1, t2) -> Just $ diffUTCTime t2 t1 @@ -175,9 +183,9 @@ newtype HasuraMetadata = HasuraMetadata { unHM :: M.HashMap T.Text T.Text } deriving (Show) instance ToJSON HasuraMetadata where - toJSON hash = toJSON $ M.fromList $ map (\(k,v) -> (format k, v)) hdrs + toJSON h = toJSON $ M.fromList $ map (\(k,v) -> (format k, v)) hdrs where - hdrs = M.toList $ unHM hash + hdrs = M.toList $ unHM h format = T.map underscorify . T.drop 2 underscorify '-' = '_' underscorify c = c diff --git a/server/src-lib/Hasura/Server/Middleware.hs b/server/src-lib/Hasura/Server/Middleware.hs index 025642965b3a1..252803b3a22ce 100644 --- a/server/src-lib/Hasura/Server/Middleware.hs +++ b/server/src-lib/Hasura/Server/Middleware.hs @@ -14,7 +14,6 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as TE import qualified Network.HTTP.Types as H - data CorsPolicy = CorsPolicy { cpDomain :: !T.Text @@ -22,7 +21,6 @@ data CorsPolicy , cpMaxAge :: !Int } deriving (Show, Eq) - mkDefaultCorsPolicy :: T.Text -> CorsPolicy mkDefaultCorsPolicy domain = CorsPolicy @@ -31,7 +29,6 @@ mkDefaultCorsPolicy domain = , cpMaxAge = 1728000 } - corsMiddleware :: CorsPolicy -> Middleware corsMiddleware policy app req sendResp = maybe (app req sendResp) handleCors $ getRequestHeader "Origin" req diff --git a/server/src-lib/Hasura/Server/Query.hs b/server/src-lib/Hasura/Server/Query.hs index bc1262cc68a00..667a3faf6fd07 100644 --- a/server/src-lib/Hasura/Server/Query.hs +++ b/server/src-lib/Hasura/Server/Query.hs @@ -12,6 +12,7 @@ import Language.Haskell.TH.Syntax (Lift) import qualified Data.ByteString.Builder as BB import qualified Data.ByteString.Lazy as BL +import qualified Data.HashMap.Strict as Map import qualified Data.Sequence as Seq import qualified Data.Text as T import qualified Data.Vector as V @@ -242,7 +243,7 @@ setHeadersTx :: UserInfo -> Q.TxE QErr () setHeadersTx userInfo = forM_ hdrs $ \h -> Q.unitQE defaultTxErrorHandler (mkQ h) () False where - hdrs = userHeaders userInfo + hdrs = Map.toList $ userHeaders userInfo mkQ (h, v) = Q.fromBuilder $ BB.string7 $ T.unpack $ "SET LOCAL hasura." <> dropAndSnakeCase h <> " = " <> pgFmtLit v diff --git a/server/stack.yaml b/server/stack.yaml index a5fad0c9edb09..1dec4df0ca515 100644 --- a/server/stack.yaml +++ b/server/stack.yaml @@ -18,7 +18,7 @@ extra-deps: - git: https://github.com/hasura/pg-client-hs.git commit: 77995388cab656f9180b851f33f3d603cf1017c7 - git: https://github.com/hasura/graphql-parser-hs.git - commit: 0974c1a2cddb0b5aca0941abae4ad0a9b2e4a051 + commit: eae59812ec537b3756c3ddb5f59a7cc59508869b # Override default flag values for local packages and extra-deps flags: {} diff --git a/server/test/Main.hs b/server/test/Main.hs index 6d4c901fc0503..653c9fc0c7da0 100644 --- a/server/test/Main.hs +++ b/server/test/Main.hs @@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} module Main where @@ -11,22 +12,22 @@ import System.Exit (exitFailure) import Test.Hspec.Core.Runner import Test.Hspec.Formatters import Test.Hspec.Wai -import Web.Spock.Core (spockAsApp, spockT) import qualified Data.Aeson as J import qualified Data.ByteString.Lazy.Char8 as BLC +import qualified Database.PG.Query as Q +import qualified Hasura.Logging as L import Hasura.Prelude -import Hasura.Server.App (AuthMode (..), RavenLogger, app, - ravenLogGen) -import Hasura.Server.Init -import Hasura.Server.Logging (withStdoutLogger) -import Ops (initCatalogSafe) -import Spec (mkSpecs) +import Hasura.Server.App (mkWaiApp) +import Hasura.Server.Auth (AuthMode (..)) + -import qualified Database.PG.Query as Q import qualified Database.PG.Query as PGQ +import Hasura.Server.Init +import Ops (initCatalogSafe) +import Spec (mkSpecs) data ConnectionParams = ConnectionParams RawConnInfo Q.ConnParams @@ -40,13 +41,14 @@ resetStateTx = do Q.unitQE PGQ.PGExecErrTx "DROP SCHEMA public CASCADE" () False Q.unitQE PGQ.PGExecErrTx "CREATE SCHEMA public" () False -ravenApp :: RavenLogger -> PGQ.PGPool -> IO Application -ravenApp rlogger pool = do +ravenApp :: L.LoggerCtx -> PGQ.PGPool -> IO Application +ravenApp loggerCtx pool = do let corsCfg = CorsConfigG "*" True -- cors is disabled - spockAsApp $ spockT id $ app Q.Serializable Nothing rlogger pool AMNoAuth corsCfg True -- no access key and no webhook + -- spockAsApp $ spockT id $ app Q.Serializable Nothing rlogger pool AMNoAuth corsCfg True -- no access key and no webhook + mkWaiApp Q.Serializable Nothing loggerCtx pool AMNoAuth corsCfg True -- no access key and no webhook main :: IO () -main = withStdoutLogger ravenLogGen $ \rlogger -> do +main = do -- parse CLI flags for connection params ConnectionParams rci cp <- parseArgs -- form the postgres connection info @@ -59,9 +61,10 @@ main = withStdoutLogger ravenLogGen $ \rlogger -> do -- intialize state for graphql-engine in the database liftIO $ initialise pool specs <- mkSpecs + loggerCtx <- L.mkLoggerCtx L.defaultLoggerSettings -- run the tests withArgs [] $ hspecWith defaultConfig {configFormatter = Just progress} $ - with (ravenApp rlogger pool) specs + with (ravenApp loggerCtx pool) specs where initialise :: Q.PGPool -> IO ()