source: trip-planner-front/node_modules/pacote/lib/registry.js@ 59329aa

Last change on this file since 59329aa was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 6.5 KB
Line 
1const Fetcher = require('./fetcher.js')
2const RemoteFetcher = require('./remote.js')
3const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved')
4const pacoteVersion = require('../package.json').version
5const npa = require('npm-package-arg')
6const rpj = require('read-package-json-fast')
7const pickManifest = require('npm-pick-manifest')
8const ssri = require('ssri')
9const Minipass = require('minipass')
10
11// Corgis are cute. 🐕🐶
12const corgiDoc = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*'
13const fullDoc = 'application/json'
14
15const fetch = require('npm-registry-fetch')
16
17// TODO: memoize reg requests, so we don't even have to check cache
18
19const _headers = Symbol('_headers')
20class RegistryFetcher extends Fetcher {
21 constructor (spec, opts) {
22 super(spec, opts)
23
24 // you usually don't want to fetch the same packument multiple times in
25 // the span of a given script or command, no matter how many pacote calls
26 // are made, so this lets us avoid doing that. It's only relevant for
27 // registry fetchers, because other types simulate their packument from
28 // the manifest, which they memoize on this.package, so it's very cheap
29 // already.
30 this.packumentCache = this.opts.packumentCache || null
31
32 // handle case when npm-package-arg guesses wrong.
33 if (this.spec.type === 'tag' &&
34 this.spec.rawSpec === '' &&
35 this.defaultTag !== 'latest')
36 this.spec = npa(`${this.spec.name}@${this.defaultTag}`)
37 this.registry = fetch.pickRegistry(spec, opts)
38 this.packumentUrl = this.registry.replace(/\/*$/, '/') +
39 this.spec.escapedName
40
41 // XXX pacote <=9 has some logic to ignore opts.resolved if
42 // the resolved URL doesn't go to the same registry.
43 // Consider reproducing that here, to throw away this.resolved
44 // in that case.
45 }
46
47 resolve () {
48 if (this.resolved)
49 return Promise.resolve(this.resolved)
50
51 // fetching the manifest sets resolved and (usually) integrity
52 return this.manifest().then(() => {
53 if (this.resolved)
54 return this.resolved
55
56 throw Object.assign(
57 new Error('Invalid package manifest: no `dist.tarball` field'),
58 { package: this.spec.toString() }
59 )
60 })
61 }
62
63 [_headers] () {
64 return {
65 // npm will override UA, but ensure that we always send *something*
66 'user-agent': this.opts.userAgent ||
67 `pacote/${pacoteVersion} node/${process.version}`,
68 ...(this.opts.headers || {}),
69 'pacote-version': pacoteVersion,
70 'pacote-req-type': 'packument',
71 'pacote-pkg-id': `registry:${this.spec.name}`,
72 accept: this.fullMetadata ? fullDoc : corgiDoc,
73 }
74 }
75
76 async packument () {
77 // note this might be either an in-flight promise for a request,
78 // or the actual packument, but we never want to make more than
79 // one request at a time for the same thing regardless.
80 if (this.packumentCache && this.packumentCache.has(this.packumentUrl))
81 return this.packumentCache.get(this.packumentUrl)
82
83 // npm-registry-fetch the packument
84 // set the appropriate header for corgis if fullMetadata isn't set
85 // return the res.json() promise
86 const p = fetch(this.packumentUrl, {
87 ...this.opts,
88 headers: this[_headers](),
89 spec: this.spec,
90 // never check integrity for packuments themselves
91 integrity: null,
92 }).then(res => res.json().then(packument => {
93 packument._cached = res.headers.has('x-local-cache')
94 packument._contentLength = +res.headers.get('content-length')
95 if (this.packumentCache)
96 this.packumentCache.set(this.packumentUrl, packument)
97 return packument
98 })).catch(er => {
99 if (this.packumentCache)
100 this.packumentCache.delete(this.packumentUrl)
101 if (er.code === 'E404' && !this.fullMetadata) {
102 // possible that corgis are not supported by this registry
103 this.fullMetadata = true
104 return this.packument()
105 }
106 throw er
107 })
108 if (this.packumentCache)
109 this.packumentCache.set(this.packumentUrl, p)
110 return p
111 }
112
113 manifest () {
114 if (this.package)
115 return Promise.resolve(this.package)
116
117 return this.packument()
118 .then(packument => pickManifest(packument, this.spec.fetchSpec, {
119 ...this.opts,
120 defaultTag: this.defaultTag,
121 before: this.before,
122 }) /* XXX add ETARGET and E403 revalidation of cached packuments here */)
123 .then(mani => {
124 // add _resolved and _integrity from dist object
125 const { dist } = mani
126 if (dist) {
127 this.resolved = mani._resolved = dist.tarball
128 mani._from = this.from
129 const distIntegrity = dist.integrity ? ssri.parse(dist.integrity)
130 : dist.shasum ? ssri.fromHex(dist.shasum, 'sha1', {...this.opts})
131 : null
132 if (distIntegrity) {
133 if (!this.integrity)
134 this.integrity = distIntegrity
135 else if (!this.integrity.match(distIntegrity)) {
136 // only bork if they have algos in common.
137 // otherwise we end up breaking if we have saved a sha512
138 // previously for the tarball, but the manifest only
139 // provides a sha1, which is possible for older publishes.
140 // Otherwise, this is almost certainly a case of holding it
141 // wrong, and will result in weird or insecure behavior
142 // later on when building package tree.
143 for (const algo of Object.keys(this.integrity)) {
144 if (distIntegrity[algo]) {
145 throw Object.assign(new Error(
146 `Integrity checksum failed when using ${algo}: `+
147 `wanted ${this.integrity} but got ${distIntegrity}.`
148 ), { code: 'EINTEGRITY' })
149 }
150 }
151 // made it this far, the integrity is worthwhile. accept it.
152 // the setter here will take care of merging it into what we
153 // already had.
154 this.integrity = distIntegrity
155 }
156 }
157 }
158 if (this.integrity)
159 mani._integrity = String(this.integrity)
160 this.package = rpj.normalize(mani)
161 return this.package
162 })
163 }
164
165 [_tarballFromResolved] () {
166 // we use a RemoteFetcher to get the actual tarball stream
167 return new RemoteFetcher(this.resolved, {
168 ...this.opts,
169 resolved: this.resolved,
170 pkgid: `registry:${this.spec.name}@${this.resolved}`,
171 })[_tarballFromResolved]()
172 }
173
174 get types () {
175 return [
176 'tag',
177 'version',
178 'range',
179 ]
180 }
181}
182module.exports = RegistryFetcher
Note: See TracBrowser for help on using the repository browser.