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