Socket
Socket
Sign inDemoInstall

@percy/client

Package Overview
Dependencies
Maintainers
6
Versions
238
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@percy/client - npm Package Compare versions

Comparing version 1.0.0-beta.65 to 1.0.0-beta.66

17

dist/client.js

@@ -18,8 +18,4 @@ "use strict";

var _request = _interopRequireWildcard(require("./request"));
var _request = _interopRequireDefault(require("./request"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -73,10 +69,3 @@

this.clientInfo = new Set([].concat(clientInfo));
this.environmentInfo = new Set([].concat(environmentInfo)); // only use a proxy agent for production https requests
if (apiUrl.startsWith('https:')) {
this.httpsAgent = new _request.ProxyHttpsAgent({
keepAlive: true,
maxSockets: 5
});
}
this.environmentInfo = new Set([].concat(environmentInfo));
} // Adds additional unique client info.

@@ -126,3 +115,2 @@

method: 'GET',
agent: this.httpsAgent,
headers: this.headers()

@@ -136,3 +124,2 @@ });

method: 'POST',
agent: this.httpsAgent,
body: JSON.stringify(body),

@@ -139,0 +126,0 @@ headers: this.headers({

307

dist/request.js

@@ -6,7 +6,9 @@ "use strict";

});
exports.port = port;
exports.href = href;
exports.getProxy = getProxy;
exports.proxyAgentFor = proxyAgentFor;
exports.default = request;
exports.ProxyHttpsAgent = void 0;
exports.ProxyHttpsAgent = exports.ProxyHttpAgent = void 0;
var _url = _interopRequireDefault(require("url"));
var _net = _interopRequireDefault(require("net"));

@@ -26,2 +28,4 @@

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
const CRLF = '\r\n';

@@ -32,48 +36,129 @@ const STATUS_REG = /^HTTP\/1.[01] (\d*)/;

