Socket
Socket
Sign inDemoInstall

protoblast

Package Overview
Dependencies
1
Maintainers
1
Versions
101
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.7.9 to 0.7.10

.github/workflows/unit_test.yaml

11

CHANGELOG.md

@@ -0,1 +1,12 @@

## 0.7.10 (2021-08-07)
* Add `Request.lookup()` method which caches DNS lookups for 60 seconds
* Add more `Request` methods so no external `xhr` access is required
* Add `Request` caching
* Add `Blast.mkdirp()` and `Blast.mkdirpSync()` methods
* Add `Blast.rmrf()` and `Blast.rmrfSync()` methods
* Add temporary files methods: `Blast.generateTempPath()`, `Blast.openTempFile()`, `Blast.cleanupTempPaths()`, ...
* Fix the `String#replaceAll()` polyfill
* Fix `TimeoutPledge` not actually running its executor
## 0.7.9 (2021-06-11)

@@ -2,0 +13,0 @@

2

lib/function.js

@@ -81,3 +81,3 @@ var tokenMatches,

comment1 : /\/\*[\s\S]*?\*\//,
comment2 : /\/\/.*?\n/,
comment2 : /\/\/.*?(?=\r\n|\r|\n|$)/,
number : /\d+(?:\.\d+)?(?:e[+-]?\d+)?/,

@@ -84,0 +84,0 @@ parens : /[\(\)]/,

@@ -300,5 +300,2 @@ module.exports = function BlastInitLoader(modifyPrototype) {

Blast.ACTIVE_FILE = Symbol('active_file');
// We break this string up so the Blast.convertCoverage doesn't find this
var source_map_url_prefix = '//# sourceMappingURL' + '=data:application/json;charset=utf-8;base64,';
}

@@ -379,3 +376,3 @@ // PROTOBLAST END CUT

