remote.js 2.7 KB

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