├── .eslintrc.js ├── .gitignore ├── LICENSE.md ├── README.md ├── apiClient.js ├── apiStore.js ├── index.js ├── lib ├── addonsDifferent.js └── memoryStorage.js ├── package-lock.json ├── package.json └── test └── test.js /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "node": true, 4 | "commonjs": true, 5 | "es6": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "parserOptions": { 9 | "ecmaVersion": 2018 10 | }, 11 | "rules": { 12 | "no-console": "off", 13 | "indent": [ 14 | "error", 15 | "tab" 16 | ], 17 | "linebreak-style": [ 18 | "error", 19 | "unix" 20 | ], 21 | "quotes": [ 22 | "error", 23 | "single" 24 | ], 25 | "semi": [ 26 | "error", 27 | "always" 28 | ] 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright © 2019 SmartCode OOD 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the “Software”), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stremio-api-client 2 | 3 | Facilitates the connection between the `stremio-api` and Stremio, with extras such as user/add-on sync and persistence. 4 | 5 | Contains two main modules: 6 | 7 | ## StremioAPIClient 8 | 9 | This is a stateless module to request the `stremio-api` 10 | 11 | It's constructed like this: 12 | 13 | ```javascript 14 | var StremioAPIClient = require('stremio-api-client').StremioAPIClient 15 | var API = new StremioAPIClient(options) 16 | ``` 17 | 18 | ### Options: 19 | 20 | * `endpoint` - URL to the API, default is `https://api.strem.io` 21 | 22 | * `authKey` - session auth key, default is `null` 23 | 24 | ### Methods: 25 | 26 | * `request(method, params)` - returns a promise 27 | 28 | 29 | 30 | ## StremioAPIStore 31 | 32 | This is a stateful class that, when created, would take care of persistance and sync of the user and her add-ons collection 33 | 34 | It's constructed like this: 35 | 36 | ```javascript 37 | var StremioAPIStore = require('stremio-api-client').StremioAPIStore 38 | var APIStore = new StremioAPIStore(options) 39 | ``` 40 | 41 | ### Options: 42 | 43 | * `endpoint` - URL to the API, default is `https://api.strem.io` 44 | 45 | * `storage` - a storage object with synchronous `getJSON` and `setJSON` properties 46 | 47 | ### Properties: 48 | 49 | `APIStore.user` - User object 50 | 51 | `APIStore.addons` - AddonCollection 52 | 53 | ### Methods: 54 | 55 | **NOTE:** All the methods return promises 56 | 57 | `APIStore.login({ email, password, fbLoginToken })` - logs in; `fbLoginToken` is optional 58 | 59 | `APIStore.authWithApple({ token, sub, email, name })` - authenticates with Apple Sign In; requires token, sub, email, name for authentication 60 | 61 | `APIStore.register({ email, password })` - registers a new user 62 | 63 | `APIStore.logout()` - logs out 64 | 65 | All of the above 3 methods change `API.user` and therefore will emit (upon success) `user-change` 66 | 67 | `APIStore.pushUser()` - pushes the local `API.user` to the API; requires to be logged in 68 | 69 | `APIStore.pullUser()` - pull the latest user from the API; requires to be logged in 70 | 71 | `pullUser()` may emit `user-change` if the remote user is more recent 72 | 73 | `APIStore.pushAddonCollection()` - pushes local `API.addons` collection to the API (via `addonCollectionSet`); requires to be logged in 74 | 75 | `APIStore.pullAddonCollection()` - pulls the remote add-on collection (via `addonCollectionGet`), may emit `addons-change` or `addons-different` 76 | 77 | ### Events: 78 | 79 | `user-change`: emitted when the User is changed (by ID, i.e. completely different user) 80 | 81 | `addons-change`: emitted when the add-on set (AddonCollection) is changed 82 | 83 | `addons-different`: emitted when the add-on collection is different (compared through transportUrls) 84 | -------------------------------------------------------------------------------- /apiClient.js: -------------------------------------------------------------------------------- 1 | var fetch = require('node-fetch'); 2 | 3 | function ApiClient(options) { 4 | options = options || {}; 5 | 6 | var authKey = options.authKey; 7 | var endpoint = options.endpoint || 'https://api.strem.io'; 8 | 9 | this.endpoint = endpoint; 10 | 11 | this.request = function(method, params) { 12 | var fetchOptions = { 13 | method: 'POST', 14 | headers: { 15 | 'content-type': 'application/json' 16 | }, 17 | body: JSON.stringify(Object.assign({ authKey: authKey }, params)) 18 | }; 19 | 20 | return fetch(endpoint + '/api/' + method, fetchOptions) 21 | .then(function(resp) { 22 | if (resp.status !== 200) { 23 | throw new Error('request failed with status code ' + resp.status); 24 | } 25 | 26 | return resp.json(); 27 | }) 28 | .then(function(body) { 29 | if (body.error) { 30 | throw body.error; 31 | } 32 | 33 | if (!body.result) { 34 | throw new Error('response has no result'); 35 | } 36 | 37 | return body.result; 38 | }); 39 | }; 40 | 41 | Object.freeze(this); 42 | return this; 43 | } 44 | 45 | module.exports = ApiClient; 46 | -------------------------------------------------------------------------------- /apiStore.js: -------------------------------------------------------------------------------- 1 | var EventEmitter = require('events'); 2 | var AddonCollection = require('stremio-addon-client').AddonCollection; 3 | var mapURL = require('stremio-addon-client').mapURL; 4 | var officialAddons = require('stremio-official-addons'); 5 | var MemoryStorage = require('./lib/memoryStorage'); 6 | var addonsDifferent = require('./lib/addonsDifferent'); 7 | var ApiClient = require('./apiClient'); 8 | 9 | var ENDPOINT = 'https://api.strem.io'; 10 | var INTERRUPTED_ERROR_MESSAGE = 'request interrupted'; 11 | 12 | var USER_REQUIRED = 'user required to invoke this'; 13 | 14 | function ApiStore(options) { 15 | options = options || {}; 16 | var endpoint = options.endpoint || ENDPOINT; 17 | var storage = options.storage || new MemoryStorage(); 18 | var client = new ApiClient({ endpoint: endpoint, authKey: storage.getJSON('authKey') }); 19 | 20 | var self = this; 21 | 22 | this.endpoint = endpoint; 23 | 24 | this.events = new EventEmitter(); 25 | 26 | this.user = storage.getJSON('user'); 27 | // Migration from legacy format 28 | if (this.user && this.user.authKey) { 29 | storage.setJSON('authKey', this.user.authKey); 30 | client = new ApiClient({ endpoint: endpoint, authKey: this.user.authKey }); 31 | storage.setJSON('user', this.user); 32 | } 33 | 34 | this.addons = new AddonCollection(); 35 | this.addons.load(storage.getJSON('addons') || officialAddons); 36 | 37 | this.request = function(method, params) { 38 | var currentClient = client; 39 | return new Promise(function(resolve, reject) { 40 | currentClient.request(method, params) 41 | .then(function(resp) { 42 | if (currentClient !== client) { 43 | reject(new Error(INTERRUPTED_ERROR_MESSAGE)); 44 | return; 45 | } 46 | 47 | resolve(resp); 48 | }) 49 | .catch(function(err) { 50 | if (currentClient !== client) { 51 | reject(new Error(INTERRUPTED_ERROR_MESSAGE)); 52 | return; 53 | } 54 | 55 | reject(err); 56 | }); 57 | }); 58 | }; 59 | 60 | this.login = function(params) { 61 | return this.request('login', params) 62 | .then(function(result) { 63 | self.userChange(result.authKey, result.user); 64 | addonsUpdated(null, null); 65 | }); 66 | }; 67 | 68 | this.loginWithToken = function(params) { 69 | return this.request('loginWithToken', params) 70 | .then(function(result) { 71 | self.userChange(result.authKey, result.user); 72 | addonsUpdated(null, null); 73 | }); 74 | }; 75 | 76 | this.authWithApple = function(params) { 77 | return this.request('authWithApple', params) 78 | .then(function(result) { 79 | self.userChange(result.authKey, result.user); 80 | addonsUpdated(null, null); 81 | }); 82 | }; 83 | 84 | this.register = function(params) { 85 | return this.request('register', params) 86 | .then(function(result) { 87 | self.userChange(result.authKey, result.user); 88 | addonsUpdated(null, null); 89 | }); 90 | }; 91 | 92 | this.logout = function() { 93 | return this.request('logout') 94 | .then(function() { 95 | self.userChange(null, null); 96 | addonsUpdated(null, null); 97 | }) 98 | .catch(function(err) { 99 | if (err && err.message === INTERRUPTED_ERROR_MESSAGE) { 100 | throw err; 101 | } 102 | 103 | self.userChange(null, null); 104 | addonsUpdated(null, null); 105 | }); 106 | }; 107 | 108 | // 109 | // pullAddonCollection, pushAddonCollection 110 | // 111 | this.pullAddonCollection = function() { 112 | if (!self.user) { 113 | return Promise.reject(new Error(USER_REQUIRED)); 114 | } 115 | 116 | var params = { update: true, addFromURL: [] }; 117 | 118 | var legacyKey = 'addons:' + (self.user ? self.user._id : ''); 119 | params.addFromURL = mapLegacyAddonRepo(storage.getJSON(legacyKey)); 120 | 121 | var lastModifiedOriginal = storage.getJSON('addonsLastModified') || 0; 122 | 123 | return this.request('addonCollectionGet', params) 124 | .then(function(resp) { 125 | if (!Array.isArray(resp.addons)) { 126 | throw 'no resp.addons'; 127 | } 128 | 129 | var lastModified = storage.getJSON('addonsLastModified') || 0; 130 | var newLastModified = new Date(resp.lastModified).getTime(); 131 | if (resp.addons.length && lastModified == lastModifiedOriginal && newLastModified > lastModified) { 132 | addonsUpdated(resp.addons, newLastModified); 133 | 134 | if (params.addFromURL.length) { 135 | storage.setJSON(legacyKey, null); 136 | } 137 | } 138 | }); 139 | }; 140 | 141 | this.pushAddonCollection = function() { 142 | var descriptors = self.addons.save(); 143 | storage.setJSON('addons', descriptors); 144 | storage.setJSON('addonsLastModified', Date.now()); 145 | 146 | if (!self.user) { 147 | return Promise.resolve(); 148 | } 149 | 150 | return self.request('addonCollectionSet', { addons: descriptors }); 151 | }; 152 | 153 | // 154 | // pullUser, pushUser 155 | // 156 | this.pullUser = function() { 157 | if (!self.user) { 158 | return Promise.reject(new Error(USER_REQUIRED)); 159 | } 160 | 161 | return this.request('getUser') 162 | .then(function(user) { 163 | if (!(user && user._id)) { 164 | throw 'invalid user returned'; 165 | } 166 | 167 | var lastModified = new Date(self.user.lastModified).getTime(); 168 | var newLastModified = new Date(user.lastModified).getTime(); 169 | if (newLastModified > lastModified) { 170 | storage.setJSON('user', user); 171 | self.user = user; 172 | } 173 | }); 174 | }; 175 | 176 | this.pushUser = function() { 177 | if (!self.user) { 178 | return Promise.reject(new Error(USER_REQUIRED)); 179 | } 180 | 181 | self.user.lastModified = new Date(); 182 | storage.setJSON('user', self.user); 183 | return self.request('saveUser', self.user); 184 | }; 185 | 186 | // 187 | // Private methods 188 | // 189 | 190 | // only invoked when the user is changed by _id (different user) 191 | // call this with (null, null) when logging out 192 | this.userChange = function(authKey, user) { 193 | storage.setJSON('authKey', authKey); 194 | storage.setJSON('user', user); 195 | client = new ApiClient({ endpoint: endpoint, authKey: authKey }); 196 | self.user = user; 197 | self.events.emit('user-change', user); 198 | }; 199 | 200 | // this may be invoked when the add-on set is updated 201 | function addonsUpdated(descriptors, lastModified) { 202 | var isDifferent = addonsDifferent(descriptors || [], self.addons.getAddons()); 203 | 204 | storage.setJSON('addons', descriptors); 205 | storage.setJSON('addonsLastModified', lastModified || 0); 206 | self.addons.load(descriptors || officialAddons); 207 | self.events.emit('addons-change'); 208 | if (isDifferent) self.events.emit('addons-different'); 209 | } 210 | 211 | // remaps old add-on format into a list of URLs 212 | function mapLegacyAddonRepo(repo) { 213 | if (repo && Array.isArray(repo.addons)) { 214 | return repo.addons 215 | .filter(function(x) { return Array.isArray(x.endpoints) && typeof (x.endpoints[0]) === 'string'; }) 216 | .map(function(x) { return mapURL(x.endpoints[0]); }); 217 | } 218 | return []; 219 | } 220 | 221 | Object.seal(this); 222 | return this; 223 | } 224 | 225 | module.exports = ApiStore; 226 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | StremioAPIClient: require('./apiClient'), 3 | StremioAPIStore: require('./apiStore'), 4 | addonsDifferent: require('./lib/addonsDifferent') 5 | }; -------------------------------------------------------------------------------- /lib/addonsDifferent.js: -------------------------------------------------------------------------------- 1 | module.exports = function(a, b) { 2 | if (a.length !== b.length) return true; 3 | return a.some(function(x, i) { return b[i].transportUrl !== x.transportUrl; }); 4 | }; -------------------------------------------------------------------------------- /lib/memoryStorage.js: -------------------------------------------------------------------------------- 1 | function MemoryStorage() { 2 | var data = {}; 3 | 4 | this.setJSON = function(key, value) { 5 | data[key] = JSON.stringify(value); 6 | }; 7 | 8 | this.getJSON = function(key) { 9 | return data.hasOwnProperty(key) ? JSON.parse(data[key]) : null; 10 | }; 11 | } 12 | 13 | module.exports = MemoryStorage; 14 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stremio-api-client", 3 | "version": "1.6.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.0.0", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", 10 | "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.0.0" 14 | } 15 | }, 16 | "@babel/highlight": { 17 | "version": "7.0.0", 18 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", 19 | "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", 20 | "dev": true, 21 | "requires": { 22 | "chalk": "^2.0.0", 23 | "esutils": "^2.0.2", 24 | "js-tokens": "^4.0.0" 25 | } 26 | }, 27 | "acorn": { 28 | "version": "6.4.1", 29 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", 30 | "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", 31 | "dev": true 32 | }, 33 | "acorn-jsx": { 34 | "version": "5.0.1", 35 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", 36 | "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", 37 | "dev": true 38 | }, 39 | "ajv": { 40 | "version": "6.9.1", 41 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", 42 | "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==", 43 | "dev": true, 44 | "requires": { 45 | "fast-deep-equal": "^2.0.1", 46 | "fast-json-stable-stringify": "^2.0.0", 47 | "json-schema-traverse": "^0.4.1", 48 | "uri-js": "^4.2.2" 49 | } 50 | }, 51 | "ansi-escapes": { 52 | "version": "3.2.0", 53 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", 54 | "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", 55 | "dev": true 56 | }, 57 | "ansi-regex": { 58 | "version": "3.0.0", 59 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 60 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 61 | "dev": true 62 | }, 63 | "ansi-styles": { 64 | "version": "3.2.1", 65 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 66 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 67 | "dev": true, 68 | "requires": { 69 | "color-convert": "^1.9.0" 70 | } 71 | }, 72 | "argparse": { 73 | "version": "1.0.10", 74 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 75 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 76 | "dev": true, 77 | "requires": { 78 | "sprintf-js": "~1.0.2" 79 | } 80 | }, 81 | "astral-regex": { 82 | "version": "1.0.0", 83 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", 84 | "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", 85 | "dev": true 86 | }, 87 | "balanced-match": { 88 | "version": "1.0.0", 89 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 90 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 91 | "dev": true 92 | }, 93 | "brace-expansion": { 94 | "version": "1.1.11", 95 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 96 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 97 | "dev": true, 98 | "requires": { 99 | "balanced-match": "^1.0.0", 100 | "concat-map": "0.0.1" 101 | } 102 | }, 103 | "callsites": { 104 | "version": "3.0.0", 105 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", 106 | "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", 107 | "dev": true 108 | }, 109 | "chalk": { 110 | "version": "2.4.2", 111 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 112 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 113 | "dev": true, 114 | "requires": { 115 | "ansi-styles": "^3.2.1", 116 | "escape-string-regexp": "^1.0.5", 117 | "supports-color": "^5.3.0" 118 | } 119 | }, 120 | "chardet": { 121 | "version": "0.7.0", 122 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", 123 | "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", 124 | "dev": true 125 | }, 126 | "cli-cursor": { 127 | "version": "2.1.0", 128 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", 129 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", 130 | "dev": true, 131 | "requires": { 132 | "restore-cursor": "^2.0.0" 133 | } 134 | }, 135 | "cli-width": { 136 | "version": "2.2.0", 137 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 138 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", 139 | "dev": true 140 | }, 141 | "color-convert": { 142 | "version": "1.9.3", 143 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 144 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 145 | "dev": true, 146 | "requires": { 147 | "color-name": "1.1.3" 148 | } 149 | }, 150 | "color-name": { 151 | "version": "1.1.3", 152 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 153 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 154 | "dev": true 155 | }, 156 | "concat-map": { 157 | "version": "0.0.1", 158 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 159 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 160 | "dev": true 161 | }, 162 | "cross-spawn": { 163 | "version": "6.0.5", 164 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 165 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 166 | "dev": true, 167 | "requires": { 168 | "nice-try": "^1.0.4", 169 | "path-key": "^2.0.1", 170 | "semver": "^5.5.0", 171 | "shebang-command": "^1.2.0", 172 | "which": "^1.2.9" 173 | } 174 | }, 175 | "debug": { 176 | "version": "4.1.1", 177 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 178 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 179 | "dev": true, 180 | "requires": { 181 | "ms": "^2.1.1" 182 | } 183 | }, 184 | "deep-equal": { 185 | "version": "1.0.1", 186 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", 187 | "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", 188 | "dev": true 189 | }, 190 | "deep-is": { 191 | "version": "0.1.3", 192 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 193 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 194 | "dev": true 195 | }, 196 | "define-properties": { 197 | "version": "1.1.2", 198 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", 199 | "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", 200 | "dev": true, 201 | "requires": { 202 | "foreach": "^2.0.5", 203 | "object-keys": "^1.0.8" 204 | } 205 | }, 206 | "defined": { 207 | "version": "1.0.0", 208 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", 209 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", 210 | "dev": true 211 | }, 212 | "doctrine": { 213 | "version": "3.0.0", 214 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 215 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 216 | "dev": true, 217 | "requires": { 218 | "esutils": "^2.0.2" 219 | } 220 | }, 221 | "emoji-regex": { 222 | "version": "7.0.3", 223 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 224 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 225 | "dev": true 226 | }, 227 | "es-abstract": { 228 | "version": "1.12.0", 229 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", 230 | "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", 231 | "dev": true, 232 | "requires": { 233 | "es-to-primitive": "^1.1.1", 234 | "function-bind": "^1.1.1", 235 | "has": "^1.0.1", 236 | "is-callable": "^1.1.3", 237 | "is-regex": "^1.0.4" 238 | } 239 | }, 240 | "es-to-primitive": { 241 | "version": "1.1.1", 242 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", 243 | "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", 244 | "dev": true, 245 | "requires": { 246 | "is-callable": "^1.1.1", 247 | "is-date-object": "^1.0.1", 248 | "is-symbol": "^1.0.1" 249 | } 250 | }, 251 | "escape-string-regexp": { 252 | "version": "1.0.5", 253 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 254 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 255 | "dev": true 256 | }, 257 | "eslint": { 258 | "version": "5.14.1", 259 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.14.1.tgz", 260 | "integrity": "sha512-CyUMbmsjxedx8B0mr79mNOqetvkbij/zrXnFeK2zc3pGRn3/tibjiNAv/3UxFEyfMDjh+ZqTrJrEGBFiGfD5Og==", 261 | "dev": true, 262 | "requires": { 263 | "@babel/code-frame": "^7.0.0", 264 | "ajv": "^6.9.1", 265 | "chalk": "^2.1.0", 266 | "cross-spawn": "^6.0.5", 267 | "debug": "^4.0.1", 268 | "doctrine": "^3.0.0", 269 | "eslint-scope": "^4.0.0", 270 | "eslint-utils": "^1.3.1", 271 | "eslint-visitor-keys": "^1.0.0", 272 | "espree": "^5.0.1", 273 | "esquery": "^1.0.1", 274 | "esutils": "^2.0.2", 275 | "file-entry-cache": "^5.0.1", 276 | "functional-red-black-tree": "^1.0.1", 277 | "glob": "^7.1.2", 278 | "globals": "^11.7.0", 279 | "ignore": "^4.0.6", 280 | "import-fresh": "^3.0.0", 281 | "imurmurhash": "^0.1.4", 282 | "inquirer": "^6.2.2", 283 | "js-yaml": "^3.12.0", 284 | "json-stable-stringify-without-jsonify": "^1.0.1", 285 | "levn": "^0.3.0", 286 | "lodash": "^4.17.11", 287 | "minimatch": "^3.0.4", 288 | "mkdirp": "^0.5.1", 289 | "natural-compare": "^1.4.0", 290 | "optionator": "^0.8.2", 291 | "path-is-inside": "^1.0.2", 292 | "progress": "^2.0.0", 293 | "regexpp": "^2.0.1", 294 | "semver": "^5.5.1", 295 | "strip-ansi": "^4.0.0", 296 | "strip-json-comments": "^2.0.1", 297 | "table": "^5.2.3", 298 | "text-table": "^0.2.0" 299 | } 300 | }, 301 | "eslint-scope": { 302 | "version": "4.0.0", 303 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", 304 | "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", 305 | "dev": true, 306 | "requires": { 307 | "esrecurse": "^4.1.0", 308 | "estraverse": "^4.1.1" 309 | } 310 | }, 311 | "eslint-utils": { 312 | "version": "1.4.3", 313 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", 314 | "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", 315 | "dev": true, 316 | "requires": { 317 | "eslint-visitor-keys": "^1.1.0" 318 | }, 319 | "dependencies": { 320 | "eslint-visitor-keys": { 321 | "version": "1.1.0", 322 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", 323 | "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", 324 | "dev": true 325 | } 326 | } 327 | }, 328 | "eslint-visitor-keys": { 329 | "version": "1.0.0", 330 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", 331 | "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", 332 | "dev": true 333 | }, 334 | "espree": { 335 | "version": "5.0.1", 336 | "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", 337 | "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", 338 | "dev": true, 339 | "requires": { 340 | "acorn": "^6.0.7", 341 | "acorn-jsx": "^5.0.0", 342 | "eslint-visitor-keys": "^1.0.0" 343 | } 344 | }, 345 | "esprima": { 346 | "version": "4.0.1", 347 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 348 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 349 | "dev": true 350 | }, 351 | "esquery": { 352 | "version": "1.0.1", 353 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", 354 | "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", 355 | "dev": true, 356 | "requires": { 357 | "estraverse": "^4.0.0" 358 | } 359 | }, 360 | "esrecurse": { 361 | "version": "4.2.1", 362 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", 363 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", 364 | "dev": true, 365 | "requires": { 366 | "estraverse": "^4.1.0" 367 | } 368 | }, 369 | "estraverse": { 370 | "version": "4.2.0", 371 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 372 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", 373 | "dev": true 374 | }, 375 | "esutils": { 376 | "version": "2.0.2", 377 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 378 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 379 | "dev": true 380 | }, 381 | "events": { 382 | "version": "1.1.0", 383 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.0.tgz", 384 | "integrity": "sha1-SzifwgD5EHQuv/Orsu/jNpD0VCk=" 385 | }, 386 | "external-editor": { 387 | "version": "3.0.3", 388 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", 389 | "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", 390 | "dev": true, 391 | "requires": { 392 | "chardet": "^0.7.0", 393 | "iconv-lite": "^0.4.24", 394 | "tmp": "^0.0.33" 395 | } 396 | }, 397 | "fast-deep-equal": { 398 | "version": "2.0.1", 399 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 400 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", 401 | "dev": true 402 | }, 403 | "fast-json-stable-stringify": { 404 | "version": "2.0.0", 405 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 406 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", 407 | "dev": true 408 | }, 409 | "fast-levenshtein": { 410 | "version": "2.0.6", 411 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 412 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 413 | "dev": true 414 | }, 415 | "figures": { 416 | "version": "2.0.0", 417 | "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", 418 | "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", 419 | "dev": true, 420 | "requires": { 421 | "escape-string-regexp": "^1.0.5" 422 | } 423 | }, 424 | "file-entry-cache": { 425 | "version": "5.0.1", 426 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", 427 | "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", 428 | "dev": true, 429 | "requires": { 430 | "flat-cache": "^2.0.1" 431 | } 432 | }, 433 | "flat-cache": { 434 | "version": "2.0.1", 435 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", 436 | "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", 437 | "dev": true, 438 | "requires": { 439 | "flatted": "^2.0.0", 440 | "rimraf": "2.6.3", 441 | "write": "1.0.3" 442 | } 443 | }, 444 | "flatted": { 445 | "version": "2.0.0", 446 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", 447 | "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", 448 | "dev": true 449 | }, 450 | "for-each": { 451 | "version": "0.3.3", 452 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 453 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 454 | "dev": true, 455 | "requires": { 456 | "is-callable": "^1.1.3" 457 | } 458 | }, 459 | "foreach": { 460 | "version": "2.0.5", 461 | "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", 462 | "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", 463 | "dev": true 464 | }, 465 | "fs.realpath": { 466 | "version": "1.0.0", 467 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 468 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 469 | "dev": true 470 | }, 471 | "function-bind": { 472 | "version": "1.1.1", 473 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 474 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 475 | "dev": true 476 | }, 477 | "functional-red-black-tree": { 478 | "version": "1.0.1", 479 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 480 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 481 | "dev": true 482 | }, 483 | "glob": { 484 | "version": "7.1.2", 485 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 486 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 487 | "dev": true, 488 | "requires": { 489 | "fs.realpath": "^1.0.0", 490 | "inflight": "^1.0.4", 491 | "inherits": "2", 492 | "minimatch": "^3.0.4", 493 | "once": "^1.3.0", 494 | "path-is-absolute": "^1.0.0" 495 | } 496 | }, 497 | "globals": { 498 | "version": "11.11.0", 499 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", 500 | "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", 501 | "dev": true 502 | }, 503 | "has": { 504 | "version": "1.0.3", 505 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 506 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 507 | "dev": true, 508 | "requires": { 509 | "function-bind": "^1.1.1" 510 | } 511 | }, 512 | "has-flag": { 513 | "version": "3.0.0", 514 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 515 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 516 | "dev": true 517 | }, 518 | "iconv-lite": { 519 | "version": "0.4.24", 520 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 521 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 522 | "dev": true, 523 | "requires": { 524 | "safer-buffer": ">= 2.1.2 < 3" 525 | } 526 | }, 527 | "ignore": { 528 | "version": "4.0.6", 529 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 530 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 531 | "dev": true 532 | }, 533 | "import-fresh": { 534 | "version": "3.0.0", 535 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", 536 | "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", 537 | "dev": true, 538 | "requires": { 539 | "parent-module": "^1.0.0", 540 | "resolve-from": "^4.0.0" 541 | } 542 | }, 543 | "imurmurhash": { 544 | "version": "0.1.4", 545 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 546 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 547 | "dev": true 548 | }, 549 | "inflight": { 550 | "version": "1.0.6", 551 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 552 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 553 | "dev": true, 554 | "requires": { 555 | "once": "^1.3.0", 556 | "wrappy": "1" 557 | } 558 | }, 559 | "inherits": { 560 | "version": "2.0.3", 561 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 562 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 563 | "dev": true 564 | }, 565 | "inquirer": { 566 | "version": "6.2.2", 567 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", 568 | "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", 569 | "dev": true, 570 | "requires": { 571 | "ansi-escapes": "^3.2.0", 572 | "chalk": "^2.4.2", 573 | "cli-cursor": "^2.1.0", 574 | "cli-width": "^2.0.0", 575 | "external-editor": "^3.0.3", 576 | "figures": "^2.0.0", 577 | "lodash": "^4.17.11", 578 | "mute-stream": "0.0.7", 579 | "run-async": "^2.2.0", 580 | "rxjs": "^6.4.0", 581 | "string-width": "^2.1.0", 582 | "strip-ansi": "^5.0.0", 583 | "through": "^2.3.6" 584 | }, 585 | "dependencies": { 586 | "ansi-regex": { 587 | "version": "4.0.0", 588 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", 589 | "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", 590 | "dev": true 591 | }, 592 | "strip-ansi": { 593 | "version": "5.0.0", 594 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", 595 | "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", 596 | "dev": true, 597 | "requires": { 598 | "ansi-regex": "^4.0.0" 599 | } 600 | } 601 | } 602 | }, 603 | "is-callable": { 604 | "version": "1.1.4", 605 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", 606 | "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", 607 | "dev": true 608 | }, 609 | "is-date-object": { 610 | "version": "1.0.1", 611 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", 612 | "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", 613 | "dev": true 614 | }, 615 | "is-fullwidth-code-point": { 616 | "version": "2.0.0", 617 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 618 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 619 | "dev": true 620 | }, 621 | "is-promise": { 622 | "version": "2.1.0", 623 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 624 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", 625 | "dev": true 626 | }, 627 | "is-regex": { 628 | "version": "1.0.4", 629 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", 630 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", 631 | "dev": true, 632 | "requires": { 633 | "has": "^1.0.1" 634 | } 635 | }, 636 | "is-symbol": { 637 | "version": "1.0.1", 638 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", 639 | "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", 640 | "dev": true 641 | }, 642 | "isexe": { 643 | "version": "2.0.0", 644 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 645 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 646 | "dev": true 647 | }, 648 | "js-tokens": { 649 | "version": "4.0.0", 650 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 651 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 652 | "dev": true 653 | }, 654 | "js-yaml": { 655 | "version": "3.13.1", 656 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 657 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 658 | "dev": true, 659 | "requires": { 660 | "argparse": "^1.0.7", 661 | "esprima": "^4.0.0" 662 | } 663 | }, 664 | "json-schema-traverse": { 665 | "version": "0.4.1", 666 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 667 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 668 | "dev": true 669 | }, 670 | "json-stable-stringify-without-jsonify": { 671 | "version": "1.0.1", 672 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 673 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 674 | "dev": true 675 | }, 676 | "levn": { 677 | "version": "0.3.0", 678 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 679 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 680 | "dev": true, 681 | "requires": { 682 | "prelude-ls": "~1.1.2", 683 | "type-check": "~0.3.2" 684 | } 685 | }, 686 | "lodash": { 687 | "version": "4.17.21", 688 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 689 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 690 | "dev": true 691 | }, 692 | "mimic-fn": { 693 | "version": "1.2.0", 694 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 695 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", 696 | "dev": true 697 | }, 698 | "minimatch": { 699 | "version": "3.0.4", 700 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 701 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 702 | "dev": true, 703 | "requires": { 704 | "brace-expansion": "^1.1.7" 705 | } 706 | }, 707 | "minimist": { 708 | "version": "1.2.0", 709 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 710 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 711 | "dev": true 712 | }, 713 | "mkdirp": { 714 | "version": "0.5.1", 715 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 716 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 717 | "dev": true, 718 | "requires": { 719 | "minimist": "0.0.8" 720 | }, 721 | "dependencies": { 722 | "minimist": { 723 | "version": "0.0.8", 724 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 725 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 726 | "dev": true 727 | } 728 | } 729 | }, 730 | "ms": { 731 | "version": "2.1.1", 732 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 733 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 734 | "dev": true 735 | }, 736 | "mute-stream": { 737 | "version": "0.0.7", 738 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", 739 | "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", 740 | "dev": true 741 | }, 742 | "natural-compare": { 743 | "version": "1.4.0", 744 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 745 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 746 | "dev": true 747 | }, 748 | "nice-try": { 749 | "version": "1.0.5", 750 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 751 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 752 | "dev": true 753 | }, 754 | "node-fetch": { 755 | "version": "2.6.1", 756 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", 757 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" 758 | }, 759 | "object-inspect": { 760 | "version": "1.6.0", 761 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", 762 | "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", 763 | "dev": true 764 | }, 765 | "object-keys": { 766 | "version": "1.0.12", 767 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", 768 | "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", 769 | "dev": true 770 | }, 771 | "once": { 772 | "version": "1.4.0", 773 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 774 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 775 | "dev": true, 776 | "requires": { 777 | "wrappy": "1" 778 | } 779 | }, 780 | "onetime": { 781 | "version": "2.0.1", 782 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", 783 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", 784 | "dev": true, 785 | "requires": { 786 | "mimic-fn": "^1.0.0" 787 | } 788 | }, 789 | "optionator": { 790 | "version": "0.8.2", 791 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 792 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 793 | "dev": true, 794 | "requires": { 795 | "deep-is": "~0.1.3", 796 | "fast-levenshtein": "~2.0.4", 797 | "levn": "~0.3.0", 798 | "prelude-ls": "~1.1.2", 799 | "type-check": "~0.3.2", 800 | "wordwrap": "~1.0.0" 801 | } 802 | }, 803 | "os-tmpdir": { 804 | "version": "1.0.2", 805 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 806 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 807 | "dev": true 808 | }, 809 | "parent-module": { 810 | "version": "1.0.0", 811 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.0.tgz", 812 | "integrity": "sha512-8Mf5juOMmiE4FcmzYc4IaiS9L3+9paz2KOiXzkRviCP6aDmN49Hz6EMWz0lGNp9pX80GvvAuLADtyGfW/Em3TA==", 813 | "dev": true, 814 | "requires": { 815 | "callsites": "^3.0.0" 816 | } 817 | }, 818 | "path-is-absolute": { 819 | "version": "1.0.1", 820 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 821 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 822 | "dev": true 823 | }, 824 | "path-is-inside": { 825 | "version": "1.0.2", 826 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 827 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 828 | "dev": true 829 | }, 830 | "path-key": { 831 | "version": "2.0.1", 832 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 833 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 834 | "dev": true 835 | }, 836 | "path-parse": { 837 | "version": "1.0.5", 838 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", 839 | "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", 840 | "dev": true 841 | }, 842 | "prelude-ls": { 843 | "version": "1.1.2", 844 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 845 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 846 | "dev": true 847 | }, 848 | "progress": { 849 | "version": "2.0.3", 850 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 851 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 852 | "dev": true 853 | }, 854 | "regexpp": { 855 | "version": "2.0.1", 856 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", 857 | "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", 858 | "dev": true 859 | }, 860 | "resolve": { 861 | "version": "1.7.1", 862 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", 863 | "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", 864 | "dev": true, 865 | "requires": { 866 | "path-parse": "^1.0.5" 867 | } 868 | }, 869 | "resolve-from": { 870 | "version": "4.0.0", 871 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 872 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 873 | "dev": true 874 | }, 875 | "restore-cursor": { 876 | "version": "2.0.0", 877 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", 878 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", 879 | "dev": true, 880 | "requires": { 881 | "onetime": "^2.0.0", 882 | "signal-exit": "^3.0.2" 883 | } 884 | }, 885 | "resumer": { 886 | "version": "0.0.0", 887 | "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", 888 | "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", 889 | "dev": true, 890 | "requires": { 891 | "through": "~2.3.4" 892 | } 893 | }, 894 | "rimraf": { 895 | "version": "2.6.3", 896 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 897 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 898 | "dev": true, 899 | "requires": { 900 | "glob": "^7.1.3" 901 | }, 902 | "dependencies": { 903 | "glob": { 904 | "version": "7.1.3", 905 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 906 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 907 | "dev": true, 908 | "requires": { 909 | "fs.realpath": "^1.0.0", 910 | "inflight": "^1.0.4", 911 | "inherits": "2", 912 | "minimatch": "^3.0.4", 913 | "once": "^1.3.0", 914 | "path-is-absolute": "^1.0.0" 915 | } 916 | } 917 | } 918 | }, 919 | "run-async": { 920 | "version": "2.3.0", 921 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", 922 | "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", 923 | "dev": true, 924 | "requires": { 925 | "is-promise": "^2.1.0" 926 | } 927 | }, 928 | "rxjs": { 929 | "version": "6.4.0", 930 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", 931 | "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", 932 | "dev": true, 933 | "requires": { 934 | "tslib": "^1.9.0" 935 | } 936 | }, 937 | "safer-buffer": { 938 | "version": "2.1.2", 939 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 940 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 941 | "dev": true 942 | }, 943 | "semver": { 944 | "version": "5.6.0", 945 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", 946 | "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", 947 | "dev": true 948 | }, 949 | "shebang-command": { 950 | "version": "1.2.0", 951 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 952 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 953 | "dev": true, 954 | "requires": { 955 | "shebang-regex": "^1.0.0" 956 | } 957 | }, 958 | "shebang-regex": { 959 | "version": "1.0.0", 960 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 961 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 962 | "dev": true 963 | }, 964 | "signal-exit": { 965 | "version": "3.0.2", 966 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 967 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 968 | "dev": true 969 | }, 970 | "slice-ansi": { 971 | "version": "2.1.0", 972 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", 973 | "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", 974 | "dev": true, 975 | "requires": { 976 | "ansi-styles": "^3.2.0", 977 | "astral-regex": "^1.0.0", 978 | "is-fullwidth-code-point": "^2.0.0" 979 | } 980 | }, 981 | "sprintf-js": { 982 | "version": "1.0.3", 983 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 984 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 985 | "dev": true 986 | }, 987 | "string-width": { 988 | "version": "2.1.1", 989 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 990 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 991 | "dev": true, 992 | "requires": { 993 | "is-fullwidth-code-point": "^2.0.0", 994 | "strip-ansi": "^4.0.0" 995 | } 996 | }, 997 | "string.prototype.trim": { 998 | "version": "1.1.2", 999 | "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", 1000 | "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", 1001 | "dev": true, 1002 | "requires": { 1003 | "define-properties": "^1.1.2", 1004 | "es-abstract": "^1.5.0", 1005 | "function-bind": "^1.0.2" 1006 | } 1007 | }, 1008 | "strip-ansi": { 1009 | "version": "4.0.0", 1010 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1011 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1012 | "dev": true, 1013 | "requires": { 1014 | "ansi-regex": "^3.0.0" 1015 | } 1016 | }, 1017 | "strip-json-comments": { 1018 | "version": "2.0.1", 1019 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1020 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1021 | "dev": true 1022 | }, 1023 | "supports-color": { 1024 | "version": "5.5.0", 1025 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1026 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1027 | "dev": true, 1028 | "requires": { 1029 | "has-flag": "^3.0.0" 1030 | } 1031 | }, 1032 | "table": { 1033 | "version": "5.2.3", 1034 | "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", 1035 | "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", 1036 | "dev": true, 1037 | "requires": { 1038 | "ajv": "^6.9.1", 1039 | "lodash": "^4.17.11", 1040 | "slice-ansi": "^2.1.0", 1041 | "string-width": "^3.0.0" 1042 | }, 1043 | "dependencies": { 1044 | "ansi-regex": { 1045 | "version": "4.0.0", 1046 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", 1047 | "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", 1048 | "dev": true 1049 | }, 1050 | "string-width": { 1051 | "version": "3.0.0", 1052 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.0.0.tgz", 1053 | "integrity": "sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew==", 1054 | "dev": true, 1055 | "requires": { 1056 | "emoji-regex": "^7.0.1", 1057 | "is-fullwidth-code-point": "^2.0.0", 1058 | "strip-ansi": "^5.0.0" 1059 | } 1060 | }, 1061 | "strip-ansi": { 1062 | "version": "5.0.0", 1063 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", 1064 | "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", 1065 | "dev": true, 1066 | "requires": { 1067 | "ansi-regex": "^4.0.0" 1068 | } 1069 | } 1070 | } 1071 | }, 1072 | "tape": { 1073 | "version": "4.9.1", 1074 | "resolved": "https://registry.npmjs.org/tape/-/tape-4.9.1.tgz", 1075 | "integrity": "sha512-6fKIXknLpoe/Jp4rzHKFPpJUHDHDqn8jus99IfPnHIjyz78HYlefTGD3b5EkbQzuLfaEvmfPK3IolLgq2xT3kw==", 1076 | "dev": true, 1077 | "requires": { 1078 | "deep-equal": "~1.0.1", 1079 | "defined": "~1.0.0", 1080 | "for-each": "~0.3.3", 1081 | "function-bind": "~1.1.1", 1082 | "glob": "~7.1.2", 1083 | "has": "~1.0.3", 1084 | "inherits": "~2.0.3", 1085 | "minimist": "~1.2.0", 1086 | "object-inspect": "~1.6.0", 1087 | "resolve": "~1.7.1", 1088 | "resumer": "~0.0.0", 1089 | "string.prototype.trim": "~1.1.2", 1090 | "through": "~2.3.8" 1091 | } 1092 | }, 1093 | "text-table": { 1094 | "version": "0.2.0", 1095 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1096 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1097 | "dev": true 1098 | }, 1099 | "through": { 1100 | "version": "2.3.8", 1101 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1102 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1103 | "dev": true 1104 | }, 1105 | "tmp": { 1106 | "version": "0.0.33", 1107 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1108 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1109 | "dev": true, 1110 | "requires": { 1111 | "os-tmpdir": "~1.0.2" 1112 | } 1113 | }, 1114 | "tslib": { 1115 | "version": "1.9.3", 1116 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", 1117 | "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", 1118 | "dev": true 1119 | }, 1120 | "type-check": { 1121 | "version": "0.3.2", 1122 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1123 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1124 | "dev": true, 1125 | "requires": { 1126 | "prelude-ls": "~1.1.2" 1127 | } 1128 | }, 1129 | "uri-js": { 1130 | "version": "4.2.2", 1131 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 1132 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 1133 | "dev": true, 1134 | "requires": { 1135 | "punycode": "^2.1.0" 1136 | }, 1137 | "dependencies": { 1138 | "punycode": { 1139 | "version": "2.1.1", 1140 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1141 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 1142 | "dev": true 1143 | } 1144 | } 1145 | }, 1146 | "which": { 1147 | "version": "1.3.1", 1148 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1149 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1150 | "dev": true, 1151 | "requires": { 1152 | "isexe": "^2.0.0" 1153 | } 1154 | }, 1155 | "wordwrap": { 1156 | "version": "1.0.0", 1157 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 1158 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 1159 | "dev": true 1160 | }, 1161 | "wrappy": { 1162 | "version": "1.0.2", 1163 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1164 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1165 | "dev": true 1166 | }, 1167 | "write": { 1168 | "version": "1.0.3", 1169 | "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", 1170 | "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", 1171 | "dev": true, 1172 | "requires": { 1173 | "mkdirp": "^0.5.1" 1174 | } 1175 | } 1176 | } 1177 | } 1178 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stremio-api-client", 3 | "version": "1.6.1", 4 | "main": "index.js", 5 | "author": "Smart Code OOD", 6 | "license": "MIT", 7 | "scripts": { 8 | "pretest": "eslint --ignore-path .gitignore .", 9 | "test": "node test/test" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/Stremio/stremio-api-client.git" 14 | }, 15 | "dependencies": { 16 | "events": "1.1.0", 17 | "node-fetch": "2.6.1" 18 | }, 19 | "devDependencies": { 20 | "eslint": "^5.14.1", 21 | "tape": "4.9.1" 22 | }, 23 | "peerDependencies": { 24 | "stremio-addon-client": "^1.14.5", 25 | "stremio-official-addons": "^1.5.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var StremioAPIStore = require('..').StremioAPIStore; 2 | var tape = require('tape'); 3 | var MemoryStorage = require('../lib/memoryStorage'); 4 | 5 | 6 | var defaultStore = new MemoryStorage(); 7 | 8 | var api = new StremioAPIStore({ storage: defaultStore }); 9 | 10 | // @TODO: test StremioAPIClient too 11 | 12 | 13 | tape('basic call', function(t) { 14 | t.ok(api.endpoint, 'has endpoint'); 15 | 16 | api.request('addonCollectionGet', {}) 17 | .then(function(resp) { 18 | t.ok(resp, 'has response'); 19 | t.ok(Array.isArray(resp.addons), 'response is valid'); 20 | t.ok(resp.isInitial, 'response isInitial'); 21 | t.end(); 22 | }) 23 | .catch(function(err) { 24 | t.error(err); 25 | }); 26 | }); 27 | 28 | tape('API.addons is initialized by default', function(t) { 29 | t.ok(api.addons, 'api.addons is there'); 30 | t.ok(api.addons.getAddons().length > 0, 'api.addons.getAddons() has addons'); 31 | t.end(); 32 | }); 33 | 34 | tape('pullUser does not work without api.user', function(t) { 35 | api.pullUser() 36 | .then(function() { 37 | t.error('should not be here'); 38 | }) 39 | .catch(function(err) { 40 | t.ok(err, 'has error'); 41 | t.equals(err.message, 'user required to invoke this'); 42 | t.end(); 43 | }); 44 | }); 45 | 46 | var user = { 47 | email: 'stremioapiclient+'+Date.now()+'@strem.io', 48 | password: '215552'+Date.now(), 49 | }; 50 | 51 | tape('register', function(t) { 52 | var userChangeEmitted = false; 53 | 54 | api.events.on('user-change', function(){ userChangeEmitted = true; }); 55 | api.register(user) 56 | .then(function() { 57 | t.ok(api.user, 'api.user'); 58 | t.equals(api.user.email, user.email, 'user email is equal'); 59 | t.ok(userChangeEmitted, 'user-change emitted'); 60 | t.end(); 61 | }) 62 | .catch(function(err) { 63 | t.error(err); 64 | }); 65 | }); 66 | 67 | tape('authWithApple', function(t) { 68 | var userChangeEmitted = false; 69 | 70 | api.events.on('user-change', function(){ userChangeEmitted = true; }); 71 | 72 | var token = 'mock.apple.token'; 73 | var sub = 'mock.apple.sub'; 74 | var email = 'mock.apple.email'; 75 | var name = 'mock.apple.name'; 76 | 77 | api.authWithApple({ token, sub, email, name }) 78 | .then(function() { 79 | t.ok(api.user, 'api.user exists after Apple auth'); 80 | t.ok(userChangeEmitted, 'user-change emitted'); 81 | t.end(); 82 | }) 83 | .catch(function(err) { 84 | t.error(err); 85 | }); 86 | }); 87 | 88 | // @TODO: proper tests of pullAddonCollection, pushAddonCollection 89 | // @TODO: to properly test this, first do a addonCollectionSet, and then check if this updates it 90 | tape('pullAddonCollection', function(t) { 91 | var addonsChangeEmitted = false; 92 | var addonsDifferentEmitted = false; 93 | 94 | api.events.on('addons-change', function() { addonsChangeEmitted = true; }); 95 | api.events.on('addons-different', function() { addonsDifferentEmitted = true; }); 96 | 97 | api.pullAddonCollection() 98 | .then(function() { 99 | // @TODO: what's said in the prev comment 100 | t.ok(api.addons, 'api.addons is there'); 101 | t.ok(api.addons.getAddons().length > 0, 'api.addons.getAddons() has addons'); 102 | t.ok(addonsChangeEmitted, 'addons-change emitted'); 103 | t.notOk(addonsDifferentEmitted, 'addons-different not emitted'); 104 | t.end(); 105 | }) 106 | .catch(function(err) { 107 | t.error(err); 108 | }); 109 | }); 110 | 111 | tape('pushAddonCollection', function(t) { 112 | api.pushAddonCollection() 113 | .then(function() { 114 | // @TODO: properly test if this works 115 | t.ok(api.addons, 'api.addons is there'); 116 | t.ok(api.addons.getAddons().length > 0, 'api.addons.getAddons() has addons'); 117 | t.end(); 118 | }) 119 | .catch(function(err) { 120 | t.error(err); 121 | }); 122 | }); 123 | 124 | // @TODO: pullUser/pushUser proper tests 125 | 126 | // @TODO: finish this test 127 | tape('pullUser', function(t) { 128 | api.pullUser() 129 | .then(function() { 130 | // @TODO: what's said in the prev comment 131 | t.ok(api.user, 'api.user is there'); 132 | t.end(); 133 | }) 134 | .catch(function(err) { 135 | t.error(err); 136 | }); 137 | }); 138 | 139 | tape('pushUser', function(t) { 140 | api.pushUser() 141 | .then(function() { 142 | // @TODO: what's said in the prev comment 143 | t.ok(api.user, 'api.user is there'); 144 | t.end(); 145 | }) 146 | .catch(function(err) { 147 | t.error(err); 148 | }); 149 | }); 150 | 151 | 152 | 153 | // @TODO: from a logged in state, log in again with another account 154 | // @TODO: check if add-ons is reset !! 155 | 156 | tape('storage persists', function(t) { 157 | var user = { 158 | email: 'stremioapiclient2+'+Date.now()+'@strem.io', 159 | password: '215552'+Date.now(), 160 | }; 161 | 162 | var store = new MemoryStorage(); 163 | var API = new StremioAPIStore({ storage: store }); 164 | API.register(user) 165 | .then(function() { 166 | t.ok(API.user, 'API.user'); 167 | t.equals(API.user.email, user.email, 'user email is equal'); 168 | 169 | t.ok(store.getJSON('authKey'), 'storage has saved authKey'); 170 | 171 | var API2 = new StremioAPIStore({ storage: store }); 172 | t.ok(API2.user, 'API2.user'); 173 | t.deepEquals(API.user, API2.user, 'API.user is the same as API2.user'); 174 | 175 | return API2.request('getUser'); 176 | }) 177 | .then(function(resp) { 178 | t.ok(resp.email, 'has resp.email'); 179 | t.deepEquals(resp, API.user, 'resp.user is same as API.user'); 180 | 181 | // @TODO: API.addons is initialized by default, same as API1's add-ons 182 | 183 | return API.logout(); 184 | }) 185 | .then(function() { 186 | t.notOk(API.user, 'API.user is empty'); 187 | t.notOk(store.getJSON('authKey'), 'storage does not have authKey'); 188 | t.end(); 189 | }) 190 | .catch(function(err) { 191 | t.error(err); 192 | }); 193 | }); 194 | 195 | tape('migrationg legacy user works', function(t) { 196 | var store = new MemoryStorage(); 197 | var copiedUser = Object.assign({ authKey: defaultStore.getJSON('authKey') }, defaultStore.getJSON('user')); 198 | 199 | store.setJSON('user', copiedUser); 200 | 201 | var API = new StremioAPIStore({ storage: store }); 202 | 203 | t.ok(store.getJSON('authKey'), 'store has authKey'); 204 | 205 | API.pullUser() 206 | .then(function() { 207 | // @TODO: what's said in the prev comment 208 | t.ok(api.user, 'api.user is there'); 209 | t.end(); 210 | }) 211 | .catch(function(err) { 212 | t.error(err); 213 | }); 214 | }); 215 | 216 | /* 217 | tape('add-on collection persisted even without being logged in', function(t) { 218 | // @TODO 219 | }) 220 | */ 221 | 222 | 223 | tape('logout', function(t) { 224 | api.logout() 225 | .then(function() { 226 | t.notOk(api.user, 'api.user should be empty'); 227 | // @TODO: test if storage authKey is reset 228 | // @TODO: test if storage addons is reset 229 | // @TODO: test if API.addons has been reset to official 230 | t.end(); 231 | }) 232 | .catch(function(err) { 233 | t.error(err); 234 | }); 235 | }); 236 | --------------------------------------------------------------------------------