// when unit testing
if (module.exports.unit_test) {
if (module.exports.unit_test || Blast.Globals.__is_protoblast_unit_test) {
Blast.Shims = {};

@@ -676,3 +673,3 @@ }

// In node, every global is an own property of the `global` object
Globals[name] = constructor;
Globals[name] = value;
} else {

@@ -953,464 +950,3 @@ // In the browser, it's mostly a property of the window prototype

//PROTOBLAST START CUT
let os = require('os'),
tmpdir = fs.mkdtempSync(libpath.resolve(os.tmpdir(), 'protoblast')),
cache = {};
/**
* Server side: create client side file
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.1.1
* @version 0.7.2
*
* @param {Object} options
*
* @return {Pledge}
*/
Blast.getClientPath = function getClientPath(options) {
var refresh = false,
ua,
id;
if (!options) {
options = {};
} else {
if (options.ua) {
ua = Blast.parseUseragent(options.ua);
id = ua.family + '-' + ua.major + '.' + ua.minor;
}
if (options.refresh) {
refresh = true;
}
}
let create_source_map = options.create_source_map,
enable_coverage = options.enable_coverage;
// If the source-map module couldn't be loaded, ignore it
if (Blast.sourceMap === false) {
create_source_map = false;
}
// If we want to add coverage, the sourcemap is required!
if (enable_coverage) {
create_source_map = true;
if (!Blast.instrumentSource) {
require('./coverage.js');
}
}
// If we want to make a sourcemap, but the module hasn't been loaded
// try to load it now
if (create_source_map && Blast.sourceMap == null) {
try {
Blast.sourceMap = require('source-map');
} catch (err) {
create_source_map = false;
Blast.sourceMap = false;
}
}
if (!id) {
id = 'full';
}
if (options.use_common) {
id = 'common_' + id;
} else if (options.modify_prototypes) {
id = 'global_' + id;
}
if (enable_coverage) {
id += '_cov';
}
if (cache[id] && !refresh) {
return cache[id];
}
let extra_files = [],
compose_id = '',
extra,
i;
// Now iterate over the extras
for (i = 0; i < extras.length; i++) {
extra = extras[i];
if (!extra.client) {
continue;
}
// See if we've been given a useragent
if (ua && extra.versions && id != 'full' && id != 'full_common') {
let entry = extra.versions[ua.family];
// If the user's browser version is higher than the required max,
// it is also not needed
if (entry && ua.version.float > entry.max) {
continue;
}
}
extra_files.push(extra);
compose_id += i + '-';
}
compose_id = Blast.Bound.Object.checksum(compose_id);
if (enable_coverage) {
compose_id += '_cov';
}
if (cache[compose_id] && !refresh) {
cache[id] = cache[compose_id];
return cache[id];
}
let files = [
'init',
'json-dry',
];
let code = '',
tasks = [];
// The first file should be the template
tasks.push(Blast.getCachedFile('client.js'));
// Queue some basic, pre-wrapped files
files.forEach(function eachFile(name, index) {
var path;
name = name.toLowerCase();
if (name == 'json-dry') {
path = require.resolve('json-dry');
} else {
path = libpath.resolve(__dirname, name + '.js');
}
tasks.push(function getFile(next) {
Blast.getCachedFile(path).then(function gotCode(code) {
let filename = name + '.js';
var data = 'require.register("' + filename + '", function(module, exports, require){\n';
data += code;
data += '});\n';
let result = {
start : 1, // Starts at 1 for the `require` line
code : data,
filename : filename,
name_id : name,
name : name,
path : path,
source : null
};
if (create_source_map) {
result.source = code;
}
next(null, result);
}).catch(next);
});
});
extra_files.forEach(function eachExtraFile(options) {
tasks.push(function getExtraFile(next) {
Blast.getCachedFile(options.path).then(function gotCode(code) {
let source,
start = 0;
if (create_source_map) {
source = code;
}
if (options.add_wrapper !== false) {
if (options.add_wrapper || code.slice(0, 14) != 'module.exports') {
// Add 1 line for the `register` line
start++;
let data = 'module.exports = function(';
if (options.arguments) {
data += Blast.getArgumentConfiguration(options.arguments).names.join(',');
} else {
data += 'Blast, Collection, Bound, Obj, Fn';
}
data += ') {\n';
code = data + code + '\n};';
}
}
let name = options.name_id || options.name,
filename = libpath.basename(options.path);
code = 'require.register("' + name + '", function(module, exports, require){\n'
+ code
+ '});\n';
// Add 1 line for the `require` line
start++;
let result = {
start : start,
code : code,
filename : filename,
name : options.name,
name_id : options.name_id,
path : options.path,
source : null
};
if (create_source_map) {
result.source = source;
}
next(null, result);
}).catch(next);
});
});
cache[id] = new Blast.Classes.Pledge();
cache[compose_id] = cache[id];
Blast.Bound.Function.parallel(tasks, function gotFiles(err, files) {
if (err) {
return cache[id].reject(err);
}
let current_line,
sourcemap,
template = files.shift(),
index = template.indexOf('//_REGISTER_//'),
filename = libpath.resolve(tmpdir, compose_id + '.js'),
code = '',
file,
i;
let template_start = template.slice(0, index),
template_offset = Blast.Bound.String.count(template_start, '\n');
if (create_source_map) {
sourcemap = new Blast.sourceMap.SourceMapGenerator({
file : compose_id + '.js',
sourceRoot : ''
});
}
for (i = 0; i < files.length; i++) {
file = files[i];
if (code) {
code += '\n';
}
if (create_source_map) {
// Count the current line we're on
current_line = template_offset + Blast.Bound.String.count(code, '\n');
}
if (typeof file == 'string') {
let path = libpath.resolve(__dirname, 'client.js');
code += file;
if (create_source_map) {
// Ugly hack for the client.js file
file = {
start : 0,
code : file,
source : file,
path : path,
name : 'blast_template_client.js'
};
}
} else {
code += file.code;
}
if (create_source_map) {
let filename = file.name;
if (filename.indexOf('.js') == -1) {
filename += '.js';
}
filename = file.path;
sourcemap.setSourceContent(filename, file.source);
let target_line = current_line + (file.start || 0),
end_column,
char_start,
char_end,
tokens,
lines = file.source.split('\n'),
token,
i,
j;
for (i = 0; i < lines.length; i++) {
line = lines[i];
tokens = Blast.Bound.Function.tokenize(line, false);
char_start = 0;
for (j = 0; j < tokens.length; j++) {
char_end = char_start + tokens[j].length;
sourcemap.addMapping({
source : filename,
original : {line: 1 + i, column: char_start},
generated : {line: target_line + i + 1, column: char_start},
name : tokens[j]
});
char_start = char_end;
}
}
}
}
if (options.use_common) {
code += '\nuse_common = true;\n';
} else if (options.modify_prototypes) {
code += '\nmodify_prototypes = true;\n';
}
let client_extras = [];
extra_files.forEach(function eachExtraFile(options) {
if (options.client === false || options.is_extra === false) {
return;
}
client_extras.push([options.name_id, options.arguments]);
});
code += '\nclient_extras = ' + JSON.stringify(client_extras) + ';\n';
template = template_start + code + template.slice(index);
let cut_rx = /\/\/\s?PROTOBLAST\s?START\s?CUT([\s\S]*?)(\/\/\s?PROTOBLAST\s?END\s?CUT)/gm;
// Remove everything between "PROTOBLAST START CUT" and "PROTOBLAST END CUT" (with slashes)
if (create_source_map) {
// Instead of actually cutting the code when making a sourcemap,
// the code is commented
template = template.replace(cut_rx, function doReplace(match) {
let result = '',
lines = match.split('\n'),
line,
i;
for (i = 0; i < lines.length; i++) {
if (i) {
result += '\n';
}
line = lines[i];
result += '// ' + line;
}
return result;
});
let sourcemap_64 = Buffer.from(sourcemap.toString()).toString('base64');
let inline_source_map = source_map_url_prefix + sourcemap_64;
template += '\n' + inline_source_map;
} else {
template = template.replace(cut_rx, '');
}
if (enable_coverage) {
template = Blast.instrumentSource(template, 'test_path.js', JSON.parse(sourcemap.toString())).code;
}
let retries = 0;
function retryWithTempdir(filename, template) {
retries++;
fs.mkdtemp(libpath.resolve(os.tmpdir(), 'protoblast'), function madeDir(err, result) {
if (err) {
return cache[id].reject(err);
}
tmpdir = result;
filename = libpath.resolve(tmpdir, compose_id + '.js')
writeFile(filename, template);
});
}
function writeFile(filename, template) {
fs.writeFile(filename, template, function written(err) {
if (err) {
if (retries == 0) {
return retryWithTempdir(filename, template);
}
return cache[id].reject(err);
}
cache[id].resolve(filename);
});
}
writeFile(filename, template);
});
return cache[id];
};
/**
* Get a file and cache it
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.7.0
* @version 0.7.0
*
* @param {String} path
*
* @return {Promise}
*/
Blast.getCachedFile = function getCachedFile(path) {
if (path[0] != '/') {
path = libpath.resolve(__dirname, path);
}
return new Promise(function doReadFile(resolve, reject) {
fs.readFile(path, 'utf8', function gotResult(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
};
require('./server_functions.js')(Blast, extras);
//PROTOBLAST END CUT

@@ -1642,2 +1178,31 @@

/**
* Do a synchronous sleep (blocking the eventloop!)
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @param {number} duration
*/
Blast.sleepSync = function sleepSync(duration) {
const valid = duration < Infinity;
if (!valid) {
throw new Error('Unable to sleep, duration is not valid: "' + duration + '"');
}
if (typeof SharedArrayBuffer !== 'undefined' && typeof Atomics !== 'undefined') {
const nil = new Int32Array(new SharedArrayBuffer(4));
Atomics.wait(nil, 0, 0, Number(duration));
} else {
const target = Date.now() + Number(duration);
while (target > Date.now()) {
// Let's go CPU!
}
}
};
//PROTOBLAST START CUT

@@ -1644,0 +1209,0 @@ /**

@@ -974,3 +974,3 @@ var PENDING = 0,

* @since 0.7.1
* @version 0.7.1
* @version 0.7.10
*

@@ -991,4 +991,10 @@ * @param {Function} executor

this.executor = executor;
if (typeof timeout != 'number') {
timeout = +timeout;
}
if (!timeout) {
timeout = 0;
}
setTimeout(function checkTimeout() {

@@ -1009,2 +1015,4 @@

}, timeout);
TimeoutPledge.super.call(this, executor);
});

@@ -1011,0 +1019,0 @@

@@ -7,2 +7,74 @@ var Request = Blast.Classes.Develry.Request,

/**
* The XMLHttpRequest instance,
* which is doing the actual browser-side request
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {XMLHttpRequest}
*/
Request.setProperty('xhr', null);
/**
* The original XHR response instance
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {Response}
*/
Request.setProperty('xhr_res', null);
/**
* Allow parsing responses as JSON-Dry by default
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {boolean}
*/
Request.setProperty('allow_json_dry_response', true);
/**
* Get the current response status
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {number}
*/
Request.setProperty(function status() {
if (this.xhr) {
return this.xhr.status;
}
if (this.cached_request) {
return this.cached_request.status;
}
});
/**
* Get the current response status message
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {string}
*/
Request.setProperty(function status_message() {
if (this.xhr) {
return this.xhr.statusText;
}
if (this.cached_request) {
return this.cached_request.status_message;
}
});
/**
* Actually make the request

@@ -50,2 +122,3 @@ *

pledge.cancel = function cancel() {
that.cancelled = true;
xhr.abort();

@@ -155,4 +228,6 @@ };

response = xhr.response || xhr.responseText;
that.response = response;
that.xhr_res = response;
type = xhr.getResponseHeader('content-type') || '';
that.status = xhr.status;
that.statusText = xhr.statusText;

@@ -284,23 +359,8 @@ if (type && type.indexOf(';') > -1) {

if (!error && xhr.status > 399) {
error = new Error(xhr.statusText);
error.status = error.number = xhr.status;
}
let parsed = that._parseResponse(result, error);
if (type && type.indexOf('json') > -1 && result) {
try {
result = Collection.JSON.undry(result);
} catch (err) {
console.error('Error parsing JSON string from "' + that.url.path + '":', result, err);
return pledge.reject(err);
}
}
if (error) {
error.result = result;
pledge.reject(error);
that.error = error;
if (parsed.error) {
pledge.reject(parsed.error);
} else {
that.result = result;
pledge.resolve(result);
pledge.resolve(parsed.result);
Blast.state.reportSuccess();

@@ -337,9 +397,36 @@ }

* @since 0.7.0
* @version 0.7.0
* @version 0.7.10
*/
Request.setMethod(function getResponseHeader(name) {
return this.xhr.getResponseHeader(name);
if (this.xhr) {
return this.xhr.getResponseHeader(name);
}
if (this.cached_request) {
return this.cached_request.getResponseHeader(name);
}
});
/**
* Get all the response header
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @return {object}
*/
Request.setMethod(function getAllResponseHeaders() {
if (this.xhr) {
return this.xhr.getAllResponseHeaders();
}
if (this.cached_request) {
return this.cached_request.getAllResponseHeaders();
}
});
/**
* Hook into the original open method

@@ -346,0 +433,0 @@ *

@@ -1,5 +0,7 @@

var Request = Blast.Classes.Develry.Request,
var dns_cache,
Request = Blast.Classes.Develry.Request,
https,
http,
zlib;
zlib,
dns;

@@ -10,2 +12,3 @@ if (Blast.isNW) {

zlib = nw.require('zlib');
dns = nw.require('dns');
} else {

@@ -15,5 +18,135 @@ https = require('https');

zlib = require('zlib');
dns = require('dns');
}
/**
* Server-side DNS lookup with caching
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*/
Request.setStatic(function lookup(hostname, options, callback) {
let start = Date.now();
if (!dns_cache) {
dns_cache = new Blast.Classes.Develry.Cache({
max_age : 60 * 1000,
});
}
if (typeof options == 'function') {
callback = options;
options = {};
}
let key = Blast.Bound.Object.checksum([hostname, options]),
result;
if (dns_cache.has(key)) {
result = dns_cache.get(key);
return resolve(result);
}
let pledge = new Blast.Classes.Pledge();
dns_cache.set(key, pledge);
dns.lookup(hostname, options, (...response) => {
dns_cache.set(key, response);
resolve(response);
});
function resolve(result) {
let dur = Date.now() - start;
// If it's an array, we can callback
if (Blast.Classes.Array.isArray(result)) {
return Blast.setImmediate(() => {
callback(...result);
});
}
// If not, it's thennable and we need to wait for it
Blast.Classes.Pledge.done(result, (err, ...result) => {
callback(...result);
});
}
});
/**
* The ClientRequest instance:
* the Node.js outgoing request
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {ClientRequest}
*/
Request.setProperty('outgoing_req', null);
/**
* The IncomingMessage instance:
* the Node.js response to the ClientRequest
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {IncomingMessage}
*/
Request.setProperty('incoming_res', null);
/**
* Do not allow parsing responses as JSON-Dry by default
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {boolean}
*/
Request.setProperty('allow_json_dry_response', false);
/**
* Get the current response status
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {number}
*/
Request.setProperty(function status() {
if (this.incoming_res) {
return this.incoming_res.statusCode;
}
if (this.cached_request) {
return this.cached_request.status;
}
});
/**
* Get the current response status message
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {string}
*/
Request.setProperty(function status_message() {
if (this.incoming_res) {
return this.incoming_res.statusMessage;
}
if (this.cached_request) {
return this.cached_request.status_message;
}
});
/**
* Actually make a request

@@ -37,4 +170,3 @@ *

body = this.body,
url,
req;
url;

@@ -57,3 +189,4 @@ if (options) {

headers : this.headers,
method : method.method
method : method.method,
lookup : Request.lookup
};

@@ -91,4 +224,6 @@

// Create the request
req = protocol.request(config, function gotResponse(res) {
this.outgoing_req = protocol.request(config, (res) => {
this.incoming_res = res;
var output,

@@ -102,3 +237,3 @@ gzip,

// Follow redirects if there are any
if (res.statusCode > 299 && res.statusCode < 400) {
if (this.status > 299 && this.status < 400) {

@@ -117,4 +252,2 @@ // Increase the redirect count

that.response = res;
// If an error occurs, call the callback with it

@@ -144,33 +277,4 @@ res.on('error', function gotResponseError(err) {

output.on('end', function ended() {
var error_data,
error;
if (res.headers['content-type'] && (~res.headers['content-type'].indexOf('json'))) {
body = Blast.Bound.JSON.safeParse(body);
}
if (res.statusCode >= 400) {
error = res.statusCode + ' - ' + res.statusMessage + '\n';
if (body && typeof body == 'object') {
if (body.code) {
error += ' Body error code: ' + body.code + '\n';
}
if (body.message) {
error += ' Body error message: ' + body.message + '\n';
}
}
error += 'on ' + config.method + ' ' + String(url) + '\n';
error = new Error(error);
error.request = that;
error.result = body;
} else {
error = null;
}
done(error, body);
let parsed = that._parseResponse(body);
done(parsed.error, parsed.result);
});

@@ -180,3 +284,3 @@ });

// Listen for request errors
req.on('error', function onRequestError(err) {
this.outgoing_req.on('error', function onRequestError(err) {
done(err);

@@ -187,5 +291,5 @@ });

if (is_form) {
handleFormData(body, req);
handleFormData(body, this.outgoing_req);
} else {
req.write(body);
this.outgoing_req.write(body);
}

@@ -196,3 +300,3 @@ }

if (!is_form) {
req.end();
this.outgoing_req.end();
}

@@ -220,2 +324,44 @@

/**
* Get a response header
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @param {string}
*
* @return {string|undefined}
*/
Request.setMethod(function getResponseHeader(name) {
if (this.incoming_res) {
return this.incoming_res.headers[name];
}
if (this.cached_request) {
return this.cached_request.getResponseHeader(name);
}
});
/**
* Get all the response header
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @return {object}
*/
Request.setMethod(function getAllResponseHeaders() {
if (this.incoming_res) {
return this.incoming_res.headers;
}
if (this.cached_request) {
return this.cached_request.getAllResponseHeaders();
}
});
/**
* Handle server-side form data submission

@@ -222,0 +368,0 @@ *

@@ -1,3 +0,5 @@

var method_symbol = Symbol('method'),
url_symbol = Symbol('url');
const ORIGINAL_REQUEST = Symbol('ori_req'),
MAKE_REQUEST = Symbol('make_request'),
METHOD = Symbol('method'),
URL = Symbol('url');

@@ -52,2 +54,17 @@ /**

/**
* A cache instance used for caching GET requests
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @return {Cache}
*/
Request.prepareStaticProperty(function cache() {
return new Blast.Classes.Develry.Cache({
max_age : 60 * 1000,
});
});
/**
* Method info

@@ -128,2 +145,35 @@ *

/**
* The original response data
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {*}
*/
Request.setProperty('raw_response_body', null);
/**
* The parent request we're caching
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {Develry.Request}
*/
Request.setProperty('cached_request', null);
/**
* Was this request cancelled?
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {boolean}
*/
Request.setProperty('cancelled', false);
/**
* Default timeout in ms

@@ -151,2 +201,13 @@ *

/**
* Allow cached responses?
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {boolean|number|null}
*/
Request.setProperty('cache', null);
/**
* Refer to the time_started

@@ -175,4 +236,4 @@ *

if (this[method_symbol]) {
return this[method_symbol];
if (this[METHOD]) {
return this[METHOD];
}

@@ -189,3 +250,3 @@

return this[method_symbol] = method;
return this[METHOD] = method;
});

@@ -216,3 +277,3 @@

Request.setProperty(function url() {
return this[url_symbol];
return this[URL];
}, function setUrl(url) {

@@ -223,2 +284,46 @@ return this.setUrl(url);

/**
* Get the response content type
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {string|undefined}
*/
Request.setProperty(function content_type() {
let content_type = this.getResponseHeader('content-type');
if (content_type) {
if (content_type.indexOf(';') > -1) {
content_type = Bound.String.before(content_type, ';');
}
return content_type;
}
if (Blast.isBrowser && this.xhr_res) {
return this.xhr_res.type;
}
if (this.cached_request) {
return this.cached_request.content_type;
}
});
/**
* Deprecated reference to the status number
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {number}
*/
Request.setProperty(function statusCode() {
return this.status;
});
/**
* Set options

@@ -309,5 +414,5 @@ *

this[url_symbol] = Blast.Classes.RURL.parse(url, origin);
this[URL] = Blast.Classes.RURL.parse(url, origin);
} else {
this[url_symbol] = url;
this[URL] = url;
}

@@ -355,3 +460,3 @@ });

* @since 0.2.0
* @version 0.7.0
* @version 0.7.10
*

@@ -378,7 +483,196 @@ * @return {Pledge}

let pledge,
key;
if (this.method == 'GET' && this.cache !== false && this.blast_cache !== false) {
key = Blast.Classes.Object.checksum([this.url.href, this.headers, this.download_if_inline, this.get_stream]);
pledge = Request.cache.get(key);
if (pledge) {
return this._resolveWithCache(pledge, key);
}
}
// Do the response, follow redirects
return this._make_request();
pledge = this[MAKE_REQUEST](key);
return pledge;
});
/**
* Parse a response
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @param {string} response_body
*
* @return {Object}
*/
Request.setMethod(function _parseResponse(response_body, error) {
// Remember the raw response body
this.raw_response_body = response_body;
if (!error && this.status >= 400) {
error = new Error(this.status_message);
error.request = this;
error.status = error.number = this.status;
}
let result;
if (this.content_type && this.content_type.indexOf('json') > -1) {
result = Bound.JSON.safeParse(response_body);
if (this.allow_json_dry_response) {
try {
result = Bound.JSON.undry(result);
} catch (parse_error) {
if (!error) {
error = parse_error;
}
}
}
} else {
result = response_body;
}
if (error) {
error.result = result;
}
if (!error) {
error = null;
}
this.result = result;
this.error = error;
return {
result : result,
error : error,
};
});
/**
* Resolve with a cached response
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @param {Pledge} cached_pledge The Pledge gotten from the cache
* @param {string} key The key that was used in the cache
*
* @return {Pledge}
*/
Request.setMethod(function _resolveWithCache(cached_pledge, key) {
let ori_req = cached_pledge[ORIGINAL_REQUEST];
// If no original request instance is found, or it had an error,
// make the request anyway!
if (!ori_req || ori_req.error || ori_req.cancelled) {
return this[MAKE_REQUEST](key);
}
let result = new Blast.Classes.Pledge();
this.cached_request = ori_req;
result.request = this;
Blast.Classes.Pledge.done(cached_pledge, (err, res) => {
if (err || ori_req.error) {
this.cached_request = null;
result.resolve(this[MAKE_REQUEST](key));
return;
}
this.time_ended = Date.now();
let parsed = this._parseResponse(ori_req.raw_response_body, ori_req.error || err);
if (parsed.error) {
result.reject(parsed.error);
} else {
result.resolve(parsed.result);
}
});
return result;
});
/**
* Make the request and potentially cache it
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @param {string} key The key that should be used in the cache
*
* @return {Pledge}
*/
Request.setMethod(MAKE_REQUEST, function makeRequest(key) {
let pledge = this._make_request();
if (key) {
let max_age;
if (typeof this.cache == 'number') {
max_age = this.cache;
}
Request.cache.set(key, pledge, max_age);
pledge[ORIGINAL_REQUEST] = this;
}
return pledge;
});
/**
* A small Response class
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @param {Develry.Request} request
*/
const Response = Collection.Function.inherits('Informer', 'Develry', function Response(request) {
this.request = request;
});
/**
* Reference to the response status number
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {number}
*/
Response.setProperty(['status', 'statusCode'], function status() {
return this.request.status;
});
/**
* Reference to all the response headers
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 0.7.10
* @version 0.7.10
*
* @type {object}
*/
Response.setProperty(function headers() {
return this.request.getAllResponseHeaders();
});
/**
* Fetch a simple resource

@@ -388,3 +682,3 @@ *

* @since 0.2.0
* @version 0.7.1
* @version 0.7.10
*

@@ -419,9 +713,11 @@ * @param {Object} options

if (callback) {
pledge.done(function done(err, result) {
pledge.done(function done(err, output) {
let response = new Response(req);
if (err) {
return callback(err, req.response);
return callback(err, response);
}
callback(null, req.response, result);
callback(null, response, output);
});

@@ -428,0 +724,0 @@ }

@@ -1556,3 +1556,3 @@ let astral_rx = /\ud83c[\udffb-\udfff](?=\ud83c[\udffb-\udfff])|(?:[^\ud800-\udfff][\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]?|[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?(?:\u200d(?:[^\ud800-\udfff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?)*/g;

* @since 0.1.2
* @version 0.1.2
* @version 0.7.10
*

@@ -1566,21 +1566,16 @@ * @param {String} needle The string to look for

var count,
str,
len,
i;
count = this.match(new RegExp(needle, 'g'));
if (!count) {
if (needle == null) {
return this;
}
str = this;
len = count.length;
if (!Collection.RegExp.isRegExp(needle)) {
let escaped = Collection.RegExp.escape(needle);
needle = Collection.RegExp.interpret(escaped, 'g');
}
for (i = 0; i < len; i++) {
str = str.replace(needle, replacement);
if (needle.flags.indexOf('g') == -1) {
throw TypeError('String.prototype.replaceAll called with a non-global RegExp argument');
}
return str;
return this.replace(needle, replacement);
}, true);

@@ -1587,0 +1582,0 @@

{
"name": "protoblast",
"description": "Native object expansion library",
"version": "0.7.9",
"version": "0.7.10",
"author": "Jelle De Loecker <jelle@elevenways.be>",

@@ -15,3 +15,3 @@ "keywords": [

"dependencies": {
"json-dry" : "~1.1.0"
"json-dry" : "~1.1.0"
},

@@ -22,5 +22,5 @@ "repository": "11ways/protoblast",

"scripts": {
"test" : "mocha --exit --reporter spec --bail --timeout 5000 --file test/00-init.js",
"coverage" : "nyc --reporter=text --reporter=lcov mocha --exit --timeout 20000 --bail --file test/00-init.js",
"report-coverage" : "codecov"
"report-coverage" : "codecov",
"test" : "mocha --exit --reporter spec --bail --timeout 5000 --file test/00-init.js"
},

@@ -30,3 +30,3 @@ "main": "lib/init.js",

"browserify" : "~16.5.1",
"codecov" : "~3.7.0",
"codecov" : "~3.8.3",
"git-rev" : "0.2.1",

@@ -39,3 +39,3 @@ "istanbul-lib-instrument" : "~4.0.3",

"promises-aplus-tests" : "~2.1.2",
"puppeteer" : "~5.1.0",
"puppeteer" : "~10.2.0",
"source-map" : "~0.7.3",

@@ -46,4 +46,4 @@ "uglify-js" : "3.2.0",

"engines": {
"node": ">=10.21.0"
"node" : ">=10.21.0"
}
}

@@ -6,12 +6,7 @@ <h1 align="center">

<div align="center">
<!-- CI - TravisCI -->
<a href="https://travis-ci.org/11ways/protoblast">
<img src="https://travis-ci.org/11ways/protoblast.svg?branch=master" alt="Mac/Linux Build Status" />
<!-- CI - Github Actions -->
<a href="https://github.com/11ways/protoblast/actions/workflows/unit_test.yaml">
<img src="https://github.com/11ways/protoblast/actions/workflows/unit_test.yaml/badge.svg" alt="Node.js CI (Linux, MacOS, Windows)" />
</a>
<!-- CI - AppVeyor -->
<a href="https://ci.appveyor.com/project/skerit/protoblast">
<img src="https://img.shields.io/appveyor/ci/skerit/protoblast/master.svg?label=Windows" alt="Windows Build status" />
</a>
<!-- Coverage - Codecov -->

@@ -18,0 +13,0 @@ <a href="https://codecov.io/gh/11ways/protoblast">

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc