source: trip-planner-front/node_modules/npm-registry-fetch/index.js@ 8d391a1

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

initial commit

  • Property mode set to 100644
File size: 6.1 KB
Line 
1'use strict'
2
3const { HttpErrorAuthOTP } = require('./errors.js')
4const checkResponse = require('./check-response.js')
5const getAuth = require('./auth.js')
6const fetch = require('make-fetch-happen')
7const JSONStream = require('minipass-json-stream')
8const npa = require('npm-package-arg')
9const qs = require('querystring')
10const url = require('url')
11const zlib = require('minizlib')
12const Minipass = require('minipass')
13
14const defaultOpts = require('./default-opts.js')
15
16// WhatWG URL throws if it's not fully resolved
17const urlIsValid = u => {
18 try {
19 return !!new url.URL(u)
20 } catch (_) {
21 return false
22 }
23}
24
25module.exports = regFetch
26function regFetch (uri, /* istanbul ignore next */ opts_ = {}) {
27 const opts = {
28 ...defaultOpts,
29 ...opts_,
30 }
31
32 // if we did not get a fully qualified URI, then we look at the registry
33 // config or relevant scope to resolve it.
34 const uriValid = urlIsValid(uri)
35 let registry = opts.registry || defaultOpts.registry
36 if (!uriValid) {
37 registry = opts.registry = (
38 (opts.spec && pickRegistry(opts.spec, opts)) ||
39 opts.registry ||
40 registry
41 )
42 uri = `${
43 registry.trim().replace(/\/?$/g, '')
44 }/${
45 uri.trim().replace(/^\//, '')
46 }`
47 // asserts that this is now valid
48 new url.URL(uri)
49 }
50
51 const method = opts.method || 'GET'
52
53 // through that takes into account the scope, the prefix of `uri`, etc
54 const startTime = Date.now()
55 const auth = getAuth(uri, opts)
56 const headers = getHeaders(uri, auth, opts)
57 let body = opts.body
58 const bodyIsStream = Minipass.isStream(body)
59 const bodyIsPromise = body &&
60 typeof body === 'object' &&
61 typeof body.then === 'function'
62
63 if (body && !bodyIsStream && !bodyIsPromise && typeof body !== 'string' && !Buffer.isBuffer(body)) {
64 headers['content-type'] = headers['content-type'] || 'application/json'
65 body = JSON.stringify(body)
66 } else if (body && !headers['content-type'])
67 headers['content-type'] = 'application/octet-stream'
68
69 if (opts.gzip) {
70 headers['content-encoding'] = 'gzip'
71 if (bodyIsStream) {
72 const gz = new zlib.Gzip()
73 body.on('error', /* istanbul ignore next: unlikely and hard to test */
74 err => gz.emit('error', err))
75 body = body.pipe(gz)
76 } else if (!bodyIsPromise)
77 body = new zlib.Gzip().end(body).concat()
78 }
79
80 const parsed = new url.URL(uri)
81
82 if (opts.query) {
83 const q = typeof opts.query === 'string' ? qs.parse(opts.query)
84 : opts.query
85
86 Object.keys(q).forEach(key => {
87 if (q[key] !== undefined)
88 parsed.searchParams.set(key, q[key])
89 })
90 uri = url.format(parsed)
91 }
92
93 if (parsed.searchParams.get('write') === 'true' && method === 'GET') {
94 // do not cache, because this GET is fetching a rev that will be
95 // used for a subsequent PUT or DELETE, so we need to conditionally
96 // update cache.
97 opts.offline = false
98 opts.preferOffline = false
99 opts.preferOnline = true
100 }
101
102 const doFetch = async body => {
103 const p = fetch(uri, {
104 agent: opts.agent,
105 algorithms: opts.algorithms,
106 body,
107 cache: getCacheMode(opts),
108 cacheManager: opts.cache,
109 ca: opts.ca,
110 cert: opts.cert,
111 headers,
112 integrity: opts.integrity,
113 key: opts.key,
114 localAddress: opts.localAddress,
115 maxSockets: opts.maxSockets,
116 memoize: opts.memoize,
117 method: method,
118 noProxy: opts.noProxy,
119 proxy: opts.httpsProxy || opts.proxy,
120 retry: opts.retry ? opts.retry : {
121 retries: opts.fetchRetries,
122 factor: opts.fetchRetryFactor,
123 minTimeout: opts.fetchRetryMintimeout,
124 maxTimeout: opts.fetchRetryMaxtimeout,
125 },
126 strictSSL: opts.strictSSL,
127 timeout: opts.timeout || 30 * 1000,
128 }).then(res => checkResponse({
129 method,
130 uri,
131 res,
132 registry,
133 startTime,
134 auth,
135 opts,
136 }))
137
138 if (typeof opts.otpPrompt === 'function') {
139 return p.catch(async er => {
140 if (er instanceof HttpErrorAuthOTP) {
141 // if otp fails to complete, we fail with that failure
142 const otp = await opts.otpPrompt()
143 // if no otp provided, throw the original HTTP error
144 if (!otp)
145 throw er
146 return regFetch(uri, { ...opts, otp })
147 }
148 throw er
149 })
150 } else
151 return p
152 }
153
154 return Promise.resolve(body).then(doFetch)
155}
156
157module.exports.json = fetchJSON
158function fetchJSON (uri, opts) {
159 return regFetch(uri, opts).then(res => res.json())
160}
161
162module.exports.json.stream = fetchJSONStream
163function fetchJSONStream (uri, jsonPath,
164 /* istanbul ignore next */ opts_ = {}) {
165 const opts = { ...defaultOpts, ...opts_ }
166 const parser = JSONStream.parse(jsonPath, opts.mapJSON)
167 regFetch(uri, opts).then(res =>
168 res.body.on('error',
169 /* istanbul ignore next: unlikely and difficult to test */
170 er => parser.emit('error', er)).pipe(parser)
171 ).catch(er => parser.emit('error', er))
172 return parser
173}
174
175module.exports.pickRegistry = pickRegistry
176function pickRegistry (spec, opts = {}) {
177 spec = npa(spec)
178 let registry = spec.scope &&
179 opts[spec.scope.replace(/^@?/, '@') + ':registry']
180
181 if (!registry && opts.scope)
182 registry = opts[opts.scope.replace(/^@?/, '@') + ':registry']
183
184 if (!registry)
185 registry = opts.registry || defaultOpts.registry
186
187 return registry
188}
189
190function getCacheMode (opts) {
191 return opts.offline ? 'only-if-cached'
192 : opts.preferOffline ? 'force-cache'
193 : opts.preferOnline ? 'no-cache'
194 : 'default'
195}
196
197function getHeaders (uri, auth, opts) {
198 const headers = Object.assign({
199 'user-agent': opts.userAgent,
200 }, opts.headers || {})
201
202 if (opts.projectScope)
203 headers['npm-scope'] = opts.projectScope
204
205 if (opts.npmSession)
206 headers['npm-session'] = opts.npmSession
207
208 if (opts.npmCommand)
209 headers['npm-command'] = opts.npmCommand
210
211 // If a tarball is hosted on a different place than the manifest, only send
212 // credentials on `alwaysAuth`
213 if (auth.token)
214 headers.authorization = `Bearer ${auth.token}`
215 else if (auth.auth)
216 headers.authorization = `Basic ${auth.auth}`
217
218 if (opts.otp)
219 headers['npm-otp'] = opts.otp
220
221 return headers
222}
Note: See TracBrowser for help on using the repository browser.