const port = ({
port,
protocol
}) => port || protocol === 'https:' && 443 || 80; // Proxified https agent
function port(options) {
if (options.port) return options.port;
return options.protocol === 'https:' ? 443 : 80;
}
function href(options) {
let {
protocol,
hostname,
path,
pathname,
search,
hash
} = options;
return `${protocol}//${hostname}:${port(options)}` + (path || `${pathname || ''}${search || ''}${hash || ''}`);
}
class ProxyHttpsAgent extends _https.default.Agent {
// enforce request options
;
function getProxy(options) {
let proxyUrl = options.protocol === 'https:' && (process.env.https_proxy || process.env.HTTPS_PROXY) || process.env.http_proxy || process.env.HTTP_PROXY;
let shouldProxy = !!proxyUrl && !(0, _utils.hostnameMatches)(process.env.no_proxy || process.env.NO_PROXY, href(options));
if (shouldProxy) {
proxyUrl = new URL(proxyUrl);
let isHttps = proxyUrl.protocol === 'https:';
if (!isHttps && proxyUrl.protocol !== 'http:') {
throw new Error(`Unsupported proxy protocol: ${proxyUrl.protocol}`);
}
let proxy = {
isHttps
};
proxy.auth = !!proxyUrl.username && 'Basic ' + (proxyUrl.password ? Buffer.from(`${proxyUrl.username}:${proxyUrl.password}`) : Buffer.from(proxyUrl.username)).toString('base64');
proxy.host = proxyUrl.hostname;
proxy.port = port(proxyUrl);
proxy.connect = () => (isHttps ? _tls.default : _net.default).connect({
rejectUnauthorized: options.rejectUnauthorized,
host: proxy.host,
port: proxy.port
});
return proxy;
}
} // Proxified http agent
class ProxyHttpAgent extends _http.default.Agent {
constructor(...args) {
super(...args);
_defineProperty(this, "httpsAgent", new _https.default.Agent({
keepAlive: true
}));
}
addRequest(request, options) {
var _options$rejectUnauth;
var _request$outputData;
options.href || (options.href = _url.default.format({
protocol: options.protocol,
hostname: options.hostname,
port: options.port,
slashes: true
}) + options.path);
options.uri || (options.uri = new URL(options.href));
let proxyUrl = options.uri.protocol === 'https:' && (process.env.https_proxy || process.env.HTTPS_PROXY) || process.env.http_proxy || process.env.HTTP_PROXY;
let shouldProxy = !!proxyUrl && !(0, _utils.hostnameMatches)(process.env.no_proxy || process.env.NO_PROXY, options.href);
if (shouldProxy) options.proxy = new URL(proxyUrl); // useful when testing
let proxy = getProxy(options);
if (!proxy) return super.addRequest(request, options);
(0, _logger.default)('client:proxy').debug(`Proxying request: ${options.href}`); // modify the request for proxying
(_options$rejectUnauth = options.rejectUnauthorized) !== null && _options$rejectUnauth !== void 0 ? _options$rejectUnauth : options.rejectUnauthorized = this.rejectUnauthorized;
return super.addRequest(request, options);
} // proxy https requests using a TLS connection
request.path = href(options);
if (proxy.auth) {
request.setHeader('Proxy-Authorization', proxy.auth);
} // regenerate headers since we just changed things
createConnection(options, callback) {
let {
uri,
proxy
} = options;
let isProxyHttps = (proxy === null || proxy === void 0 ? void 0 : proxy.protocol) === 'https:';
if (!proxy) {
return super.createConnection(options, callback);
} else if (proxy.protocol !== 'http:' && !isProxyHttps) {
throw new Error(`Unsupported proxy protocol: ${proxy.protocol}`);
} // setup socket and listeners
delete request._header;
request._implicitHeader();
let socket = (isProxyHttps ? _tls.default : _net.default).connect({ ...options,
host: proxy.hostname,
port: port(proxy)
if (((_request$outputData = request.outputData) === null || _request$outputData === void 0 ? void 0 : _request$outputData.length) > 0) {
let first = request.outputData[0].data;
let endOfHeaders = first.indexOf(CRLF.repeat(2)) + 4;
request.outputData[0].data = request._header + first.substring(endOfHeaders);
} // coerce the connection to the proxy
options.port = proxy.port;
options.host = proxy.host;
delete options.path;
if (proxy.isHttps) {
// use the underlying https agent to complete the connection
request.agent = this.httpsAgent;
return this.httpsAgent.addRequest(request, options);
} else {
return super.addRequest(request, options);
}
}
} // Proxified https agent
exports.ProxyHttpAgent = ProxyHttpAgent;
class ProxyHttpsAgent extends _https.default.Agent {
constructor(options) {
// default keep-alive
super({
keepAlive: true,
...options
});
}
createConnection(options, callback) {
let proxy = getProxy(options);
if (!proxy) return super.createConnection(options, callback);
(0, _logger.default)('client:proxy').debug(`Proxying request: ${href(options)}`); // generate proxy connect message
let host = `${options.hostname}:${port(options)}`;
let connectMessage = [`CONNECT ${host} HTTP/1.1`, `Host: ${host}`];
if (proxy.auth) {
connectMessage.push(`Proxy-Authorization: ${proxy.auth}`);
}
connectMessage = connectMessage.join(CRLF);
connectMessage += CRLF.repeat(2); // start the proxy connection and setup listeners
let socket = proxy.connect();
let handleError = err => {

@@ -102,55 +187,50 @@ socket.destroy(err);

options.socket = socket;
options.servername = uri.hostname; // callback not passed in so not to be added as a listener
options.servername = options.hostname; // callback not passed in so not to be added as a listener
callback(null, super.createConnection(options));
}; // write proxy connect message to the socket
}; // send and handle the connect message
let host = `${uri.hostname}:${port(uri)}`;
let connectMessage = [`CONNECT ${host} HTTP/1.1`, `Host: ${host}`];
if (proxy.username) {
let auth = proxy.username;
if (proxy.password) auth += `:${proxy.password}`;
connectMessage.push(`Proxy-Authorization: basic ${Buffer.from(auth).toString('base64')}`);
}
connectMessage = connectMessage.join(CRLF);
connectMessage += CRLF.repeat(2);
(0, _logger.default)('client:proxy').debug(`Proxying request: ${options.href}`);
socket.on('error', handleError).on('close', handleClose).on('data', handleData).write(connectMessage);
}
} // Returns true or false if an error should cause the request to be retried
}
exports.ProxyHttpsAgent = ProxyHttpsAgent;
function shouldRetryRequest(error, retryNotFound) {
if (error.response) {
/* istanbul ignore next: client does not retry 404s, but other internal libs may want to */
return !!retryNotFound && error.response.status === 404 || error.response.status >= 500 && error.response.status < 600;
} else if (error.code) {
return RETRY_ERROR_CODES.includes(error.code);
} else {
return false;
function proxyAgentFor(url, options) {
let cache = proxyAgentFor.cache || (proxyAgentFor.cache = new Map());
let {
protocol,
hostname
} = new URL(url);
let cachekey = `${protocol}//${hostname}`;
if (!cache.has(cachekey)) {
cache.set(cachekey, protocol === 'https:' ? new ProxyHttpsAgent(options) : new ProxyHttpAgent(options));
}
} // Returns a promise that resolves when the request is successful and rejects
// when a non-successful response is received. The rejected error contains
// response data and any received error details. Server 500 errors are retried
// up to 5 times at 50ms intervals.
return cache.get(cachekey);
} // Proxified request function that resolves with the response body when the request is successful
// and rejects when a non-successful response is received. The rejected error contains response data
// and any received error details. Server 500 errors are retried up to 5 times at 50ms intervals by
// default, and 404 errors may also be optionally retried. If a callback is provided, it is called
// with the parsed response body and response details. If the callback returns a value, that value
// will be returned in the final resolved promise instead of the response body.
function request(url, {
body,
retries,
retryNotFound,
interval,
...options
}) {
/* istanbul ignore next: the client api is https only, but this helper is borrowed in some
* cli-exec commands for its retryability with the internal api */
function request(url, options = {}, callback) {
// accept `request(url, callback)`
if (typeof options === 'function') [options, callback] = [{}, options];
let {
request
} = url.startsWith('https:') ? _https.default : _http.default;
body,
retries,
retryNotFound,
interval,
noProxy,
...requestOptions
} = options; // allow bypassing proxied requests entirely
if (!noProxy) requestOptions.agent || (requestOptions.agent = proxyAgentFor(url)); // parse the requested URL into request options
let {

@@ -161,41 +241,60 @@ protocol,

pathname,
search
search,
hash
} = new URL(url);
options = { ...options,
protocol,
hostname,
port,
path: pathname + search
};
return (0, _utils.retry)((resolve, reject, retry) => {
let handleError = error => {
return shouldRetryRequest(error, retryNotFound) ? retry(error) : reject(error);
if (handleError.handled) return;
handleError.handled = true;
let shouldRetry = error.response // maybe retry 404s and always retry 500s
? retryNotFound && error.response.status === 404 || error.response.status >= 500 && error.response.status < 600 : !!error.code && RETRY_ERROR_CODES.includes(error.code);
return shouldRetry ? retry(error) : reject(error);
};
request(options).on('response', res => {
let status = res.statusCode;
let raw = '';
res.setEncoding('utf8').on('data', chunk => raw += chunk).on('error', handleError).on('end', () => {
let body = raw;
let handleFinished = async (body, res) => {
let raw = body; // attempt to parse the body as json
try {
body = JSON.parse(raw);
} catch (e) {}
try {
body = JSON.parse(body);
} catch (e) {}
if (status >= 200 && status < 300) {
resolve(body);
try {
if (res.statusCode >= 200 && res.statusCode < 300) {
var _await$callback, _callback;
// resolve successful statuses after the callback
resolve((_await$callback = await ((_callback = callback) === null || _callback === void 0 ? void 0 : _callback(body, res))) !== null && _await$callback !== void 0 ? _await$callback : body);
} else {
var _body, _body$errors, _body$errors$find;
handleError(Object.assign(new Error(), {
response: {
status,
body
},
// use first error detail or the status message
message: ((_body = body) === null || _body === void 0 ? void 0 : (_body$errors = _body.errors) === null || _body$errors === void 0 ? void 0 : (_body$errors$find = _body$errors.find(e => e.detail)) === null || _body$errors$find === void 0 ? void 0 : _body$errors$find.detail) || `${status} ${res.statusMessage || raw}`
}));
// use the first error detail or the status message
throw new Error(((_body = body) === null || _body === void 0 ? void 0 : (_body$errors = _body.errors) === null || _body$errors === void 0 ? void 0 : (_body$errors$find = _body$errors.find(e => e.detail)) === null || _body$errors$find === void 0 ? void 0 : _body$errors$find.detail) || `${res.statusCode} ${res.statusMessage || raw}`);
}
});
}).on('error', handleError).end(body);
} catch (error) {
handleError(Object.assign(error, {
response: {
status: res.statusCode,
body
}
}));
}
};
let handleResponse = res => {
let body = '';
res.setEncoding('utf8');
res.on('data', chunk => body += chunk);
res.on('end', () => handleFinished(body, res));
res.on('error', handleError);
};
let req = (protocol === 'https:' ? _https.default : _http.default).request({ ...requestOptions,
path: pathname + search + hash,
protocol,
hostname,
port
});
req.on('response', handleResponse);
req.on('error', handleError);
req.end(body);
}, {

@@ -202,0 +301,0 @@ retries,

{
"name": "@percy/client",
"version": "1.0.0-beta.65",
"version": "1.0.0-beta.66",
"license": "MIT",

@@ -26,4 +26,4 @@ "main": "dist/index.js",

"dependencies": {
"@percy/env": "1.0.0-beta.65",
"@percy/logger": "1.0.0-beta.65"
"@percy/env": "1.0.0-beta.66",
"@percy/logger": "1.0.0-beta.66"
},

@@ -35,3 +35,3 @@ "repository": {

},
"gitHead": "19a727cb92b9b6c06dec9ccec7cc198b0d8f1e12"
"gitHead": "740a335bab4966f7dda4e4693505e17a5fdcfd4c"
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc