npm-registry-fetch
Advanced tools
Comparing version 0.0.2 to 1.0.0
251
index.js
'use strict' | ||
'use strict' | ||
const Buffer = require('safe-buffer').Buffer | ||
const checkResponse = require('./check-response.js') | ||
const config = require('./config.js') | ||
const getAuth = require('./auth.js') | ||
const fetch = require('make-fetch-happen') | ||
const LRU = require('lru-cache') | ||
const npmlog = require('npmlog') | ||
const npa = require('npm-package-arg') | ||
const qs = require('querystring') | ||
const silentLog = require('./silentlog.js') | ||
const url = require('url') | ||
const WARNING_REGEXP = /^\s*(\d{3})\s+(\S+)\s+"(.*)"\s+"([^"]+)"/ | ||
const BAD_HOSTS = new LRU({ max: 50 }) | ||
module.exports = regFetch | ||
function regFetch (uri, opts) { | ||
opts = Object.assign({ | ||
log: npmlog | ||
}, opts) | ||
const registry = opts.registry || url.parse(uri).host | ||
opts = config(Object.assign({ | ||
log: silentLog | ||
}, opts)) | ||
const registry = opts.get('registry') || | ||
'https://registry.npmjs.org/' | ||
uri = url.parse(uri).protocol | ||
? uri | ||
: `${ | ||
registry.trim().replace(/\/?$/g, '') | ||
}/${ | ||
uri.trim().replace(/^\//, '') | ||
}` | ||
// through that takes into account the scope, the prefix of `uri`, etc | ||
const startTime = Date.now() | ||
const headers = getHeaders(registry, uri, opts) | ||
let body = opts.get('body') | ||
const bodyIsStream = body && | ||
typeof body === 'object' && | ||
typeof body.pipe === 'function' | ||
if (body && !bodyIsStream && typeof body !== 'string' && !Buffer.isBuffer(body)) { | ||
headers['content-type'] = headers['content-type'] || 'application/json' | ||
body = JSON.stringify(body) | ||
} else if (body && !headers['content-type']) { | ||
headers['content-type'] = 'application/octet-stream' | ||
} | ||
if (opts.get('query')) { | ||
let q = opts.get('query') | ||
console.log('got query:', q) | ||
if (typeof q === 'string') { | ||
q = qs.parse(q) | ||
} | ||
const parsed = url.parse(uri) | ||
parsed.search = '?' + qs.stringify( | ||
parsed.query | ||
? Object.assign(qs.parse(parsed.query), q) | ||
: q | ||
) | ||
uri = url.format(parsed) | ||
} | ||
return fetch(uri, { | ||
agent: opts.agent, | ||
algorithms: opts.algorithms, | ||
agent: opts.get('agent'), | ||
algorithms: opts.get('algorithms'), | ||
body, | ||
cache: getCacheMode(opts), | ||
cacheManager: opts.cache, | ||
ca: opts.ca, | ||
cert: opts.cert, | ||
headers: getHeaders(uri, registry, opts), | ||
integrity: opts.integrity, | ||
key: opts.key, | ||
localAddress: opts.localAddress, | ||
maxSockets: opts.maxSockets, | ||
memoize: opts.memoize, | ||
noProxy: opts.noProxy, | ||
Promise: opts.Promise, | ||
proxy: opts.proxy, | ||
referer: opts.refer, | ||
retry: opts.retry, | ||
strictSSL: !!opts.strictSSL, | ||
timeout: opts.timeout, | ||
uid: opts.uid, | ||
gid: opts.gid | ||
}).then(res => { | ||
if (res.headers.has('npm-notice') && !res.headers.has('x-local-cache')) { | ||
opts.log.warn('notice', res.headers.get('npm-notice')) | ||
} | ||
checkWarnings(res, registry, opts) | ||
if (res.status >= 400) { | ||
const err = new Error(`${res.status} ${res.statusText}: ${ | ||
opts.spec ? opts.spec : uri | ||
}`) | ||
err.code = `E${res.status}` | ||
err.uri = uri | ||
err.response = res | ||
err.spec = opts.spec | ||
logRequest(uri, res, startTime, opts) | ||
throw err | ||
} else { | ||
res.body.on('end', () => logRequest(uri, res, startTime, opts)) | ||
return res | ||
} | ||
}) | ||
cacheManager: opts.get('cache'), | ||
ca: opts.get('ca'), | ||
cert: opts.get('cert'), | ||
headers, | ||
integrity: opts.get('integrity'), | ||
key: opts.get('key'), | ||
localAddress: opts.get('local-address'), | ||
maxSockets: opts.get('maxsockets'), | ||
memoize: opts.get('memoize'), | ||
method: opts.get('method') || 'GET', | ||
noProxy: opts.get('noproxy'), | ||
Promise: opts.get('Promise'), | ||
proxy: opts.get('proxy'), | ||
referer: opts.get('refer'), | ||
retry: opts.get('retry') || { | ||
retries: opts.get('fetch-retries'), | ||
factor: opts.get('fetch-retry-factor'), | ||
minTimeout: opts.get('fetch-retry-mintimeout'), | ||
maxTimeout: opts.get('fetch-retry-maxtimeout') | ||
}, | ||
strictSSL: !!opts.get('strict-ssl'), | ||
timeout: opts.get('timeout'), | ||
uid: opts.get('uid'), | ||
gid: opts.get('gid') | ||
}).then(res => checkResponse( | ||
opts.get('method') || 'GET', res, registry, startTime, opts | ||
)) | ||
} | ||
function logRequest (uri, res, startTime, opts) { | ||
const elapsedTime = Date.now() - startTime | ||
const attempt = res.headers.get('x-fetch-attempts') | ||
const attemptStr = attempt && attempt > 1 ? ` attempt #${attempt}` : '' | ||
const cacheStr = res.headers.get('x-local-cache') ? ' (from cache)' : '' | ||
opts.log.http( | ||
'fetch', | ||
`GET ${res.status} ${uri} ${elapsedTime}ms${attemptStr}${cacheStr}` | ||
) | ||
module.exports.json = fetchJSON | ||
function fetchJSON (uri, opts) { | ||
return regFetch(uri, opts).then(res => res.json()) | ||
} | ||
module.exports.pickRegistry = pickRegistry | ||
function pickRegistry (spec, opts) { | ||
spec = npa(spec) | ||
opts = config(opts) | ||
if (!spec.registry) { | ||
throw new Error(`${spec} is not a valid registry dependency spec`) | ||
} | ||
let registry = spec.scope && | ||
opts.get(spec.scope.replace(/^@?/, '@') + ':registry') | ||
if (!registry && opts.get('scope')) { | ||
registry = opts.get( | ||
opts.get('scope').replace(/^@?/, '@') + ':registry' | ||
) | ||
} | ||
if (!registry) { | ||
registry = opts.get('registry') || 'https://registry.npmjs.org/' | ||
} | ||
return registry | ||
} | ||
function getCacheMode (opts) { | ||
return opts.offline | ||
? 'only-if-cached' | ||
: opts.preferOffline | ||
? 'force-cache' | ||
: opts.preferOnline | ||
? 'no-cache' | ||
: 'default' | ||
return opts.get('offline') | ||
? 'only-if-cached' | ||
: opts.get('prefer-offline') | ||
? 'force-cache' | ||
: opts.get('prefer-online') | ||
? 'no-cache' | ||
: 'default' | ||
} | ||
function getHeaders (uri, registry, opts) { | ||
function getHeaders (registry, uri, opts) { | ||
const headers = Object.assign({ | ||
'npm-in-ci': opts.isFromCI, | ||
'npm-scope': opts.projectScope, | ||
'npm-session': opts.npmSession, | ||
'user-agent': opts.userAgent, | ||
'referer': opts.refer | ||
}, opts.headers) | ||
// check for auth settings specific to this registry | ||
let auth = ( | ||
opts.auth && | ||
opts.auth[registryKey(registry)] | ||
) || opts.auth | ||
'npm-in-ci': !!( | ||
opts.get('is-from-ci') || | ||
process.env['CI'] === 'true' || | ||
process.env['TDDIUM'] || | ||
process.env['JENKINS_URL'] || | ||
process.env['bamboo.buildKey'] || | ||
process.env['GO_PIPELINE_NAME'] | ||
), | ||
'npm-scope': opts.get('project-scope'), | ||
'npm-session': opts.get('npm-session'), | ||
'user-agent': opts.get('user-agent'), | ||
'referer': opts.get('refer') | ||
}, opts.get('headers')) | ||
const auth = getAuth(registry, opts) | ||
// If a tarball is hosted on a different place than the manifest, only send | ||
// credentials on `alwaysAuth` | ||
const shouldAuth = auth && ( | ||
const shouldAuth = ( | ||
auth.alwaysAuth || | ||
@@ -116,47 +160,6 @@ url.parse(uri).host === url.parse(registry).host | ||
} | ||
if (shouldAuth && auth.otp) { | ||
headers['npm-otp'] = auth.otp | ||
} | ||
return headers | ||
} | ||
// Called a nerf dart in the main codebase. Used as a "safe" | ||
// key when fetching registry info from config. | ||
function registryKey (registry) { | ||
const parsed = url.parse(registry) | ||
const formatted = url.format({ | ||
host: parsed.host, | ||
pathname: parsed.pathname, | ||
slashes: parsed.slashes | ||
}) | ||
return url.resolve(formatted, '.') | ||
} | ||
function checkWarnings (res, registry, opts) { | ||
if (res.headers.has('warning') && !BAD_HOSTS.has(registry)) { | ||
const warnings = {} | ||
res.headers.raw()['warning'].forEach(w => { | ||
const match = w.match(WARNING_REGEXP) | ||
if (match) { | ||
warnings[match[1]] = { | ||
code: match[1], | ||
host: match[2], | ||
message: match[3], | ||
date: new Date(match[4]) | ||
} | ||
} | ||
}) | ||
BAD_HOSTS.set(registry, true) | ||
if (warnings['199']) { | ||
if (warnings['199'].message.match(/ENOTFOUND/)) { | ||
opts.log.warn('registry', `Using stale data from ${registry} because the host is inaccessible -- are you offline?`) | ||
} else { | ||
opts.log.warn('registry', `Unexpected warning for ${registry}: ${warnings['199'].message}`) | ||
} | ||
} | ||
if (warnings['111']) { | ||
// 111 Revalidation failed -- we're using stale data | ||
opts.log.warn( | ||
'registry', | ||
`Using stale data from ${registry} due to a request error during revalidation.` | ||
) | ||
} | ||
} | ||
} |
@@ -1,21 +0,16 @@ | ||
The MIT License (MIT) | ||
Copyright (c) 2017 npm, Inc | ||
ISC License | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
Copyright (c) npm, Inc. | ||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
Permission to use, copy, modify, and/or distribute this software for | ||
any purpose with or without fee is hereby granted, provided that the | ||
above copyright notice and this permission notice appear in all copies. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||
OR OTHER DEALINGS IN THE SOFTWARE. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE COPYRIGHT HOLDER DISCLAIMS | ||
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE | ||
COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS | ||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | ||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE | ||
USE OR PERFORMANCE OF THIS SOFTWARE. |
{ | ||
"name": "npm-registry-fetch", | ||
"version": "0.0.2", | ||
"version": "1.0.0", | ||
"description": "Fetch-based http client for use with npm registry APIs", | ||
@@ -13,5 +13,5 @@ "main": "index.js", | ||
"postrelease": "npm publish && git push --follow-tags", | ||
"pretest": "standard lib test *.js", | ||
"pretest": "standard", | ||
"release": "standard-version -s", | ||
"test": "nyc --all -- tap -J test/*.js", | ||
"test": "tap -J --coverage test/*.js", | ||
"update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'", | ||
@@ -31,14 +31,21 @@ "update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'" | ||
}, | ||
"license": "MIT", | ||
"license": "ISC", | ||
"dependencies": { | ||
"lru-cache": "^4.1.1", | ||
"make-fetch-happen": "^2.5.0", | ||
"npmlog": "^4.1.2", | ||
"bluebird": "^3.5.1", | ||
"figgy-pudding": "^2.0.1", | ||
"lru-cache": "^4.1.2", | ||
"make-fetch-happen": "^3.0.0", | ||
"npm-package-arg": "^6.0.0", | ||
"safe-buffer": "^5.1.1" | ||
}, | ||
"devDependencies": { | ||
"nyc": "^11.1.0", | ||
"standard": "^10.0.2", | ||
"cacache": "^10.0.4", | ||
"mkdirp": "^0.5.1", | ||
"nock": "^9.2.3", | ||
"npmlog": "^4.1.2", | ||
"rimraf": "^2.6.2", | ||
"ssri": "^5.3.0", | ||
"standard": "^11.0.1", | ||
"standard-version": "^4.2.0", | ||
"tap": "^10.7.0", | ||
"tap": "^11.1.2", | ||
"weallbehave": "^1.2.0", | ||
@@ -45,0 +52,0 @@ "weallcontribute": "^1.0.8" |
@@ -1,9 +0,10 @@ | ||
# npm-registry-fetch [![npm version](https://img.shields.io/npm/v/npm-registry-fetch.svg)](https://npm.im/npm-registry-fetch) [![license](https://img.shields.io/npm/l/npm-registry-fetch.svg)](https://npm.im/npm-registry-fetch) [![Travis](https://img.shields.io/travis/npm/registry-fetch.svg)](https://travis-ci.org/npm/registry-fetch) [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/npm/registry-fetch?svg=true)](https://ci.appveyor.com/project/npm/registry-fetch) [![Coverage Status](https://coveralls.io/repos/github/npm/registry-fetch/badge.svg?branch=latest)](https://coveralls.io/github/npm/registry-fetch?branch=latest) | ||
# npm-registry-fetch [![npm version](https://img.shields.io/npm/v/npm-registry-fetch.svg)](https://npm.im/npm-registry-fetch) [![license](https://img.shields.io/npm/l/npm-registry-fetch.svg)](https://npm.im/npm-registry-fetch) [![Travis](https://img.shields.io/travis/npm/npm-registry-fetch/latest.svg)](https://travis-ci.org/npm/npm-registry-fetch) [![AppVeyor](https://img.shields.io/appveyor/ci/npm/npm-registry-fetch/latest.svg)](https://ci.appveyor.com/project/npm/npm-registry-fetch) [![Coverage Status](https://coveralls.io/repos/github/npm/npm-registry-fetch/badge.svg?branch=latest)](https://coveralls.io/github/npm/npm-registry-fetch?branch=latest) | ||
[`npm-registry-fetch`](https://github.com/npm/npm-registry-fetch) is a Node.js | ||
library that implements a `fetch`-like API for accessing npm registry APIs consistently. | ||
library that implements a `fetch`-like API for accessing npm registry APIs | ||
consistently. | ||
## Install | ||
`$ npm install npm-logical-tree` | ||
`$ npm install npm-registry-fetch` | ||
@@ -21,2 +22,7 @@ ## Table of Contents | ||
```javascript | ||
const npmFetch = require('npm-registry-fetch') | ||
console.log( | ||
await npmFetch.json('https://registry.npmjs.org/-/ping') | ||
) | ||
``` | ||
@@ -41,3 +47,3 @@ | ||
#### <a name="fetch"></a> `> fetch(url, [opts]) -> Promise<` | ||
#### <a name="fetch"></a> `> fetch(url, [opts]) -> Promise<Response>` | ||
@@ -49,2 +55,20 @@ Performs a request to a given registry URL. | ||
```javascript | ||
const fetch = require('npm-registry-fetch') | ||
const res = await fetch('https://registry.npmjs.org/-/ping') | ||
console.log(res.headers) | ||
res.on('data', d => console.log(d.toString('utf8'))) | ||
``` | ||
#### <a name="fetch"></a> `> fetch.json(url, [opts]) -> Promise<ResponseJSON>` | ||
Performs a request to a given registry URL, parses the body of the response as | ||
JSON, and returns it as its final value. This is a utility shorthand for | ||
`fetch(url).then(res => res.json())`. | ||
##### Example | ||
```javascript | ||
const fetch = require('npm-registry-fetch') | ||
const res = await fetch.json('https://registry.npmjs.org/-/ping') | ||
console.log(res) | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 5 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
19464
10
446
1
72
6
11
11
2
+ Addedbluebird@^3.5.1
+ Addedfiggy-pudding@^2.0.1
+ Addednpm-package-arg@^6.0.0
+ Addedbuiltins@1.0.3(transitive)
+ Addedfiggy-pudding@2.0.1(transitive)
+ Addedhosted-git-info@2.8.9(transitive)
+ Addedmake-fetch-happen@3.0.0(transitive)
+ Addedmississippi@3.0.0(transitive)
+ Addednpm-package-arg@6.1.1(transitive)
+ Addedos-homedir@1.0.2(transitive)
+ Addedos-tmpdir@1.0.2(transitive)
+ Addedosenv@0.1.5(transitive)
+ Addedpump@3.0.2(transitive)
+ Addedsemver@5.7.2(transitive)
+ Addedvalidate-npm-package-name@3.0.0(transitive)
- Removednpmlog@^4.1.2
- Removedansi-regex@2.1.1(transitive)
- Removedare-we-there-yet@1.1.7(transitive)
- Removedcode-point-at@1.1.0(transitive)
- Removedconsole-control-strings@1.1.0(transitive)
- Removeddelegates@1.0.0(transitive)
- Removedgauge@2.7.4(transitive)
- Removedhas-unicode@2.0.1(transitive)
- Removedis-fullwidth-code-point@1.0.0(transitive)
- Removedmake-fetch-happen@2.6.0(transitive)
- Removedmississippi@1.3.1(transitive)
- Removednpmlog@4.1.2(transitive)
- Removednumber-is-nan@1.0.1(transitive)
- Removedobject-assign@4.1.1(transitive)
- Removedpump@1.0.3(transitive)
- Removedset-blocking@2.0.0(transitive)
- Removedsignal-exit@3.0.7(transitive)
- Removedstring-width@1.0.2(transitive)
- Removedstrip-ansi@3.0.1(transitive)
- Removedwide-align@1.1.5(transitive)
Updatedlru-cache@^4.1.2
Updatedmake-fetch-happen@^3.0.0