diff --git a/.npm/package/npm-shrinkwrap.json b/.npm/package/npm-shrinkwrap.json index 6d5405f..94b1df5 100644 --- a/.npm/package/npm-shrinkwrap.json +++ b/.npm/package/npm-shrinkwrap.json @@ -1,712 +1,45 @@ { "lockfileVersion": 1, "dependencies": { - "@tokenizer/token": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.1.1.tgz", - "integrity": "sha512-XO6INPbZCxdprl+9qa/AAbFFOMzzwqYxpjPgLICrMD6C2FCw6qfJOPcBk6JqqPLSaZ/Qx87qn4rpPmPMwaAK6w==" - }, - "@types/debug": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", - "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==" - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==" - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==" - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==" - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==" }, "at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" }, - "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=" - }, - "aws4": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", - "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" - }, - "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=" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "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=" - }, - "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=" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=" - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==" - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=" - }, - "env-paths": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", - "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==" + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "file-type": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.0.0.tgz", - "integrity": "sha512-0u4D11yDu0NXF+8qp1eiQ/6cOwPI7sbu9/bGzUOhlwzKbB9FYFivgTtsVPtlkXAakfByWjOsLp2/Jx927OVetg==" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==" - }, "fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==" - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=" - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==" + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==" }, "graceful-fs": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=" - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==" - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "ignore-walk": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "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=" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "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==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, "jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=" - }, - "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==" - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==" - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==" - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" - }, - "needle": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.2.tgz", - "integrity": "sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ==" - }, - "node-gyp": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.0.0.tgz", - "integrity": "sha512-ZW34qA3CJSPKDz2SJBHKRvyNQN0yWO5EGKKksJc+jElu9VA468gwJTyTArC1iOXU7rN3Wtfg/CMt/dBAOFIjvg==" - }, - "node-libcurl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/node-libcurl/-/node-libcurl-2.2.0.tgz", - "integrity": "sha512-dyv3IuQBqO4KK5ojtM4k6FuBA3RxZjTqO4c+MUirwvlTY7qIH2oNSws8Xte1pp2aso9TuXyAwxS/g3ZqmAk8aA==" - }, - "node-pre-gyp": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz", - "integrity": "sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==", - "dependencies": { - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==" - }, - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==" - }, - "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==" - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "tar": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", - "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } - }, - "nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==" - }, - "npm-bundled": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", - "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==" - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" - }, - "npm-packlist": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==" - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==" - }, - "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=" - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=" - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "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=" - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==" - }, - "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=" - }, - "peek-readable": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-3.1.0.tgz", - "integrity": "sha512-KGuODSTV6hcgdZvDrIDBUkN0utcAVj1LL7FfGbM0viKTtCHmtZcuEJ+lGqsp0fTFkGqesdtemV2yUSMeyy3ddA==" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==" - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==" - }, - "readable-web-to-node-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-2.0.0.tgz", - "integrity": "sha512-+oZJurc4hXpaaqsN68GoZGQAQIA3qr09Or4fqEsargABnbe5Aau8hFn6ISVleT3cpY/0n/8drn7huyyEvTbghA==" - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==" - }, - "request-libcurl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/request-libcurl/-/request-libcurl-2.2.1.tgz", - "integrity": "sha512-qbK9J348JYzhr+NE4paS7QbYb/ymb3OBZUp/jpuYZujGfpShvfN/m3ghCn4W02I/VleEx8r13FbquDRs95QyQg==" - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==" - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=" - }, - "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==" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=" - }, - "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=" - }, - "strtok3": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.0.4.tgz", - "integrity": "sha512-rqWMKwsbN9APU47bQTMEYTPcwdpKDtmf1jVhHzNW2cL1WqAxaM9iBb9t5P2fj+RV2YsErUWgQzHD5JwV0uCTEQ==" - }, - "tar": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", - "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==" - }, - "token-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-2.0.0.tgz", - "integrity": "sha512-WWvu8sGK8/ZmGusekZJJ5NM6rRVTTDO7/bahz4NGiSDb/XsmdYBn6a1N/bymUHuWYTWeuLUg98wUzvE4jPdCZw==" - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==" - }, - "tslib": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.0.tgz", - "integrity": "sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=" - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==" }, "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" - }, - "uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=" - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==" - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" } } } diff --git a/.versions b/.versions index e0f0e54..86f72a7 100644 --- a/.versions +++ b/.versions @@ -1,5 +1,5 @@ allow-deny@1.1.0 -babel-compiler@7.5.3 +babel-compiler@7.6.0 babel-runtime@1.5.0 base64@1.0.12 binary-heap@1.0.11 @@ -7,46 +7,45 @@ boilerplate-generator@1.7.1 callback-hook@1.3.0 check@1.3.1 ddp@1.4.0 -ddp-client@2.3.3 +ddp-client@2.4.0 ddp-common@1.4.0 ddp-server@2.3.2 diff-sequence@1.1.1 -dynamic-import@0.5.2 -ecmascript@0.14.3 +dynamic-import@0.6.0 +ecmascript@0.15.0 ecmascript-runtime@0.7.0 ecmascript-runtime-client@0.11.0 ecmascript-runtime-server@0.10.0 ejson@1.1.1 fetch@0.1.1 geojson-utils@1.0.10 -http@1.4.2 id-map@1.1.0 inter-process-messaging@0.1.1 -local-test:ostrio:files@1.14.3 -logging@1.1.20 +local-test:ostrio:files@2.0.0 +logging@1.2.0 meteor@1.9.3 -minimongo@1.6.0 +minimongo@1.6.1 modern-browsers@0.1.5 -modules@0.15.0 +modules@0.16.0 modules-runtime@0.12.0 -mongo@1.10.0 -mongo-decimal@0.1.1 +mongo@1.10.1 +mongo-decimal@0.1.2 mongo-dev-server@1.1.0 mongo-id@1.0.7 npm-mongo@3.8.1 ordered-dict@1.1.0 -ostrio:cookies@2.6.1 -ostrio:files@1.14.3 +ostrio:cookies@2.7.0 +ostrio:files@2.0.0 promise@0.11.2 random@1.2.0 +react-fast-refresh@0.1.0 reactive-var@1.0.11 -reload@1.3.0 +reload@1.3.1 retry@1.1.0 routepolicy@1.1.0 socket-stream-client@0.3.1 tinytest@1.1.0 tracker@1.2.0 underscore@1.0.10 -url@1.3.1 -webapp@1.9.1 -webapp-hashing@1.0.9 +webapp@1.10.0 +webapp-hashing@1.1.0 diff --git a/LICENSE b/LICENSE index 2cbf89b..aa54073 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2020, dr.dimitru (Dmitry A.; Veliov Group, LLC) +Copyright (c) 2021, dr.dimitru (Dmitry A.; Veliov Group, LLC) All rights reserved. Redistribution and use in source and binary forms, diff --git a/README.md b/README.md index 468b28b..9d323c5 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ Stable, fast, robust, and well-maintained Meteor.js package for files management - [Stream files](https://github.com/VeliovGroup/Meteor-Files#stream-files) - [Download Button](https://github.com/VeliovGroup/Meteor-Files#download-button) - [Documentation and tutorials](https://github.com/VeliovGroup/Meteor-Files/blob/master/docs/toc.md) + - [__Demo apps and examples__](https://github.com/VeliovGroup/Meteor-Files#demo-application) - [3rd-party storage integration](https://github.com/VeliovGroup/Meteor-Files/blob/master/docs/3rd-party-storage.md) examples - AWS S3, DropBox, GridFS and Google Storage - [TypeScript Definitions](https://github.com/VeliovGroup/Meteor-Files/blob/master/docs/typescript-definitions.md) - - [Demo apps and examples](https://github.com/VeliovGroup/Meteor-Files#demo-application) - [Related Packages](https://github.com/VeliovGroup/Meteor-Files#related-packages) - [Why this package?](https://github.com/VeliovGroup/Meteor-Files#why-meteor-files) - [Help / Support](https://github.com/VeliovGroup/Meteor-Files#get-support) @@ -138,7 +138,6 @@ Template.uploadForm.events({ // multiple files were selected const upload = Images.insert({ file: e.currentTarget.files[0], - streams: 'dynamic', chunkSize: 'dynamic' }, false); @@ -311,7 +310,7 @@ For more expressive example see [Download demo](https://github.com/VeliovGroup/M 3. __How to pause/continue upload and get progress/speed/remaining time?__: see *Object* returned from [`insert` method](https://github.com/VeliovGroup/Meteor-Files/blob/master/docs/insert.md) 4. When using any of `accounts` packages - package `accounts-base` must be explicitly added to `.meteor/packages` above `ostrio:files` 5. __cURL/POST uploads__ - Take a look on [POST-Example](https://github.com/noris666/Meteor-Files-POST-Example) by [@noris666](https://github.com/noris666) -6. In __Safari__ (Mobile and Desktop) for `DDP` upload streams are hard-coded to `1` and chunk size is reduced by algorithm, due to error thrown if too many connection is open by the browser or frame is too big. Limit simultaneous uploads to `6` is recommended for Safari. This issue should be fixed in Safari 11. Switching to `http` transport (*which has no such issue*) is recommended for Safari. See [#458](https://github.com/VeliovGroup/Meteor-Files/issues/458) +6. In __Safari__ (Mobile and Desktop) for `DDP` chunk size is reduced by algorithm, due to error thrown if frame is too big. Limit simultaneous uploads to `6` is recommended for Safari. This issue should be fixed in Safari 11. Switching to `http` transport (*which has no such issue*) is recommended for Safari. See [#458](https://github.com/VeliovGroup/Meteor-Files/issues/458) 7. Make sure you're using single domain for the Meteor app, and the same domain for hosting Meteor-Files endpoints, see [#737](https://github.com/VeliovGroup/Meteor-Files/issues/737) for details 8. When proxying requests to Meteor-Files endpoint make sure protocol `http/1.1` is used, see [#742](https://github.com/VeliovGroup/Meteor-Files/issues/742) for details @@ -331,9 +330,7 @@ For more expressive example see [Download demo](https://github.com/VeliovGroup/M ## Demo application: - [Live: __files.veliov.com__](https://files.veliov.com) -- [Source Code Rep](https://github.com/VeliovGroup/Meteor-Files-Demos/tree/master/demo) -- [Compiled Rep](https://github.com/VeliovGroup/Meteor-Files-Demo) -- [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/VeliovGroup/Meteor-Files-Demo) +- [Source Code Rep](https://github.com/veliovgroup/meteor-files-website#file-sharing-web-app) ## Related Packages: diff --git a/client.js b/client.js index 653a251..4010f45 100644 --- a/client.js +++ b/client.js @@ -1,9 +1,9 @@ -import { Mongo } from 'meteor/mongo'; -import { Meteor } from 'meteor/meteor'; -import { DDP } from 'meteor/ddp-client'; -import { Cookies } from 'meteor/ostrio:cookies'; -import { check, Match } from 'meteor/check'; -import { UploadInstance } from './upload.js'; +import { DDP } from 'meteor/ddp-client'; +import { Mongo } from 'meteor/mongo'; +import { Meteor } from 'meteor/meteor'; +import { Cookies } from 'meteor/ostrio:cookies'; +import { check, Match } from 'meteor/check'; +import { UploadInstance } from './upload.js'; import FilesCollectionCore from './core.js'; import { formatFleURL, helpers } from './lib.js'; @@ -130,10 +130,10 @@ export class FilesCollection extends FilesCollectionCore { const _URL = window.URL || window.webkitURL || window.mozURL || window.msURL || window.oURL || false; if (window.Worker && window.Blob && _URL && helpers.isFunction(_URL.createObjectURL)) { this._supportWebWorker = true; - this._webWorkerUrl = _URL.createObjectURL(new window.Blob(['!function(a){"use strict";a.onmessage=function(b){var c=b.data.f.slice(b.data.cs*(b.data.cc-1),b.data.cs*b.data.cc);if(b.data.ib===!0)postMessage({bin:c,chunkId:b.data.cc});else{var d;a.FileReader?(d=new FileReader,d.onloadend=function(a){postMessage({bin:(d.result||a.srcElement||a.target).split(",")[1],chunkId:b.data.cc,s:b.data.s})},d.onerror=function(a){throw(a.target||a.srcElement).error},d.readAsDataURL(c)):a.FileReaderSync?(d=new FileReaderSync,postMessage({bin:d.readAsDataURL(c).split(",")[1],chunkId:b.data.cc})):postMessage({bin:null,chunkId:b.data.cc,error:"File API is not supported in WebWorker!"})}}}(this);'], {type: 'application/javascript'})); + this._webWorkerUrl = _URL.createObjectURL(new window.Blob(['!function(a){"use strict";a.onmessage=function(b){var c=b.data.f.slice(b.data.cs*(b.data.cc-1),b.data.cs*b.data.cc);if(b.data.ib===!0)postMessage({bin:c,chunkId:b.data.cc});else{var d;a.FileReader?(d=new FileReader,d.onloadend=function(a){postMessage({bin:(d.result||a.srcElement||a.target).split(",")[1],chunkId:b.data.cc,s:b.data.s})},d.onerror=function(a){throw(a.target||a.srcElement).error},d.readAsDataURL(c)):a.FileReaderSync?(d=new FileReaderSync,postMessage({bin:d.readAsDataURL(c).split(",")[1],chunkId:b.data.cc})):postMessage({bin:null,chunkId:b.data.cc,error:"File API is not supported in WebWorker!"})}}}(this);'], {type: 'application/javascript'})); } else if (window.Worker) { this._supportWebWorker = true; - this._webWorkerUrl = Meteor.absoluteUrl('packages/ostrio_files/worker.min.js'); + this._webWorkerUrl = Meteor.absoluteUrl('packages/ostrio_files/worker.min.js'); } else { this._supportWebWorker = false; } @@ -219,7 +219,6 @@ export class FilesCollection extends FilesCollectionCore { * {String} fileId - Optionnal `fileId` used at insert * {Object} meta - Additional data as object, use later for search * {Boolean} allowWebWorkers- Allow/Deny WebWorkers usage - * {Number|dynamic} streams - Quantity of parallel upload streams, default: 2 * {Number|dynamic} chunkSize - Chunk size for upload * {String} transport - Upload transport `http` or `ddp` * {Object} ddp - Custom DDP connection. Object returned form `DDP.connect()` diff --git a/core.js b/core.js index a5e236c..a0209df 100644 --- a/core.js +++ b/core.js @@ -1,6 +1,6 @@ -import { EventEmitter } from 'eventemitter3'; -import { check, Match } from 'meteor/check'; -import { formatFleURL, helpers } from './lib.js'; +import { EventEmitter } from 'eventemitter3'; +import { check, Match } from 'meteor/check'; +import { formatFleURL, helpers } from './lib.js'; import { FilesCursor, FileCursor } from './cursor.js'; export default class FilesCollectionCore extends EventEmitter { @@ -149,12 +149,12 @@ export default class FilesCollectionCore extends EventEmitter { * @summary Internal method. Classify file based on 'type' field */ _updateFileTypes(data) { - data.isVideo = /^video\//i.test(data.type); - data.isAudio = /^audio\//i.test(data.type); - data.isImage = /^image\//i.test(data.type); - data.isText = /^text\//i.test(data.type); - data.isJSON = /^application\/json$/i.test(data.type); - data.isPDF = /^application\/(x-)?pdf$/i.test(data.type); + data.isVideo = /^video\//i.test(data.type); + data.isAudio = /^audio\//i.test(data.type); + data.isImage = /^image\//i.test(data.type); + data.isText = /^text\//i.test(data.type); + data.isJSON = /^application\/json$/i.test(data.type); + data.isPDF = /^application\/(x-)?pdf$/i.test(data.type); } /* diff --git a/docs/about-transports.md b/docs/about-transports.md index 0560903..a12d020 100644 --- a/docs/about-transports.md +++ b/docs/about-transports.md @@ -48,4 +48,3 @@ The cons: - No mobile browsers support; - Chunk size limited to 64KB; -- Only single stream is supported (*so, it's currently uses synchronous chunk uploads*. If `RTC/DC` will be accepted by community we will implement asynchronous chunks upload). diff --git a/docs/constructor.md b/docs/constructor.md index f2e62c4..4054ceb 100644 --- a/docs/constructor.md +++ b/docs/constructor.md @@ -220,7 +220,7 @@ Isomorphic - Upload & Serve (for 206 responce) chunk size + Upload & Serve (for 206 response) chunk size 272144 diff --git a/docs/dropbox-integration.md b/docs/dropbox-integration.md index e86ec14..07ad7ba 100644 --- a/docs/dropbox-integration.md +++ b/docs/dropbox-integration.md @@ -3,7 +3,8 @@ Example below shows how to store and serve uploaded file via DropBox. This example also covers file removing from both your application and DropBox. ## Prerequisite -We will use next packages: Request (NPM), Node-fetch (NPM) and Underscore (meteor) + +We will use next packages: request (NPM), Node-fetch (NPM) and Underscore (meteor) ```shell meteor npm install request @@ -24,17 +25,18 @@ meteor npm install dropbox@=4.0.30 ``` ### Step 2: Get access to DropBox API: - - Go to https://www.dropbox.com/developers (*Sign(in|up) if required*) - - Click on [Create your app](https://www.dropbox.com/developers/apps/create) - - Choose "*Dropbox API*" - - Choose "*App folder*" - - Type-in your application name - - Go to you application's *settings* - - Click on "*Enable additional users*" - - Obtain "*Generated access token*" (Click on "*Generate Access token*") for `accessToken` in `new Dropbox({})` + +- Go to [DropBox Developers](https://www.dropbox.com/developers) (*Sign(in|up) if required*) +- Click on [Create your app](https://www.dropbox.com/developers/apps/create) +- Choose "*Dropbox API*" +- Choose "*App folder*" +- Type-in your application name +- Go to you application's *settings* +- Click on "*Enable additional users*" +- Obtain "*Generated access token*" (Click on "*Generate Access token*") for `accessToken` in `new Dropbox({})` ```javascript -var Dropbox, Request, bound, client, fs, Collections = {}; +var Dropbox, request, bound, client, fs, Collections = {}; if(Meteor.isServer){ Dropbox = require('dropbox').Dropbox; @@ -48,7 +50,7 @@ if(Meteor.isServer){ }); } -Request = require('request'); +request = require('request'); fs = require('fs'); Collections.files = new FilesCollection({ @@ -84,7 +86,7 @@ Collections.files = new FilesCollection({ console.error(error); }); }; - + var writeToDB = function(fileRef, version, data){ // DropBox already uses random URLs // No need to use random file names @@ -116,7 +118,7 @@ Collections.files = new FilesCollection({ readFile(fileRef, vRef, version); }); }; - + sendToStorage(fileRef); } catch(error){ // There was an error while uploading the file to Dropbox, displaying the concerned file @@ -148,7 +150,7 @@ Collections.files = new FilesCollection({ // If file is moved to DropBox // We will pipe request to DropBox // So, original link will stay always secure - Request({ + request({ url: path, headers: _.pick(http.request.headers, 'range', 'accept-language', 'accept', 'cache-control', 'pragma', 'connection', 'upgrade-insecure-requests', 'user-agent') }).on('response', function(response){ diff --git a/docs/file-subversions.md b/docs/file-subversions.md index a366476..8bb0837 100644 --- a/docs/file-subversions.md +++ b/docs/file-subversions.md @@ -57,8 +57,7 @@ if (Meteor.isClient) { } else { return "Please upload file in next formats: 'ogg', 'mp4', 'avi', 'webm' with size less than 512 Mb. You have tried to upload file with \"" + this.ext + "\" extension and with \"" + (Math.round((this.size / (1024 * 1024)) * 100) / 100) + "\" Mb"; } - }, - streams: 8 + } }); }); } diff --git a/docs/image-processing.md b/docs/image-processing.md index 1d9802f..01dcbd0 100644 --- a/docs/image-processing.md +++ b/docs/image-processing.md @@ -1,19 +1,22 @@ -### Create thumbnails after upload +# Create thumbnails after upload At this tutorial we will create thumbnails with GraphicksMagick/ImageMagick (*a.k.a. `gm`/`im`*) after file is fully uploaded to Server. Note: GraphicksMagick or ImageMagick should be installed on dev/prod machine before you implement code below. Links: - - [GraphicksMagick](https://sourceforge.net/projects/graphicsmagick/) - - [ImageMagick](https://www.imagemagick.org/script/download.php) - - See how this example used in [real-life production code](https://github.com/VeliovGroup/Meteor-Files-Demos/blob/master/demo/imports/server/image-processing.js#L19) - - [gm](https://www.npmjs.com/package/gm) NPM package - - [im](https://www.npmjs.com/package/im) NPM package - - [imagemagick-native](https://www.npmjs.com/package/imagemagick-native) NPM package - -### Install image library + +- [GraphicksMagick](https://sourceforge.net/projects/graphicsmagick/) +- [ImageMagick](https://www.imagemagick.org/script/download.php) +- See how this example [used in our demo app](https://github.com/veliovgroup/meteor-files-website/blob/master/imports/server/image-processing.js) +- [gm](https://www.npmjs.com/package/gm) NPM package +- [im](https://www.npmjs.com/package/im) NPM package +- [imagemagick-native](https://www.npmjs.com/package/imagemagick-native) NPM package + +## Install image library + __TL;TR;__ - There is various software solutions to accomplish this task. All links to make a decision is above. If you don't have time to deal with a choice - install [GraphicksMagick](https://sourceforge.net/projects/graphicsmagick/) as a library and [gm](https://www.npmjs.com/package/gm) as NPM package. Before you go - install ImageMagick or GraphicksMagick CLI tools. There are numerous ways to install it. For instance, if you're on OS X you can use Homebrew: + ```shell brew install graphicsmagick # or for ImageMagick: @@ -21,26 +24,32 @@ brew install graphicsmagick ``` Some platforms may bundle ImageMagick into their tools (like Heroku). In this case you may use GraphicsMagick as ImageMagick in this way: + ```shell npm install gm --save +``` + +And then where you use it: -And then where you use it: -```jsx -const gm = require('gm'); +```js +const gm = require('gm'); const im = gm.subClass({ imageMagick: true }); ``` Please note that GM was considered slightly faster than IM so before you chose convenience over performance read the latest news about it, - [see the comparison](https://mazira.com/blog/comparing-speed-imagemagick-graphicsmagick). -### Install Meteor/NPM packages +## Install Meteor/NPM packages + ```shell meteor add ostrio:files meteor npm install --save gm fs-extra ``` -### Create FilesCollection +## Create FilesCollection + Initiate *FilesCollection* (`/lib/files.js`): -```jsx + +```js import { FilesCollection } from 'meteor/ostrio:files'; const uploadsCollection = new FilesCollection({ @@ -50,22 +59,25 @@ const uploadsCollection = new FilesCollection({ export default uploadsCollection; ``` -### Upload form example +## Upload form example + Simple upload form (`/client/upload.html`): -```html + +```handlebars ``` Simple upload form (`/client/upload.js`): -```jsx + +```js import { Template } from 'meteor/templating'; import { ReactiveVar } from 'meteor/reactive-var'; @@ -83,11 +95,10 @@ Template.uploadForm.helpers({ }); Template.uploadForm.events({ - 'change #fileInput'(e, template) { + 'change [data-upload-file]'(e, template) { if (e.currentTarget.files && e.currentTarget.files[0]) { const uploader = uploadsCollection.insert({ file: e.currentTarget.files[0], - streams: 'dynamic', chunkSize: 'dynamic' }, false); @@ -115,9 +126,11 @@ Template.uploadForm.events({ }); ``` -### Catch uploaded files +## Catch uploaded files + Catch `afterUpload` event (`/server/files.js`): -```jsx + +```js import uploadsCollection from '/lib/files.js'; import createThumbnails from '/server/image-processing.js'; @@ -133,9 +146,11 @@ uploadsCollection.on('afterUpload', function(fileRef) { }); ``` -### Process uploaded images +## Process uploaded images + Create thumbnails (`/server/image-processing.js`): -```jsx + +```js import { check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; @@ -175,7 +190,7 @@ const createThumbnails = (collection, fileRef, cb) => { } }); - const path = (collection.storagePath(fileRef)) + '/thumbnail-' + fileRef._id + '.' + fileRef.extension; + const path = `${collection.storagePath(fileRef)}/thumbnail-${fileRef._id}.${fileRef.extension}`; const img = gm(fileRef.path) .quality(70) .define('filter:support=2') @@ -222,15 +237,18 @@ const createThumbnails = (collection, fileRef, cb) => { size: stat.size, type: fileRef.type, extension: fileRef.extension, - name: fileRef.name, // <-- Name with extension used if file's version is being downloaded + name: fileRef.name, // <-- Name with extension used when file's version is being downloaded meta: { width: imgInfo.width, height: imgInfo.height } }; - const upd = { $set: {} }; - upd['$set']['versions.thumbnail'] = fileRef.versions.thumbnail; + const upd = { + $set: { + 'versions.thumbnail': fileRef.versions.thumbnail + } + }; collection.collection.update(fileRef._id, upd, (colUpdError) => { if (cb) { diff --git a/docs/insert.md b/docs/insert.md index 9639403..5ed901c 100644 --- a/docs/insert.md +++ b/docs/insert.md @@ -204,17 +204,6 @@ Upload file to a Server via DDP or HTTP. - - - `settings.streams` {*Number*|dynamic} - - - Quantity of parallel upload streams - - - `dynamic` is recommended - - `settings.chunkSize` {*Number*|dynamic} @@ -619,7 +608,6 @@ Template.uploadForm.events({ } template.currentFile.set(false); }, - streams: 'dynamic', chunkSize: 'dynamic' }); } @@ -642,7 +630,6 @@ Template.uploadForm.events({ // multiple files were selected Images.insert({ file: e.currentTarget.files[0], - streams: 'dynamic', chunkSize: 'dynamic' }, false).on('start', function () { template.currentFile.set(this); @@ -672,7 +659,6 @@ Template.uploadForm.events({ if (e.currentTarget.files && e.currentTarget.files[0]) { const uploader = Images.insert({ file: e.currentTarget.files[0], - streams: 'dynamic', chunkSize: 'dynamic' }, false); @@ -751,7 +737,6 @@ Template.uploadForm.events({ // multiple files were selected Images.insert({ file: e.currentTarget.files[0], - streams: 'dynamic', chunkSize: 'dynamic' }, false).pipe(encrypt).pipe(zip).start(); } diff --git a/docs/load.md b/docs/load.md index c908a22..bd84cca 100644 --- a/docs/load.md +++ b/docs/load.md @@ -1,27 +1,43 @@ -### `load(url [, opts, callback, proceedAfterUpload])` [*Server*] +# Download remote file over HTTP -Write file to FS from remote URL (external resource) and add record to FilesCollection +Download remote file over HTTP to the file system of a *Server*. Download is efficient, runs in chunks writing data as available directly to FS via stream without holding it in RAM. If error or timeout occurred — unfinished file will get removed from file system. -- `url` {*String*} - Full address to file, like `scheme://example.com/sample.png` +```js +/* + * @locus Server + */ + +FilesCollection#load(url [, opts, callback, proceedAfterUpload]); +``` + +Write file to file system from remote URL (external resource) and add record to FilesCollection + +- `url` {*String*} - Full address to file, like `https://example.com/sample.png` - `opts` {*Object*} - Recommended properties: - `opts.fileName` {*String*} - File name with extension, like `name.ext` - `opts.headers` {*Object*} - Request HTTP headers, to use when requesting the file - `opts.meta` {*Object*} - Object with custom meta-data - `opts.type` {*String*} - Mime-type, like `image/png`, if not set - mime-type will be taken from response headers - `opts.size` {*Number*} - File size in bytes, if not set - file size will be taken from response headers - - `opts.userId` {*String*} - UserId, default *null* + - `opts.userId` {*String*} - UserId, default: `null` - `opts.fileId` {*String*} - id, optional - if not set - Random.id() will be used + - `opts.timeout` {*Number*} - timeout in milliseconds, default: `360000` (*6 mins*); Set to `0` to disable timeout; *Disabling timeout not recommended, sockets won't get closed until server rebooted* - `callback` {*Function*} - Triggered after first byte is received. With `error`, and `fileRef`, where `fileRef` is a new record from DB - proceedAfterUpload {*Boolean*} - Proceed `onAfterUpload` hook (*if defined*) after external source is loaded to FS - Returns {*FilesCollection*} - Current FilesCollection instance ```js +/* + * @locus Server + */ + import { FilesCollection } from 'meteor/ostrio:files'; const Images = new FilesCollection({collectionName: 'Images'}); Images.load('https://raw.githubusercontent.com/VeliovGroup/Meteor-Files/master/logo.png', { fileName: 'logo.png', fileId: 'abc123myId', //optional + timeout: 60000, // optional timeout meta: {} }); ``` diff --git a/docs/react-example.md b/docs/react-example.md index f36e9e0..74c3a81 100644 --- a/docs/react-example.md +++ b/docs/react-example.md @@ -66,7 +66,6 @@ class FileUploadComponent extends Component { locator: self.props.fileLocator, userId: Meteor.userId() // Optional, used to check on server for file tampering }, - streams: 'dynamic', chunkSize: 'dynamic', allowWebWorkers: true // If you see issues with uploads, change this to false }, false) diff --git a/docs/typescript-definitions.md b/docs/typescript-definitions.md index 57bae7e..e1d1f11 100644 --- a/docs/typescript-definitions.md +++ b/docs/typescript-definitions.md @@ -145,7 +145,6 @@ declare module "meteor/ostrio:files" { onError?: (error: Meteor.Error, fileData: FileData) => any; onProgress?: (progress: number, fileData: FileData) => any; onBeforeUpload?: (fileData: FileData) => any; - streams?: number | 'dynamic'; chunkSize?: number | 'dynamic'; allowWebWorkers?: boolean; type?: string; diff --git a/docs/write.md b/docs/write.md index b0caca7..7512f82 100644 --- a/docs/write.md +++ b/docs/write.md @@ -26,7 +26,7 @@ fs.readFile('/data/imgs/sample.png', (error, data) => { } else { Images.write(data, { fileName: 'sample.png', - fielId: 'abc123myId', //optional + fileId: 'abc123myId', //optional type: 'image/png' }, (writeError, fileRef) => { if (writeError) { diff --git a/index.d.ts b/index.d.ts index fdd185e..6c3024d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -142,7 +142,6 @@ declare module "meteor/ostrio:files" { onError?: (error: Meteor.Error, fileData: FileData) => any; onProgress?: (progress: number, fileData: FileData) => any; onBeforeUpload?: (fileData: FileData) => any; - streams?: number | 'dynamic'; chunkSize?: number | 'dynamic'; allowWebWorkers?: boolean; type?: string; diff --git a/lib.js b/lib.js index 3f8b93a..804cd48 100644 --- a/lib.js +++ b/lib.js @@ -200,7 +200,7 @@ const formatFleURL = (fileRef, version = 'original', _URIBase = (__meteor_runtim if (fileRef.public === true) { return _root + (version === 'original' ? `${fileRef._downloadRoute}/${fileRef._id}${ext}` : `${fileRef._downloadRoute}/${version}-${fileRef._id}${ext}`); } - return _root + `${fileRef._downloadRoute}/${fileRef._collectionName}/${fileRef._id}/${version}/${fileRef._id}${ext}`; + return `${_root}${fileRef._downloadRoute}/${fileRef._collectionName}/${fileRef._id}/${version}/${fileRef._id}${ext}`; }; export { fixJSONParse, fixJSONStringify, formatFleURL, helpers }; diff --git a/package.js b/package.js index 5734350..5ab99a4 100755 --- a/package.js +++ b/package.js @@ -1,23 +1,22 @@ Package.describe({ name: 'ostrio:files', - version: '1.14.3', + version: '2.0.0', summary: 'Upload files to Meteor application, with 3rd party storage support: AWS:S3, GridFS and other', git: 'https://github.com/VeliovGroup/Meteor-Files', documentation: 'README.md' }); Npm.depends({ - 'fs-extra': '9.0.1', - 'request-libcurl': '2.2.1', - 'file-type': '16.0.0', - eventemitter3: '4.0.7' + 'fs-extra': '9.1.0', + eventemitter3: '4.0.7', + 'abort-controller': '3.0.0' }); Package.onUse(function(api) { api.versionsFrom('1.9'); api.use('webapp', 'server'); - api.use(['reactive-var', 'tracker', 'http', 'ddp-client'], 'client'); - api.use(['mongo', 'check', 'random', 'ecmascript', 'ostrio:cookies@2.6.1'], ['client', 'server']); + api.use(['reactive-var', 'tracker', 'ddp-client'], 'client'); + api.use(['mongo', 'check', 'random', 'ecmascript', 'fetch', 'ostrio:cookies@2.7.0'], ['client', 'server']); api.addAssets('worker.min.js', 'client'); api.mainModule('server.js', 'server'); api.mainModule('client.js', 'client'); diff --git a/server.js b/server.js index 2bc275a..98e2a9a 100644 --- a/server.js +++ b/server.js @@ -1,17 +1,18 @@ -import { Mongo } from 'meteor/mongo'; -import { WebApp } from 'meteor/webapp'; -import { Meteor } from 'meteor/meteor'; -import { Random } from 'meteor/random'; -import { Cookies } from 'meteor/ostrio:cookies'; -import WriteStream from './write-stream.js'; -import { check, Match } from 'meteor/check'; +import { Mongo } from 'meteor/mongo'; +import { fetch } from 'meteor/fetch'; +import { WebApp } from 'meteor/webapp'; +import { Meteor } from 'meteor/meteor'; +import { Random } from 'meteor/random'; +import { Cookies } from 'meteor/ostrio:cookies'; +import { check, Match } from 'meteor/check'; + +import WriteStream from './write-stream.js'; import FilesCollectionCore from './core.js'; import { fixJSONParse, fixJSONStringify, helpers } from './lib.js'; -import fs from 'fs-extra'; -import nodeQs from 'querystring'; -import request from 'request-libcurl'; -import fileType from 'file-type'; +import AbortController from 'abort-controller'; +import fs from 'fs-extra'; +import nodeQs from 'querystring'; import nodePath from 'path'; /* @@ -518,6 +519,7 @@ export class FilesCollection extends FilesCollectionCore { } if (httpReq.headers['x-start'] !== '1') { + // CHUNK UPLOAD SCENARIO: opts = { fileId: httpReq.headers['x-fileid'] }; @@ -537,6 +539,7 @@ export class FilesCollection extends FilesCollectionCore { ({result, opts} = this._prepareUpload(Object.assign(opts, _continueUpload), user.userId, 'HTTP')); if (opts.eof) { + // FINISH UPLOAD SCENARIO: this._handleUpload(result, opts, (_error) => { let error = _error; if (error) { @@ -581,6 +584,7 @@ export class FilesCollection extends FilesCollectionCore { httpResp.end(); } } else { + // START SCENARIO: try { opts = JSON.parse(body); } catch (jsonErr) { @@ -592,19 +596,19 @@ export class FilesCollection extends FilesCollectionCore { opts.file = {}; } - opts.___s = true; this._debug(`[FilesCollection] [File Start HTTP] ${opts.file.name || '[no-name]'} - ${opts.fileId}`); if (helpers.isObject(opts.file) && opts.file.meta) { opts.file.meta = fixJSONParse(opts.file.meta); } + opts.___s = true; ({result} = this._prepareUpload(helpers.clone(opts), user.userId, 'HTTP Start Method')); if (this.collection.findOne(result._id)) { throw new Meteor.Error(400, 'Can\'t start upload, data substitution detected!'); } - opts._id = opts.fileId; + opts._id = opts.fileId; opts.createdAt = new Date(); opts.maxLength = opts.fileLength; this._preCollection.insert(helpers.omit(opts, '___s')); @@ -1041,21 +1045,6 @@ export class FilesCollection extends FilesCollectionCore { mime = fileData.type; } - if (fileData.path && (!mime || !helpers.isString(mime))) { - try { - let buf = Buffer.alloc(262); - const fd = fs.openSync(fileData.path, 'r'); - const br = fs.readSync(fd, buf, 0, 262, 0); - fs.close(fd, NOOP); - if (br < 262) { - buf = buf.slice(0, br); - } - ({mime} = fileType(buf)); - } catch (e) { - // We're good - } - } - if (!mime || !helpers.isString(mime)) { mime = 'application/octet-stream'; } @@ -1229,19 +1218,20 @@ export class FilesCollection extends FilesCollectionCore { * @memberOf FilesCollection * @name load * @param {String} url - URL to file - * @param {Object} opts - Object with file-data + * @param {Object} [opts] - Object with file-data * @param {Object} opts.headers - HTTP headers to use when requesting the file * @param {String} opts.name - File name, alias: `fileName` * @param {String} opts.type - File mime-type * @param {Object} opts.meta - File additional meta-data * @param {String} opts.userId - UserId, default *null* * @param {String} opts.fileId - _id, default *null* + * @param {Number} opts.timeout - Timeout in milliseconds, default: 360000 (6 mins) * @param {Function} callback - function(error, fileObj){...} - * @param {Boolean} proceedAfterUpload - Proceed onAfterUpload hook - * @summary Download file, write stream to FS and add to FilesCollection Collection + * @param {Boolean} [proceedAfterUpload] - Proceed onAfterUpload hook + * @summary Download file over HTTP, write stream to FS, and add to FilesCollection Collection * @returns {FilesCollection} Instance */ - load(url, _opts = {}, _callback, _proceedAfterUpload) { + load(url, _opts = {}, _callback, _proceedAfterUpload = false) { this._debug(`[FilesCollection] [load(${url}, ${JSON.stringify(_opts)}, callback)]`); let opts = _opts; let callback = _callback; @@ -1250,7 +1240,7 @@ export class FilesCollection extends FilesCollectionCore { if (helpers.isFunction(opts)) { proceedAfterUpload = callback; callback = opts; - opts = {}; + opts = {}; } else if (helpers.isBoolean(callback)) { proceedAfterUpload = callback; } else if (helpers.isBoolean(opts)) { @@ -1263,13 +1253,19 @@ export class FilesCollection extends FilesCollectionCore { check(proceedAfterUpload, Match.Optional(Boolean)); if (!helpers.isObject(opts)) { - opts = {}; + opts = { + timeout: 360000 + }; + } + + if (!opts.timeout) { + opts.timeout = 360000; } - const fileId = opts.fileId || Random.id(); - const FSName = this.namingFunction ? this.namingFunction(opts) : fileId; + const fileId = opts.fileId || Random.id(); + const FSName = this.namingFunction ? this.namingFunction(opts) : fileId; const pathParts = url.split('/'); - const fileName = (opts.name || opts.fileName) ? (opts.name || opts.fileName) : pathParts[pathParts.length - 1] || FSName; + const fileName = (opts.name || opts.fileName) ? (opts.name || opts.fileName) : pathParts[pathParts.length - 1].split('?')[0] || FSName; const {extension, extensionWithDot} = this._getExt(fileName); opts.path = `${this.storagePath(opts)}${nodePath.sep}${FSName}${extensionWithDot}`; @@ -1299,45 +1295,106 @@ export class FilesCollection extends FilesCollectionCore { callback && callback(efError); this._debug(`[FilesCollection] [load] [ensureFile] [Error:] ${fileName} -> ${opts.path}`, efError); } else { - request({ - url, - headers: opts.headers || {}, - wait: true - }, (reqError, response) => bound(() => { - if (reqError) { - callback && callback(reqError); - this._debug(`[FilesCollection] [load] [request.get(${url})] Error:`, reqError); - } else { - this._debug(`[FilesCollection] [load] Received: ${url}`); - const result = this._dataToSchema({ - name: fileName, - path: opts.path, - meta: opts.meta, - type: opts.type || response.headers['content-type'] || this._getMimeType({path: opts.path}), - size: opts.size || parseInt(response.headers['content-length'] || 0), - userId: opts.userId, - extension - }); + let isEnded = false; + let timer = null; + const wStream = fs.createWriteStream(opts.path, {flags: 'w', mode: this.permissions, autoClose: true, emitClose: false }); + const onEnd = (_error, response) => { + if (!isEnded) { + if (timer) { + Meteor.clearTimeout(timer); + timer = null; + } - if (!result.size) { - fs.stat(opts.path, (error, stats) => bound(() => { - if (error) { - callback && callback(error); - } else { - result.versions.original.size = (result.size = stats.size); - storeResult(result, callback); - } - })); + isEnded = true; + if (response && response.status === 200) { + this._debug(`[FilesCollection] [load] Received: ${url}`); + const result = this._dataToSchema({ + name: fileName, + path: opts.path, + meta: opts.meta, + type: opts.type || response.headers.get('content-type') || this._getMimeType({path: opts.path}), + size: opts.size || parseInt(response.headers.get('content-length') || 0), + userId: opts.userId, + extension + }); + + if (!result.size) { + fs.stat(opts.path, (statError, stats) => { + bound(() => { + if (statError) { + callback && callback(statError); + } else { + result.versions.original.size = (result.size = stats.size); + storeResult(result, callback); + } + }); + }); + } else { + storeResult(result, callback); + } } else { - storeResult(result, callback); + const error = _error || new Meteor.Error(response?.status || 408, response?.statusText || 'Bad response with empty details'); + this._debug(`[FilesCollection] [load] [fetch(${url})] Error:`, error); + + if (!wStream.destroyed) { + wStream.destroy(); + } + + fs.remove(opts.path, (removeError) => { + bound(() => { + callback && callback(error); + if (removeError) { + this._debug(`[FilesCollection] [load] [fetch(${url})] [fs.remove(${opts.path})] removeError:`, removeError); + } + }); + }); } } - })).pipe(fs.createWriteStream(opts.path, {flags: 'w', mode: this.permissions})).send(); + }; + + let resp = void 0; + wStream.on('error', (error) => { + bound(() => { + onEnd(error); + }); + }); + wStream.on('close', () => { + bound(() => { + onEnd(void 0, resp); + }); + }); + wStream.on('finish', () => { + bound(() => { + onEnd(void 0, resp); + }); + }); + + const controller = new AbortController(); + fetch(url, { + headers: opts.headers || {}, + signal: controller.signal + }).then((res) => { + resp = res; + res.body.on('error', (error) => { + bound(() => { + onEnd(error); + }); + }); + res.body.pipe(wStream); + }).catch((fetchError) => { + onEnd(fetchError); + }); + + if (opts.timeout > 0) { + timer = Meteor.setTimeout(() => { + onEnd(new Meteor.Error(408, `Request timeout after ${opts.timeout}ms`)); + controller.abort(); + }, opts.timeout); + } } }); }); - return this; } diff --git a/upload.js b/upload.js index ac54afc..cc79422 100644 --- a/upload.js +++ b/upload.js @@ -1,8 +1,8 @@ -import { HTTP } from 'meteor/http'; -import { Meteor } from 'meteor/meteor'; -import { Random } from 'meteor/random'; -import { Tracker } from 'meteor/tracker'; -import { ReactiveVar } from 'meteor/reactive-var'; +import { fetch } from 'meteor/fetch'; +import { Meteor } from 'meteor/meteor'; +import { Random } from 'meteor/random'; +import { Tracker } from 'meteor/tracker'; +import { ReactiveVar } from 'meteor/reactive-var'; import { EventEmitter } from 'eventemitter3'; import { check, Match } from 'meteor/check'; import { fixJSONParse, fixJSONStringify, helpers } from './lib.js'; @@ -23,15 +23,16 @@ export class FileUpload extends EventEmitter { this.config._debug('[FilesCollection] [FileUpload] [constructor]'); if (!this.config.isBase64) { - this.file = Object.assign({}, helpers.clone(this.config.file), this.config.fileData); + this.file = Object.assign({}, helpers.clone(this.config.file), this.config.fileData); } else { - this.file = this.config.fileData; + this.file = this.config.fileData; } - this.state = new ReactiveVar('active'); - this.onPause = new ReactiveVar(false); - this.progress = new ReactiveVar(0); - this.continueFunc = () => { }; - this.estimateTime = new ReactiveVar(1000); + + this.state = new ReactiveVar('active'); + this.onPause = new ReactiveVar(false); + this.progress = new ReactiveVar(0); + this.continueFunc = () => {}; + this.estimateTime = new ReactiveVar(1000); this.estimateSpeed = new ReactiveVar(0); this.estimateTimer = Meteor.setInterval(() => { if (this.state.get() === 'active') { @@ -52,7 +53,7 @@ export class FileUpload extends EventEmitter { } continue() { this.config._debug('[FilesCollection] [insert] [.continue()]'); - if (this.onPause.get()) { + if (this.onPause.get() && Meteor.status().connected) { this.onPause.set(false); this.state.set('active'); this.emit('continue', this.file); @@ -104,14 +105,6 @@ export class UploadInstance extends EventEmitter { this.config.meta = {}; } - if (!this.config.streams) { - this.config.streams = 2; - } - - if (this.config.streams < 1) { - this.config.streams = 2; - } - if (!helpers.isString(this.config.transport)) { this.config.transport = 'ddp'; } @@ -138,7 +131,6 @@ export class UploadInstance extends EventEmitter { type: Match.Optional(String), onError: Match.Optional(Function), onAbort: Match.Optional(Function), - streams: Match.OneOf('dynamic', Number), onStart: Match.Optional(Function), fileName: Match.Optional(String), isBase64: Match.Optional(Boolean), @@ -219,7 +211,6 @@ export class UploadInstance extends EventEmitter { this.startTime = {}; this.config.debug = this.collection.debug; this.config._debug = this.collection._debug; - this.currentChunk = 0; this.transferTime = 0; this.trackerComp = null; this.sentChunks = 0; @@ -259,10 +250,9 @@ export class UploadInstance extends EventEmitter { this.addListener('prepare', this.prepare); this.addListener('sendChunk', this.sendChunk); this.addListener('proceedChunk', this.proceedChunk); - this.addListener('createStreams', this.createStreams); this.addListener('calculateStats', helpers.throttle(() => { - const _t = (this.transferTime / this.sentChunks) / this.config.streams; + const _t = (this.transferTime / (this.sentChunks || 1)); this.result.estimateTime.set((_t * (this.fileLength - this.sentChunks))); this.result.estimateSpeed.set((this.config.chunkSize / (_t / 1000))); @@ -361,53 +351,56 @@ export class UploadInstance extends EventEmitter { if (opts.binData) { if (this.config.transport === 'ddp') { this.config.ddp.call(this.collection._methodNames._Write, opts, (error) => { - this.transferTime += (+new Date) - this.startTime[opts.chunkId]; + this.transferTime += Date.now() - this.startTime[opts.chunkId]; if (error) { if (this.result.state.get() !== 'aborted') { this.emit('end', error); } } else { - ++this.sentChunks; - if (this.sentChunks >= this.fileLength) { + if (++this.sentChunks >= this.fileLength) { this.emit('sendEOF'); - } else if (this.currentChunk < this.fileLength) { + } else { this.emit('upload'); } this.emit('calculateStats'); } }); } else { - HTTP.call('POST', `${_rootUrl}${this.collection.downloadRoute}/${this.collection.collectionName}/__upload`, { - content: opts.binData, + fetch(`${_rootUrl}${this.collection.downloadRoute}/${this.collection.collectionName}/__upload`, { + method: 'POST', + body: opts.binData, + cache: 'no-cache', + credentials: 'include', + type: 'cors', headers: { 'x-mtok': (helpers.isObject(Meteor.connection) ? Meteor.connection._lastSessionId : void 0) || null, 'x-fileid': opts.fileId, 'x-chunkid': opts.chunkId, 'content-type': 'text/plain' - }, - beforeSend(xhr) { - xhr.withCredentials = true; - return true; } - }, (error) => { - this.transferTime += +new Date() - this.startTime[opts.chunkId]; - if (error) { - if (`${error}` === 'Error: network' || `${error}` === 'Error: Connection lost') { - this.result.pause(); - } else { - if (this.result.state.get() !== 'aborted') { - this.emit('end', error); - } - } - } else { - ++this.sentChunks; - if (this.sentChunks >= this.fileLength) { + }).then((response) => { + if (response.status === 204) { + this.collection._debug('[FilesCollection] [sendChunk] [fetch()] [then] chunk successfully sent'); + this.transferTime += Date.now() - this.startTime[opts.chunkId]; + if (++this.sentChunks >= this.fileLength) { this.emit('sendEOF'); - } else if (this.currentChunk < this.fileLength) { + } else { this.emit('upload'); } this.emit('calculateStats'); + } else { + this.emit('end', new Meteor.Error(response.status, 'Can\'t continue upload, session expired. Please, start upload again.')); } + }).catch((error) => { + this.collection._debug('[FilesCollection] [sendChunk] [fetch()] [error] EXCEPTION while sending chunk', error); + this.transferTime += Date.now() - this.startTime[opts.chunkId]; + Meteor.setTimeout(() => { + if (!Meteor.status().connected || `${error}` === 'Error: network' || `${error}` === 'Error: Connection lost') { + this.result.pause(); + } else if (this.result.state.get() !== 'aborted') { + this.emit('end', error); + } + }, 512); }); } } @@ -427,32 +420,33 @@ export class UploadInstance extends EventEmitter { this.emit('end', error, result); }); } else { - HTTP.call('POST', `${_rootUrl}${this.collection.downloadRoute}/${this.collection.collectionName}/__upload`, { - content: '', + fetch(`${_rootUrl}${this.collection.downloadRoute}/${this.collection.collectionName}/__upload`, { + method: 'POST', + body: '', + cache: 'no-cache', + credentials: 'include', + type: 'cors', headers: { 'x-eof': '1', 'x-mtok': (helpers.isObject(Meteor.connection) ? Meteor.connection._lastSessionId : void 0) || null, 'x-fileId': opts.fileId, 'content-type': 'text/plain' }, - beforeSend(xhr) { - xhr.withCredentials = true; - return true; - } - }, (error, _result) => { - let result; - try { - result = JSON.parse((helpers.isObject(_result) ? _result.content : void 0) || {}); - } catch (e) { - console.warn('Something went wrong! [sendEOF] method doesn\'t returned JSON! Looks like you\'re on Cordova app or behind proxy, switching to DDP transport is recommended.'); - result = {}; - } - + }).then((response) => response.json()).then((result) => { if (result.meta) { result.meta = fixJSONParse(result.meta); } - this.emit('end', error, result); + this.emit('end', void 0, result); + }).catch((error) => { + Meteor.setTimeout(() => { + if (!Meteor.status().connected || `${error}` === 'Error: network' || `${error}` === 'Error: Connection lost') { + this.result.pause(); + } else if (this.result.state.get() !== 'aborted') { + console.warn('Something went wrong! [sendEOF] method doesn\'t returned JSON! Looks like you\'re on Cordova app or behind proxy, switching to DDP transport is recommended.'); + this.emit('end', error); + } + }, 512); }); } } @@ -511,35 +505,24 @@ export class UploadInstance extends EventEmitter { return this; } - if (this.currentChunk <= this.fileLength) { - ++this.currentChunk; + if (this.sentChunks + 1 <= this.fileLength) { if (this.worker) { this.worker.postMessage({ f: this.config.file, - sc: this.sentChunks, - cc: this.currentChunk, + cc: this.sentChunks + 1, cs: this.config.chunkSize, ib: this.config.isBase64 }); } else { - this.emit('proceedChunk', this.currentChunk); + this.emit('proceedChunk', this.sentChunks + 1); } } else { this.emit('sendEOF'); } - this.startTime[this.currentChunk] = +new Date(); + this.startTime[this.sentChunks + 1] = Date.now(); return this; } - createStreams() { - this.collection._debug('[FilesCollection] [UploadInstance] [createStreams]'); - let i = 1; - while (i <= this.config.streams) { - this.emit('upload'); - i++; - } - } - prepare() { let _len; @@ -569,21 +552,7 @@ export class UploadInstance extends EventEmitter { _len = Math.ceil(this.fileData.size / this.config.chunkSize); } - if (this.config.streams === 'dynamic') { - this.config.streams = helpers.clone(_len); - if (this.config.streams > 24) { this.config.streams = 24; } - - if (this.config.transport === 'http') { - this.config.streams = Math.round(this.config.streams / 2); - } else if (isSafari) { - this.config.streams = 1; - } - } - this.fileLength = _len <= 0 ? 1 : _len; - if (this.config.streams > this.fileLength) { - this.config.streams = this.fileLength; - } this.result.config.fileLength = this.fileLength; const opts = { @@ -599,14 +568,20 @@ export class UploadInstance extends EventEmitter { const handleStart = (error) => { if (error) { - this.collection._debug('[FilesCollection] [_Start] Error:', error); - this.emit('end', error); + Meteor.setTimeout(() => { + if (!Meteor.status().connected || `${error}` === 'Error: network' || `${error}` === 'Error: Connection lost') { + this.result.pause(); + } else if (this.result.state.get() !== 'aborted') { + this.collection._debug('[FilesCollection] [_Start] Error:', error); + this.emit('end', error); + } + }, 512); } else { this.result.continueFunc = () => { this.collection._debug('[FilesCollection] [insert] [continueFunc]'); - this.emit('createStreams'); + this.emit('upload'); }; - this.emit('createStreams'); + this.emit('upload'); } }; @@ -617,17 +592,23 @@ export class UploadInstance extends EventEmitter { opts.file.meta = fixJSONStringify(opts.file.meta); } - HTTP.call('POST', `${_rootUrl}${this.collection.downloadRoute}/${this.collection.collectionName}/__upload`, { - data: opts, + fetch(`${_rootUrl}${this.collection.downloadRoute}/${this.collection.collectionName}/__upload`, { + method: 'POST', + body: JSON.stringify(opts), + cache: 'no-cache', + credentials: 'include', + type: 'cors', headers: { 'x-start': '1', 'x-mtok': (helpers.isObject(Meteor.connection) ? Meteor.connection._lastSessionId : void 0) || null - }, - beforeSend(xhr) { - xhr.withCredentials = true; - return true; } - }, handleStart); + }).then((response) => { + if (response.status === 204) { + handleStart(); + } else { + this.emit('end', new Meteor.Error(response.status, 'Can\'t start upload, make sure you\'re connected to the Internet. Reload the page or try again later.')); + } + }).catch(handleStart); } } @@ -662,6 +643,9 @@ export class UploadInstance extends EventEmitter { if (!this.result.onPause.curValue && !Meteor.status().connected) { this.collection._debug('[FilesCollection] [insert] [Tracker] [pause]'); this.result.pause(); + } else if (this.result.onPause.curValue && Meteor.status().connected) { + this.collection._debug('[FilesCollection] [insert] [Tracker] [continue]'); + this.result.continue(); } });