feat: Created a mini nodeJS server with NewMan for testing without PostMan GUI.

This will mimic a run in a CD/CI environment or docker container.
This commit is contained in:
Simon Priet
2021-09-08 14:01:19 +02:00
parent 5fbd7c88fa
commit e69a613a37
5610 changed files with 740417 additions and 3 deletions

79
node_modules/uvm/lib/bridge-client.js generated vendored Normal file
View File

@@ -0,0 +1,79 @@
/**
* This is a cross-platform event emitter with bridge interface.
* It uses Flatted as dependency where code is modified slightly to allow loading as a string
*/
/**
* Hold reference to this for security purpose
*
* @private
*/
const toString = String.prototype.toString;
/**
* Generate code to be executed inside a VM for bootstrap.
*
* @param {String|Buffer} bootCode
* @return {String}
*/
/* eslint-disable max-len */
module.exports = function (bootCode) {
return `;
(function (emit) {
/*! (c) 2020 Andrea Giammarchi, (ISC) */
var Flatted=function(n){"use strict";var t=JSON.parse,r=JSON.stringify,e=Object.keys,a=String,u="string",f={},i="object",c=function(n,t){return t},l=function(n){return n instanceof a?a(n):n},o=function(n,t){return typeof t===u?new a(t):t},s=function(n,t,r){var e=a(t.push(r)-1);return n.set(r,e),e};return n.parse=function(n,r){var u=t(n,o).map(l),s=u[0],p=r||c,v=typeof s===i&&s?function n(t,r,u,c){for(var l=[],o=e(u),s=o.length,p=0;p<s;p++){var v=o[p],y=u[v];if(y instanceof a){var g=t[y];typeof g!==i||r.has(g)?u[v]=c.call(u,v,g):(r.add(g),u[v]=f,l.push({k:v,a:[t,r,g,c]}))}else u[v]!==f&&(u[v]=c.call(u,v,y))}for(var h=l.length,d=0;d<h;d++){var w=l[d],O=w.k,S=w.a;u[O]=c.call(u,O,n.apply(null,S))}return u}(u,new Set,s,p):s;return p.call({"":v},"",v)},n.stringify=function(n,t,e){for(var a=t&&typeof t===i?function(n,r){return""===n||-1<t.indexOf(n)?r:void 0}:t||c,f=new Map,l=[],o=[],p=+s(f,l,a.call({"":n},"",n)),v=!p;p<l.length;)v=!0,o[p]=r(l[p++],y,e);return"["+o.join(",")+"]";function y(n,t){if(v)return v=!v,t;var r=a.call(this,n,t);switch(typeof r){case i:if(null===r)return r;case u:return f.get(r)||s(f,l,r)}return r}},n}({});
/*! (C) Postdot Technologies, Inc (Apache-2.0) */
var arrayProtoSlice = Array.prototype.slice;
bridge = { // ensure global using no var
_events: {},
emit: function (name) {
var self = this,
args = arrayProtoSlice.call(arguments, 1);
this._events[name] && this._events[name].forEach(function (listener) {
listener.apply(self, args);
});
},
dispatch: function () {
emit(Flatted.stringify(arrayProtoSlice.call(arguments)));
},
on: function (name, listener) {
if (typeof listener !== 'function') { return; }
!this._events[name] && (this._events[name] = []);
this._events[name].push(listener);
},
off: function (name, listener) {
var e = this._events[name],
i = e && e.length || 0;
if (!e) { return; }
if (arguments.length === 1) {
return delete this._events[name];
}
if (typeof listener === 'function' && (i >= 1)) {
while (i >= 0) {
(e[i] === listener) && e.splice(i, 1);
i -= 1;
}
}
if (!e.length) { delete this._events[name]; }
}
};
// create the dispatch function inside a closure to ensure that actual function references are never modified
__uvm_dispatch = (function (bridge, bridgeEmit) { // ensure global by not using var statement
return function (args) {
bridgeEmit.apply(bridge, Flatted.parse(args));
};
}(bridge, bridge.emit));
}(__uvm_emit));
// boot code starts hereafter
${(typeof bootCode === 'string') ? toString.call(bootCode) : ''};`;
};

