1const Fetcher = require('./fetcher.js') 2const FileFetcher = require('./file.js') 3const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved') 4const pacoteVersion = require('../package.json').version 5const fetch = require('npm-registry-fetch') 6const { Minipass } = require('minipass') 7 8const _cacheFetches = Symbol.for('pacote.Fetcher._cacheFetches') 9const _headers = Symbol('_headers') 10class RemoteFetcher extends Fetcher { 11 constructor (spec, opts) { 12 super(spec, opts) 13 this.resolved = this.spec.fetchSpec 14 const resolvedURL = new URL(this.resolved) 15 if (this.replaceRegistryHost !== 'never' 16 && (this.replaceRegistryHost === 'always' 17 || this.replaceRegistryHost === resolvedURL.host)) { 18 this.resolved = new URL(resolvedURL.pathname, this.registry).href 19 } 20 21 // nam is a fermented pork sausage that is good to eat 22 const nameat = this.spec.name ? `${this.spec.name}@` : '' 23 this.pkgid = opts.pkgid ? opts.pkgid : `remote:${nameat}${this.resolved}` 24 } 25 26 // Don't need to cache tarball fetches in pacote, because make-fetch-happen 27 // will write into cacache anyway. 28 get [_cacheFetches] () { 29 return false 30 } 31 32 [_tarballFromResolved] () { 33 const stream = new Minipass() 34 stream.hasIntegrityEmitter = true 35 36 const fetchOpts = { 37 ...this.opts, 38 headers: this[_headers](), 39 spec: this.spec, 40 integrity: this.integrity, 41 algorithms: [this.pickIntegrityAlgorithm()], 42 } 43 44 // eslint-disable-next-line promise/always-return 45 fetch(this.resolved, fetchOpts).then(res => { 46 res.body.on('error', 47 /* istanbul ignore next - exceedingly rare and hard to simulate */ 48 er => stream.emit('error', er) 49 ) 50 51 res.body.on('integrity', i => { 52 this.integrity = i 53 stream.emit('integrity', i) 54 }) 55 56 res.body.pipe(stream) 57 }).catch(er => stream.emit('error', er)) 58 59 return stream 60 } 61 62 [_headers] () { 63 return { 64 // npm will override this, but ensure that we always send *something* 65 'user-agent': this.opts.userAgent || 66 `pacote/${pacoteVersion} node/${process.version}`, 67 ...(this.opts.headers || {}), 68 'pacote-version': pacoteVersion, 69 'pacote-req-type': 'tarball', 70 'pacote-pkg-id': this.pkgid, 71 ...(this.integrity ? { 'pacote-integrity': String(this.integrity) } 72 : {}), 73 ...(this.opts.headers || {}), 74 } 75 } 76 77 get types () { 78 return ['remote'] 79 } 80 81 // getting a packument and/or manifest is the same as with a file: spec. 82 // unpack the tarball stream, and then read from the package.json file. 83 packument () { 84 return FileFetcher.prototype.packument.apply(this) 85 } 86 87 manifest () { 88 return FileFetcher.prototype.manifest.apply(this) 89 } 90} 91module.exports = RemoteFetcher 92