remote.js 2.6 KB

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