154
node_modules/uvm/lib/bridge.browser.js generated vendored Normal file
View File

@@ -0,0 +1,154 @@
/* istanbul ignore file */
/*
* @note options.dispatchTimeout is not implemented in browser sandbox because
* there is no way to interrupt an infinite loop.
* Maybe terminate and restart the worker or execute in nested worker.
*/
const Flatted = require('flatted'),
{ randomNumber } = require('./utils'),
ERROR = 'error',
MESSAGE = 'message',
UVM_ID_ = '__id_uvm_',
// code for bridge
bridgeClientCode = require('./bridge-client'),
/**
* Returns the firmware code to be executed inside Web Worker.
*
* @private
* @param {String} code -
* @param {String} id -
* @return {String}
*/
sandboxFirmware = (code, id) => {
// @note self.postMessage and self.addEventListener methods are cached
// in variable or closure because bootCode might mutate the global scope
return `
__uvm_emit = function (postMessage, args) {
postMessage({__id_uvm: "${id}",__emit_uvm: args});
}.bind(null, self.postMessage);
__uvm_addEventListener = self.addEventListener;
try {${code}} catch (e) { setTimeout(function () { throw e; }, 0); }
(function (emit, id) {
__uvm_addEventListener("message", function (e) {
(e && e.data && (typeof e.data.__emit_uvm === 'string') && (e.data.__id_uvm === id)) &&
emit(e.data.__emit_uvm);
});
}(__uvm_dispatch, "${id}"));
__uvm_emit('${Flatted.stringify(['load.' + id])}');
__uvm_dispatch = null; __uvm_emit = null; __uvm_addEventListener = null;
delete __uvm_dispatch; delete __uvm_emit; delete __uvm_addEventListener;
`;
};
module.exports = function (bridge, options, callback) {
if (!(Blob && Worker && window && window.URL && window.URL.createObjectURL)) {
return callback(new Error('uvm: unable to setup communication bridge, missing required APIs'));
}
let worker,
bootTimer,
firmwareCode,
firmwareObjectURL;
const id = UVM_ID_ + randomNumber(),
// function to forward messages emitted
forwardEmits = (e) => {
if (!(e && e.data && (typeof e.data.__emit_uvm === 'string') && (e.data.__id_uvm === id))) { return; }
let args;
try { args = Flatted.parse(e.data.__emit_uvm); }
catch (err) { return bridge.emit(ERROR, err); }
bridge.emit(...args);
},
// function to forward errors emitted
forwardErrors = (e) => {
bridge.emit(ERROR, e);
},
// function to terminate worker
terminateWorker = function () {
if (!worker) { return; }
// remove event listeners for this sandbox
worker.removeEventListener(MESSAGE, forwardEmits);
worker.removeEventListener(ERROR, forwardErrors);
// do not terminate sandbox worker if not spawned for the bridge
if (!options._sandbox) {
worker.terminate();
// revoke after termination. otherwise, blob reference is retained until GC
// refer: "chrome://blob-internals"
window.URL.revokeObjectURL(firmwareObjectURL);
}
worker = null;
};
// on load attach the dispatcher
bridge.once('load.' + id, () => {
// stop boot timer first
clearTimeout(bootTimer);
bridge._dispatch = function () {
if (!worker) {
return bridge.emit(ERROR,
new Error('uvm: unable to dispatch "' + arguments[0] + '" post disconnection.'));
}
worker.postMessage({
__emit_uvm: Flatted.stringify(Array.prototype.slice.call(arguments)),
__id_uvm: id
});
};
callback(null, bridge);
});
// get firmware code string with boot code
firmwareCode = sandboxFirmware(bridgeClientCode(options.bootCode), id);
// start boot timer, stops once we get the load signal, terminate otherwise
bootTimer = setTimeout(() => {
terminateWorker();
callback(new Error(`uvm: boot timed out after ${options.bootTimeout}ms.`));
}, options.bootTimeout);
// if sandbox worker is provided, we simply need to init with firmware code
// @todo validate sandbox type or APIs
if (options._sandbox) {
worker = options._sandbox;
worker.postMessage({ __init_uvm: firmwareCode });
}
// else, spawn a new worker
else {
// convert the firmware code into a blob URL
firmwareObjectURL = window.URL.createObjectURL(new Blob([firmwareCode], { type: 'text/javascript' }));
// catch CSP:worker-src violations
try { worker = new Worker(firmwareObjectURL); }
catch (error) {
// clear blob reference
window.URL.revokeObjectURL(firmwareObjectURL);
return callback(new Error(`uvm: unable to spawn worker.\n${error.message || error}`));
}
}
// add event listener for receiving events from worker (is removed on disconnect)
// don't set `onmessage` and `onerror` as it might override external sandbox
worker.addEventListener(MESSAGE, forwardEmits);
worker.addEventListener(ERROR, forwardErrors);
// equip bridge to disconnect (i.e. terminate the worker)
bridge._disconnect = terminateWorker;
// help GC collect large variables
firmwareCode = null;
};

142
node_modules/uvm/lib/bridge.js generated vendored Normal file
View File

@@ -0,0 +1,142 @@
const vm = require('vm'),
Flatted = require('flatted'),
{ isString, randomNumber } = require('./utils'),
bridgeClientCode = require('./bridge-client'),
delegateTimers = require('./vm-delegate-timers'),
ERROR = 'error',
UVM_DATA_ = '__uvm_data_',
UVM_DISPATCH_ = '__uvm_dispatch_',
/**
* Convert array or arguments object to JSON
*
* @private
* @param {Array|Argument} arr
* @return {String}
*
* @note This has been held as reference to avoid being misused if modified in global context;
*/
jsonArray = (function (arrayProtoSlice, jsonStringify) {
return function (arr) {
return jsonStringify(arrayProtoSlice.call(arr));
};
}(Array.prototype.slice, Flatted.stringify)),
/**
* @private
* @param {String} str
* @return {Array}
*/
unJsonArray = (function (jsonParse) {
return function (str) {
return jsonParse(str);
};
}(Flatted.parse));
/**
* This function equips an event emitter with communication capability with a VM.
*
* @param {EventEmitter} emitter -
* @param {Object} options -
* @param {String} options.bootCode -
* @param {vm~Context=} [options._sandbox] -
* @param {Function} callback -
*/
module.exports = function (emitter, options, callback) {
let code = bridgeClientCode(options.bootCode),
context = options._sandbox || vm.createContext(Object.create(null)),
bridgeDispatch;
// inject console on debug mode
options.debug && (context.console = console);
// we need to inject the timers inside vm since VM does not have timers
if (!options._sandbox) {
delegateTimers(context);
}
try {
// inject the emitter via context. it will be referenced by the bridge and then deleted to prevent
// additional access
context.__uvm_emit = function (args) {
/* istanbul ignore if */
if (!isString(args)) { return; }
try { args = unJsonArray(args); }
catch (err) { /* istanbul ignore next */ emitter.emit(ERROR, err); }
emitter.emit(...args);
};
vm.runInContext(code, context, {
timeout: options.bootTimeout
});
// we keep a reference to the dispatcher so that we can preemptively re inject it in case it is deleted
// by user scripts
bridgeDispatch = context.__uvm_dispatch;
}
catch (err) {
return callback(err);
}
finally { // set all raw interface methods to null (except the dispatcher since we need it later)
vm.runInContext(`
__uvm_emit = null; delete __uvm_emit; __uvm_dispatch = null; delete __uvm_dispatch;
`, context);
delete context.__uvm_emit;
delete context.__uvm_dispatch;
}
// since context is created and emitter is bound, we would now attach the send function
emitter._dispatch = function () {
const id = UVM_DATA_ + randomNumber(),
dispatchId = UVM_DISPATCH_ + id;
// trigger event if any dispatch happens post disconnection
if (!context) {
return this.emit(ERROR, new Error(`uvm: unable to dispatch "${arguments[0]}" post disconnection.`));
}
try {
// save the data in context. by this method, we avoid needless string and character encoding or escaping
// issues. this is slightly prone to race condition issues, but using random numbers we intend to solve it
context[id] = jsonArray(arguments);
context[dispatchId] = bridgeDispatch;
// restore the dispatcher for immediate use!
vm.runInContext(`
(function (dispatch, data) {
${id} = null; (delete ${id});
${dispatchId} = null; (delete ${dispatchId});
dispatch(String(data));
}(${dispatchId}, ${id}));
`, context, {
timeout: options.dispatchTimeout
});
}
// swallow errors since other platforms will not trigger error if execution fails
catch (e) { this.emit(ERROR, e); }
finally { // precautionary delete
if (context) {
delete context[id];
delete context[dispatchId];
}
}
};
emitter._disconnect = function () {
/* istanbul ignore if */
if (!context) { return; }
// clear only if the context was created inside this function
!options._sandbox && Object.keys(context).forEach((prop) => {
delete context[prop];
});
context = null;
};
callback(null, emitter);
};

206
node_modules/uvm/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,206 @@
const EventEmitter = require('events'),
bridge = require('./bridge'),
{ isFunction, isObject } = require('./utils'),
/**
* The time to wait for UVM boot to finish. In milliseconds.
*
* @private
* @type {Number}
*/
DEFAULT_BOOT_TIMEOUT = 30 * 1000,
/**
* The time to wait for UVM dispatch process to finish. In milliseconds.
*
* @private
* @type {Number}
*/
DEFAULT_DISPATCH_TIMEOUT = 30 * 1000,
E = '',
ERROR_EVENT = 'error',
DISPATCH_QUEUE_EVENT = 'dispatchQueued';
/**
* Configuration options for UniversalVM connection.
*
* @typedef UniversalVM.connectOptions
*
* @property {Boolean} [bootCode] Code to be executed inside a VM on boot
* @property {Boolean} [_sandbox] Custom sandbox instance
* @property {Boolean} [debug] Inject global console object in Node.js VM
* @property {Boolean} [bootTimeout=30 * 1000] The time (in milliseconds) to wait for UVM boot to finish
* @property {Boolean} [dispatchTimeout=30 * 1000] The time (in milliseconds) to wait for UVM dispatch process to finish
*/
/**
* Universal Virtual Machine for Node and Browser.
*/
class UniversalVM extends EventEmitter {
constructor () {
super();
/**
* Boolean representing the bridge connectivity state.
*
* @private
* @type {Boolean}
*/
this._bridgeConnected = false;
/**
* Stores the pending dispatch events until the context is ready for use.
* Useful when not using the asynchronous construction.
*
* @private
* @type {Array}
*/
this._dispatchQueue = [];
}
/**
* Creates a new instance of UniversalVM.
* This is merely an alias of the construction creation without needing to
* write the `new` keyword and creating explicit connection.
*
* @param {UniversalVM.connectOptions} [options] Options to configure the UVM
* @param {Function(error, context)} callback Callback function
* @returns {Object} UVM event emitter instance
*
* @example
* const uvm = require('uvm');
*
* uvm.spawn({
* bootCode: `
* bridge.on('loopback', function (data) {
* bridge.dispatch('loopback', 'pong');
* });
* `
* }, (err, context) => {
* context.on('loopback', function (data) {
* console.log(data); // pong
* });
*
* context.dispatch('loopback', 'ping');
* });
*/
static spawn (options, callback) {
const uvm = new UniversalVM(options, callback);
// connect with the bridge
uvm.connect(options, callback);
// return event emitter for chaining
return uvm;
}
/**
* Establish connection with the communication bridge.
*
* @param {UniversalVM.connectOptions} [options] Options to configure the UVM
* @param {Function(error, context)} callback Callback function
*/
connect (options, callback) {
// set defaults for parameters
!isObject(options) && (options = {});
/**
* Wrap the callback for unified result and reduce chance of bug.
* We also abandon all dispatch replay.
*
* @private
* @param {Error=} [err] -
*/
const done = (err) => {
if (err) {
// on error during bridging, we simply abandon all dispatch replay
this._dispatchQueue.length = 0;
try { this.emit(ERROR_EVENT, err); }
// nothing to do if listeners fail, we need to move on and execute callback!
catch (e) { } // eslint-disable-line no-empty
}
isFunction(callback) && callback.call(this, err, this);
};
// bail out if bridge is connected
if (this._bridgeConnected) {
return done();
}
// start connection with the communication bridge
this._bridgeConnected = true;
// we bridge this event emitter with the context (bridge usually creates the context as well)
bridge(this, Object.assign({ // eslint-disable-line prefer-object-spread
bootCode: E,
bootTimeout: DEFAULT_BOOT_TIMEOUT,
dispatchTimeout: DEFAULT_DISPATCH_TIMEOUT
}, options), (err) => {
if (err) {
return done(err);
}
let args;
try {
// we dispatch all pending messages provided nothing had errors
while ((args = this._dispatchQueue.shift())) {
this.dispatch(...args);
}
}
// since there us no further work after dispatching events, we re-use the err parameter.
// at this point err variable is falsy since truthy case is already handled before
catch (e) { /* istanbul ignore next */ err = e; }
done(err);
});
}
/**
* Emit an event on the other end of bridge.
* The parameters are same as `emit` function of the event emitter.
*/
dispatch () {
try { this._dispatch(...arguments); }
catch (e) { /* istanbul ignore next */ this.emit(ERROR_EVENT, e); }
}
/**
* Disconnect the bridge and release memory.
*/
disconnect () {
// reset the bridge connection state
this._bridgeConnected = false;
try { this._disconnect(...arguments); }
catch (e) { this.emit(ERROR_EVENT, e); }
}
/**
* Stub dispatch handler to queue dispatched messages until bridge is ready.
*
* @private
* @param {String} name -
*/
_dispatch (name) {
this._dispatchQueue.push(arguments);
this.emit(DISPATCH_QUEUE_EVENT, name);
}
/**
* The bridge should be ready to disconnect when this is called. If not,
* then this prototype stub would throw an error
*
* @private
* @throws {Error} If bridge is not ready and this function is called
*/
_disconnect () { // eslint-disable-line class-methods-use-this
throw new Error('uvm: cannot disconnect, communication bridge is broken');
}
}
module.exports = UniversalVM;

17
node_modules/uvm/lib/utils.js generated vendored Normal file
View File

@@ -0,0 +1,17 @@
module.exports = {
isObject (subject) {
return (typeof subject === 'object' && subject !== null);
},
isFunction (subject) {
return (typeof subject === 'function');
},
isString (subject) {
return (typeof subject === 'string');
},
randomNumber () {
return ~~(Math.random() * 100000000);
}
};

55
node_modules/uvm/lib/vm-delegate-timers.js generated vendored Normal file
View File

@@ -0,0 +1,55 @@
const vm = require('vm'),
timers = require('timers'),
{ isFunction } = require('./utils'),
timerSetDelegates = ['setTimeout', 'setInterval', 'setImmediate'],
timerClearDelegates = ['clearImmediate', 'clearInterval', 'clearTimeout'];
/* istanbul ignore if */
// normalize immediate functions (usually for browsers)
if (!(isFunction(timers.setImmediate) && isFunction(timers.clearImmediate))) {
timers.setImmediate = function (fn) {
return timers.setTimeout(fn, 0);
};
timers.clearImmediate = function (id) {
return timers.clearTimeout(id);
};
}
module.exports = function (context) {
// prepare all set timer functions by putting the function inside a closure and exposing a proxy variant while
// deleting the original function from global scope
timerSetDelegates.forEach((setFn) => {
context[`${setFn}_`] = timers[setFn];
vm.runInContext(`
${setFn} = (function (_setFn, bind){
return function (cb, time) {
if (typeof cb !== 'function') { return; } // do not validate time for setImmediate
return _setFn(cb, time);
}
}(${setFn}_));
delete ${setFn}_;
(typeof ${setFn}_ !== 'undefined') && (${setFn}_ = undefined);
`, context);
});
// prepare all clear timer functions by putting the function inside a closure and exposing a proxy variant while
// deleting the original function from global scope
timerClearDelegates.forEach((clearFn) => {
context[`${clearFn}_`] = timers[clearFn]; // set the function in context
vm.runInContext(`
${clearFn} = (function (_clearFn) {
return function (id) { return _clearFn(id); };
}(${clearFn}_));
delete ${clearFn}_;
(typeof ${clearFn}_ !== 'undefined') && (${clearFn}_ = undefined);
`, context);
delete context[`${clearFn}_`]; // delete the function from context
});
return context;
};