├── .github └── workflows │ └── publish.yml ├── .gitignore ├── LICENSE ├── README.md ├── gridsome.server.js ├── package.json └── yarn.lock /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | jobs: 4 | publish: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v1 8 | - uses: actions/setup-node@v1 9 | with: 10 | node-version: 10 11 | - run: npm install 12 | - uses: JS-DevTools/npm-publish@v1 13 | with: 14 | token: ${{ secrets.NPM_TOKEN }} 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and not Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # Stores VSCode versions used for testing VSCode extensions 107 | .vscode-test -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Marcus Reinhardt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gridsome Remote Image Downloader 2 | 3 | This is a simple plugin, which is based on a discord discussion. 4 | It's more a workaround than a permanent solution. 5 | 6 | The plugin should work with any data source, but I have tested it only with `source-filesystem`. 7 | 8 | ## Features 9 | 10 | * Download of remote images 11 | * Support of multiple images ( see example ) 12 | 13 | ## Install 14 | 15 | ```sh 16 | npm i @noxify/gridsome-plugin-remote-image 17 | 18 | # or 19 | 20 | yarn add @noxify/gridsome-plugin-remote-image 21 | ``` 22 | 23 | ## Setup 24 | 25 | ```js 26 | //gridsome.config.js 27 | 28 | module.exports = { 29 | siteName: 'Gridsome', 30 | plugins: [ 31 | //... 32 | { 33 | use: '@noxify/gridsome-plugin-remote-image', 34 | options: { 35 | 'typeName' : 'Entry', 36 | 'sourceField': 'remoteImage', 37 | 'targetField': 'imageDownloaded', 38 | 'targetPath': './src/assets/remoteImages' 39 | } 40 | }, 41 | { 42 | use: '@noxify/gridsome-plugin-remote-image', 43 | options: { 44 | 'typeName' : 'Entry', 45 | 'sourceField': 'remoteImages', 46 | 'targetField': 'imagesDownloaded', 47 | 'targetPath': './src/assets/remoteImages' 48 | } 49 | } 50 | ] 51 | //... 52 | } 53 | ``` 54 | 55 | ## Documentation 56 | 57 | You can find the complete documentation here: https://webstone.info/documentation/gridsome-plugin-remote-image 58 | -------------------------------------------------------------------------------- /gridsome.server.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | const crypto = require('crypto') 3 | const fs = require('fs-extra') 4 | const get = require('lodash.get') 5 | const got = require('got').default 6 | const mime = require('mime/lite') 7 | const normalizeUrl = require('normalize-url') 8 | const path = require('path') 9 | const stream = require('stream') 10 | const url = require('url') 11 | const validate = require('validate.js') 12 | const { promisify } = require('util') 13 | 14 | const pipeline = promisify(stream.pipeline) 15 | 16 | class ImageDownloader { 17 | constructor(api, options) { 18 | 19 | //no one is perfect, so we check that all required 20 | //config values are defined in `gridsome.config.js` 21 | const validationResult = this.validateOptions(options) 22 | 23 | if (validationResult) { 24 | console.log() 25 | console.log(`${chalk.yellowBright('Remote images are not downloaded. Please check your configuration.')}`) 26 | console.log(`${chalk.yellowBright('* '+validationResult.join('\n* '))}`) 27 | console.log() 28 | 29 | return null 30 | } 31 | 32 | this.options = options 33 | this.api = api 34 | 35 | //initialize the `loadImage` event and make 36 | //it available before we run the `onBootstrap` command 37 | this.initializeEvent(api) 38 | 39 | //create a new type `Images` which is required 40 | //for array support 41 | //also add a new field to the defined collection 42 | //to store the downloaded images 43 | api.createSchema(({ addSchemaTypes }) => { 44 | const fieldType = this.getFieldType(api, options) 45 | this.generateSchemaType(addSchemaTypes, fieldType) 46 | }); 47 | 48 | //run the plugin code, after gridsome finished all their work 49 | api.onBootstrap(() => this.loadImages()) 50 | } 51 | 52 | /** 53 | * Create a new event via the gridsome plugin api 54 | * reference: node_modules/gridsome/lib/app/PluginAPI.js 55 | */ 56 | initializeEvent(api) { 57 | api._on('loadImage', this.runDownloader) 58 | } 59 | 60 | /** 61 | * Run the defined event with the required 62 | * arguments - i have no clue why `this` is not available 63 | * but I'm too tired to check this in detail... 64 | * Defining the needed methods is fine for me :) 65 | */ 66 | async loadImages() { 67 | await this.run('loadImage', null, { 68 | getFieldType: this.getFieldType, 69 | getRemoteImage: this.getRemoteImage, 70 | updateNodes: this.updateNodes, 71 | options: this.options 72 | }) 73 | } 74 | 75 | /** 76 | * Defined in `initializeEvent` 77 | * Called via `loadImages` 78 | */ 79 | async runDownloader(plugin, api) { 80 | const fieldType = plugin.getFieldType(api, plugin.options) 81 | await plugin.updateNodes(api, fieldType, plugin) 82 | } 83 | 84 | getFieldType(api, options) { 85 | const nodeCollection = api._app.store.getCollection(options.typeName) 86 | 87 | //details about this definition can be found here 88 | //https://github.com/techfort/LokiJS/wiki/Query-Examples#find-operator-examples- 89 | const findQuery = { 90 | [options.sourceField]: { 91 | '$exists': true 92 | } 93 | } 94 | 95 | const node = nodeCollection.findNode( findQuery ) 96 | 97 | //we're using the lodash get functionality 98 | //to allow a dot notation in the source field name 99 | return (node) ? typeof get(node, options.sourceField) : false 100 | } 101 | 102 | generateSchemaType(addSchemaTypes, fieldType) { 103 | 104 | const schemaType = 105 | fieldType === 'string' || 106 | !!(this.options.schemaType && this.options.schemaType === 'Image') 107 | ? 'Image' 108 | : '[Images]' 109 | 110 | addSchemaTypes(` 111 | type Images { 112 | image: Image 113 | } 114 | `) 115 | 116 | //extend the existing schema 117 | addSchemaTypes(` 118 | type ${this.options.typeName} implements Node @infer { 119 | ${this.options.targetField}: ${schemaType} 120 | } 121 | `) 122 | } 123 | 124 | async updateNodes(api, fieldType, plugin) { 125 | const collection = api._app.store.getCollection(plugin.options.typeName) 126 | 127 | 128 | await collection.data().reduce(async (prev, node) => { 129 | await prev 130 | if (get(node,plugin.options.sourceField)) { 131 | const imagePaths = await plugin.getRemoteImage(node, fieldType, plugin.options) 132 | 133 | if( fieldType === 'string' ) { 134 | node[plugin.options.targetField] = imagePaths[0] 135 | } else { 136 | node[plugin.options.targetField] = imagePaths.map(image => ({ image })) 137 | } 138 | 139 | collection.updateNode(node) 140 | } 141 | return Promise.resolve() 142 | }, Promise.resolve()) 143 | } 144 | 145 | async getRemoteImage ( node, fieldType, options ) { 146 | // Set some defaults 147 | const { 148 | cache = true, 149 | original = false, 150 | forceHttps = false, 151 | normalizeProtocol = true, 152 | defaultProtocol = 'http:', 153 | urlPrefix = '', 154 | downloadFromLocalNetwork = false, 155 | targetPath = 'src/assets/remoteImages', 156 | sourceField 157 | } = options 158 | 159 | const imageSources = (fieldType === 'string') ? [get(node, sourceField)] : get(node, sourceField) 160 | 161 | return Promise.all( 162 | imageSources.map( async imageSource => { 163 | 164 | // If a URL prefix is provided, add it 165 | if ( urlPrefix ) { 166 | imageSource = urlPrefix.concat(imageSource); 167 | } 168 | 169 | try { 170 | // Normalize URL, and extract the pathname, to be used for the original filename if required 171 | imageSource = normalizeUrl(imageSource, { 'forceHttps': forceHttps, 'normalizeProtocol': normalizeProtocol, 'defaultProtocol': defaultProtocol }) 172 | } catch(e) { 173 | return imageSource 174 | } 175 | 176 | // Check if we have a local file as source 177 | var isLocal = validate({ imageSource: imageSource }, { imageSource: { url: { allowLocal: downloadFromLocalNetwork } } }) 178 | 179 | 180 | // If this is the case, we can stop here and re-using the existing image 181 | if( isLocal ) { 182 | return imageSource 183 | } 184 | 185 | const { pathname } = new URL(imageSource) 186 | // Parse the path to get the existing name, dir, and ext 187 | let { name, dir, ext } = path.parse(pathname) 188 | 189 | try { 190 | // If there is no ext, we will try to guess from the http content-type 191 | if (!ext) { 192 | const { headers } = await got.head(imageSource) 193 | ext = `.${mime.getExtension(headers['content-type'])}` 194 | } 195 | 196 | // Build the target file name - if we want the original name then return that, otherwise return a hash of the image source 197 | const targetFileName = original ? name : crypto.createHash('sha256').update(imageSource).digest('hex') 198 | // Build the target folder path - joining the current dir, target dir, and optional original path 199 | const targetFolder = path.join(process.cwd(), targetPath, original ? dir : '') 200 | // Build the file path including ext & dir 201 | const filePath = path.format({ ext, name: targetFileName, dir: targetFolder }) 202 | 203 | // If cache = true, and file exists, we can skip downloading 204 | if (cache && await fs.exists(filePath)) return filePath 205 | 206 | // Otherwise, make sure the file exists, and start downloading with a stream 207 | await fs.ensureFile(filePath) 208 | // This streams the download directly to disk, saving Node temporarily storing every single image in memory 209 | await pipeline( 210 | got.stream(imageSource), 211 | fs.createWriteStream(filePath) 212 | ) 213 | 214 | // Return the complete file path for further use 215 | return filePath 216 | } catch(e) { 217 | console.log('') 218 | console.log(`${chalk.yellowBright(`Unable to download image for ${options.typeName} - Source URL: ${imageSource}`)}`) 219 | console.log(`${chalk.redBright(e)}`) 220 | return null 221 | } 222 | }) 223 | ) 224 | } 225 | 226 | /********************** 227 | * Helpers 228 | **********************/ 229 | 230 | /** 231 | * Copied from node_modules/gridsome/lib/app/Plugins.js 232 | */ 233 | async run(eventName, cb, ...args) { 234 | 235 | if (!this.api._app.plugins._listeners[eventName]) return [] 236 | 237 | const results = [] 238 | 239 | for (const entry of this.api._app.plugins._listeners[eventName]) { 240 | if (entry.options.once && entry.done) continue 241 | 242 | const { api, handler } = entry 243 | const result = typeof cb === 'function' 244 | ? await handler(cb(api)) 245 | : await handler(...args, api) 246 | 247 | results.push(result) 248 | entry.done = true 249 | } 250 | 251 | return results 252 | } 253 | 254 | validateOptions(options = {}) { 255 | const contraintOption = { 256 | presence: { 257 | allowEmpty: false 258 | } 259 | }; 260 | 261 | const constraints = { 262 | typeName: contraintOption, 263 | sourceField: contraintOption, 264 | targetField: contraintOption 265 | }; 266 | 267 | const validationResult = validate(options, constraints, { 268 | format: 'flat' 269 | }) 270 | 271 | return validationResult 272 | } 273 | } 274 | 275 | module.exports = ImageDownloader 276 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@noxify/gridsome-plugin-remote-image", 3 | "version": "1.4.0", 4 | "description": "Simple gridsome plugin to download an remote image based on a defined graphql field", 5 | "main": "gridsome.server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Marcus Reinhardt", 10 | "homepage": "https://github.com/noxify/gridsome-plugin-remote-image", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/noxify/gridsome-plugin-remote-image.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/noxify/gridsome-plugin-remote-image/issues" 17 | }, 18 | "license": "MIT", 19 | "publishConfig": { 20 | "access": "public" 21 | }, 22 | "keywords": [ 23 | "vue", 24 | "download", 25 | "image", 26 | "gridsome", 27 | "gridsome-plugin" 28 | ], 29 | "dependencies": { 30 | "chalk": "^4.1.0", 31 | "fs-extra": "^9.1.0", 32 | "got": "^11.8.1", 33 | "lodash.get": "^4.4.2", 34 | "mime": "^2.5.2", 35 | "normalize-url": "^5.3.1", 36 | "validate.js": "^0.13.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@sindresorhus/is@^4.0.0": 6 | version "4.0.0" 7 | resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.0.0.tgz#2ff674e9611b45b528896d820d3d7a812de2f0e4" 8 | integrity sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ== 9 | 10 | "@szmarczak/http-timer@^4.0.5": 11 | version "4.0.5" 12 | resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.5.tgz#bfbd50211e9dfa51ba07da58a14cdfd333205152" 13 | integrity sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ== 14 | dependencies: 15 | defer-to-connect "^2.0.0" 16 | 17 | "@types/cacheable-request@^6.0.1": 18 | version "6.0.1" 19 | resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976" 20 | integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ== 21 | dependencies: 22 | "@types/http-cache-semantics" "*" 23 | "@types/keyv" "*" 24 | "@types/node" "*" 25 | "@types/responselike" "*" 26 | 27 | "@types/color-name@^1.1.1": 28 | version "1.1.1" 29 | resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" 30 | integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== 31 | 32 | "@types/http-cache-semantics@*": 33 | version "4.0.0" 34 | resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a" 35 | integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A== 36 | 37 | "@types/keyv@*": 38 | version "3.1.1" 39 | resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7" 40 | integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw== 41 | dependencies: 42 | "@types/node" "*" 43 | 44 | "@types/node@*": 45 | version "14.0.13" 46 | resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.13.tgz#ee1128e881b874c371374c1f72201893616417c9" 47 | integrity sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA== 48 | 49 | "@types/responselike@*", "@types/responselike@^1.0.0": 50 | version "1.0.0" 51 | resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" 52 | integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== 53 | dependencies: 54 | "@types/node" "*" 55 | 56 | ansi-styles@^4.1.0: 57 | version "4.2.1" 58 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" 59 | integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== 60 | dependencies: 61 | "@types/color-name" "^1.1.1" 62 | color-convert "^2.0.1" 63 | 64 | at-least-node@^1.0.0: 65 | version "1.0.0" 66 | resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" 67 | integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== 68 | 69 | cacheable-lookup@^5.0.3: 70 | version "5.0.3" 71 | resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz#049fdc59dffdd4fc285e8f4f82936591bd59fec3" 72 | integrity sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w== 73 | 74 | cacheable-request@^7.0.1: 75 | version "7.0.1" 76 | resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58" 77 | integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw== 78 | dependencies: 79 | clone-response "^1.0.2" 80 | get-stream "^5.1.0" 81 | http-cache-semantics "^4.0.0" 82 | keyv "^4.0.0" 83 | lowercase-keys "^2.0.0" 84 | normalize-url "^4.1.0" 85 | responselike "^2.0.0" 86 | 87 | chalk@^4.1.0: 88 | version "4.1.0" 89 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" 90 | integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== 91 | dependencies: 92 | ansi-styles "^4.1.0" 93 | supports-color "^7.1.0" 94 | 95 | clone-response@^1.0.2: 96 | version "1.0.2" 97 | resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" 98 | integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= 99 | dependencies: 100 | mimic-response "^1.0.0" 101 | 102 | color-convert@^2.0.1: 103 | version "2.0.1" 104 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 105 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 106 | dependencies: 107 | color-name "~1.1.4" 108 | 109 | color-name@~1.1.4: 110 | version "1.1.4" 111 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 112 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 113 | 114 | decompress-response@^6.0.0: 115 | version "6.0.0" 116 | resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" 117 | integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== 118 | dependencies: 119 | mimic-response "^3.1.0" 120 | 121 | defer-to-connect@^2.0.0: 122 | version "2.0.0" 123 | resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.0.tgz#83d6b199db041593ac84d781b5222308ccf4c2c1" 124 | integrity sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg== 125 | 126 | end-of-stream@^1.1.0: 127 | version "1.4.4" 128 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 129 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 130 | dependencies: 131 | once "^1.4.0" 132 | 133 | fs-extra@^9.1.0: 134 | version "9.1.0" 135 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" 136 | integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== 137 | dependencies: 138 | at-least-node "^1.0.0" 139 | graceful-fs "^4.2.0" 140 | jsonfile "^6.0.1" 141 | universalify "^2.0.0" 142 | 143 | get-stream@^5.1.0: 144 | version "5.1.0" 145 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" 146 | integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== 147 | dependencies: 148 | pump "^3.0.0" 149 | 150 | got@^11.8.1: 151 | version "11.8.1" 152 | resolved "https://registry.yarnpkg.com/got/-/got-11.8.1.tgz#df04adfaf2e782babb3daabc79139feec2f7e85d" 153 | integrity sha512-9aYdZL+6nHmvJwHALLwKSUZ0hMwGaJGYv3hoPLPgnT8BoBXm1SjnZeky+91tfwJaDzun2s4RsBRy48IEYv2q2Q== 154 | dependencies: 155 | "@sindresorhus/is" "^4.0.0" 156 | "@szmarczak/http-timer" "^4.0.5" 157 | "@types/cacheable-request" "^6.0.1" 158 | "@types/responselike" "^1.0.0" 159 | cacheable-lookup "^5.0.3" 160 | cacheable-request "^7.0.1" 161 | decompress-response "^6.0.0" 162 | http2-wrapper "^1.0.0-beta.5.2" 163 | lowercase-keys "^2.0.0" 164 | p-cancelable "^2.0.0" 165 | responselike "^2.0.0" 166 | 167 | graceful-fs@^4.1.6, graceful-fs@^4.2.0: 168 | version "4.2.4" 169 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" 170 | integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== 171 | 172 | has-flag@^4.0.0: 173 | version "4.0.0" 174 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 175 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 176 | 177 | http-cache-semantics@^4.0.0: 178 | version "4.1.0" 179 | resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" 180 | integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== 181 | 182 | http2-wrapper@^1.0.0-beta.5.2: 183 | version "1.0.0-beta.5.2" 184 | resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz#8b923deb90144aea65cf834b016a340fc98556f3" 185 | integrity sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ== 186 | dependencies: 187 | quick-lru "^5.1.1" 188 | resolve-alpn "^1.0.0" 189 | 190 | json-buffer@3.0.1: 191 | version "3.0.1" 192 | resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" 193 | integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== 194 | 195 | jsonfile@^6.0.1: 196 | version "6.0.1" 197 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179" 198 | integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg== 199 | dependencies: 200 | universalify "^1.0.0" 201 | optionalDependencies: 202 | graceful-fs "^4.1.6" 203 | 204 | keyv@^4.0.0: 205 | version "4.0.1" 206 | resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.1.tgz#9fe703cb4a94d6d11729d320af033307efd02ee6" 207 | integrity sha512-xz6Jv6oNkbhrFCvCP7HQa8AaII8y8LRpoSm661NOKLr4uHuBwhX4epXrPQgF3+xdJnN4Esm5X0xwY4bOlALOtw== 208 | dependencies: 209 | json-buffer "3.0.1" 210 | 211 | lodash.get@^4.4.2: 212 | version "4.4.2" 213 | resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" 214 | integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= 215 | 216 | lowercase-keys@^2.0.0: 217 | version "2.0.0" 218 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" 219 | integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== 220 | 221 | mime@^2.5.2: 222 | version "2.5.2" 223 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" 224 | integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== 225 | 226 | mimic-response@^1.0.0: 227 | version "1.0.1" 228 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" 229 | integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== 230 | 231 | mimic-response@^3.1.0: 232 | version "3.1.0" 233 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" 234 | integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== 235 | 236 | normalize-url@^4.1.0: 237 | version "4.5.0" 238 | resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" 239 | integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== 240 | 241 | normalize-url@^5.3.0: 242 | version "5.3.1" 243 | resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-5.3.1.tgz#c8485c0f5ba2f9c17a6d2907b56117ae5967f882" 244 | integrity sha512-K1c7+vaAP+Yh5bOGmA10PGPpp+6h7WZrl7GwqKhUflBc9flU9pzG27DDeB9+iuhZkE3BJZOcgN1P/2sS5pqrWw== 245 | 246 | once@^1.3.1, once@^1.4.0: 247 | version "1.4.0" 248 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 249 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 250 | dependencies: 251 | wrappy "1" 252 | 253 | p-cancelable@^2.0.0: 254 | version "2.0.0" 255 | resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e" 256 | integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg== 257 | 258 | pump@^3.0.0: 259 | version "3.0.0" 260 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 261 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 262 | dependencies: 263 | end-of-stream "^1.1.0" 264 | once "^1.3.1" 265 | 266 | quick-lru@^5.1.1: 267 | version "5.1.1" 268 | resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" 269 | integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== 270 | 271 | resolve-alpn@^1.0.0: 272 | version "1.0.0" 273 | resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.0.0.tgz#745ad60b3d6aff4b4a48e01b8c0bdc70959e0e8c" 274 | integrity sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA== 275 | 276 | responselike@^2.0.0: 277 | version "2.0.0" 278 | resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723" 279 | integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw== 280 | dependencies: 281 | lowercase-keys "^2.0.0" 282 | 283 | supports-color@^7.1.0: 284 | version "7.1.0" 285 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" 286 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== 287 | dependencies: 288 | has-flag "^4.0.0" 289 | 290 | universalify@^1.0.0: 291 | version "1.0.0" 292 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" 293 | integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug== 294 | 295 | universalify@^2.0.0: 296 | version "2.0.0" 297 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" 298 | integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== 299 | 300 | validate.js@^0.13.1: 301 | version "0.13.1" 302 | resolved "https://registry.yarnpkg.com/validate.js/-/validate.js-0.13.1.tgz#b58bfac04a0f600a340f62e5227e70d95971e92a" 303 | integrity sha512-PnFM3xiZ+kYmLyTiMgTYmU7ZHkjBZz2/+F0DaALc/uUtVzdCt1wAosvYJ5hFQi/hz8O4zb52FQhHZRC+uVkJ+g== 304 | 305 | wrappy@1: 306 | version "1.0.2" 307 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 308 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 309 | --------------------------------------------------------------------------------