feat: switch proxy implementation (#1269)

This commit is contained in:
Peter Evans 2022-10-18 12:14:51 +09:00 committed by GitHub
parent ad43dccb4d
commit b4d51739f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 53646 additions and 70 deletions

1010
dist/bridge.js vendored Normal file

File diff suppressed because it is too large Load diff

977
dist/events.js vendored Normal file
View file

@ -0,0 +1,977 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// 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:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// 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.
// Modified by the vm2 team to make this a standalone module to be loaded into the sandbox.
'use strict';
const host = fromhost;
const {
Boolean,
Error,
String,
Symbol
} = globalThis;
const ReflectApply = Reflect.apply;
const ReflectOwnKeys = Reflect.ownKeys;
const ErrorCaptureStackTrace = Error.captureStackTrace;
const NumberIsNaN = Number.isNaN;
const ObjectCreate = Object.create;
const ObjectDefineProperty = Object.defineProperty;
const ObjectDefineProperties = Object.defineProperties;
const ObjectGetPrototypeOf = Object.getPrototypeOf;
const SymbolFor = Symbol.for;
function uncurryThis(func) {
return (thiz, ...args) => ReflectApply(func, thiz, args);
}
const ArrayPrototypeIndexOf = uncurryThis(Array.prototype.indexOf);
const ArrayPrototypeJoin = uncurryThis(Array.prototype.join);
const ArrayPrototypeSlice = uncurryThis(Array.prototype.slice);
const ArrayPrototypeSplice = uncurryThis(Array.prototype.splice);
const ArrayPrototypeUnshift = uncurryThis(Array.prototype.unshift);
const kRejection = SymbolFor('nodejs.rejection');
function inspect(obj) {
return typeof obj === 'symbol' ? obj.toString() : `${obj}`;
}
function spliceOne(list, index) {
for (; index + 1 < list.length; index++)
list[index] = list[index + 1];
list.pop();
}
function assert(what, message) {
if (!what) throw new Error(message);
}
function E(key, msg, Base) {
return function NodeError(...args) {
const error = new Base();
const message = ReflectApply(msg, error, args);
ObjectDefineProperties(error, {
message: {
value: message,
enumerable: false,
writable: true,
configurable: true,
},
toString: {
value() {
return `${this.name} [${key}]: ${this.message}`;
},
enumerable: false,
writable: true,
configurable: true,
},
});
error.code = key;
return error;
};
}
const ERR_INVALID_ARG_TYPE = E('ERR_INVALID_ARG_TYPE',
(name, expected, actual) => {
assert(typeof name === 'string', "'name' must be a string");
if (!ArrayIsArray(expected)) {
expected = [expected];
}
let msg = 'The ';
if (StringPrototypeEndsWith(name, ' argument')) {
// For cases like 'first argument'
msg += `${name} `;
} else {
const type = StringPrototypeIncludes(name, '.') ? 'property' : 'argument';
msg += `"${name}" ${type} `;
}
msg += 'must be ';
const types = [];
const instances = [];
const other = [];
for (const value of expected) {
assert(typeof value === 'string',
'All expected entries have to be of type string');
if (ArrayPrototypeIncludes(kTypes, value)) {
ArrayPrototypePush(types, StringPrototypeToLowerCase(value));
} else if (RegExpPrototypeTest(classRegExp, value)) {
ArrayPrototypePush(instances, value);
} else {
assert(value !== 'object',
'The value "object" should be written as "Object"');
ArrayPrototypePush(other, value);
}
}
// Special handle `object` in case other instances are allowed to outline
// the differences between each other.
if (instances.length > 0) {
const pos = ArrayPrototypeIndexOf(types, 'object');
if (pos !== -1) {
ArrayPrototypeSplice(types, pos, 1);
ArrayPrototypePush(instances, 'Object');
}
}
if (types.length > 0) {
if (types.length > 2) {
const last = ArrayPrototypePop(types);
msg += `one of type ${ArrayPrototypeJoin(types, ', ')}, or ${last}`;
} else if (types.length === 2) {
msg += `one of type ${types[0]} or ${types[1]}`;
} else {
msg += `of type ${types[0]}`;
}
if (instances.length > 0 || other.length > 0)
msg += ' or ';
}
if (instances.length > 0) {
if (instances.length > 2) {
const last = ArrayPrototypePop(instances);
msg +=
`an instance of ${ArrayPrototypeJoin(instances, ', ')}, or ${last}`;
} else {
msg += `an instance of ${instances[0]}`;
if (instances.length === 2) {
msg += ` or ${instances[1]}`;
}
}
if (other.length > 0)
msg += ' or ';
}
if (other.length > 0) {
if (other.length > 2) {
const last = ArrayPrototypePop(other);
msg += `one of ${ArrayPrototypeJoin(other, ', ')}, or ${last}`;
} else if (other.length === 2) {
msg += `one of ${other[0]} or ${other[1]}`;
} else {
if (StringPrototypeToLowerCase(other[0]) !== other[0])
msg += 'an ';
msg += `${other[0]}`;
}
}
if (actual == null) {
msg += `. Received ${actual}`;
} else if (typeof actual === 'function' && actual.name) {
msg += `. Received function ${actual.name}`;
} else if (typeof actual === 'object') {
if (actual.constructor && actual.constructor.name) {
msg += `. Received an instance of ${actual.constructor.name}`;
} else {
const inspected = inspect(actual, { depth: -1 });
msg += `. Received ${inspected}`;
}
} else {
let inspected = inspect(actual, { colors: false });
if (inspected.length > 25)
inspected = `${StringPrototypeSlice(inspected, 0, 25)}...`;
msg += `. Received type ${typeof actual} (${inspected})`;
}
return msg;
}, TypeError);
const ERR_INVALID_THIS = E('ERR_INVALID_THIS', s => `Value of "this" must be of type ${s}`, TypeError);
const ERR_OUT_OF_RANGE = E('ERR_OUT_OF_RANGE',
(str, range, input, replaceDefaultBoolean = false) => {
assert(range, 'Missing "range" argument');
let msg = replaceDefaultBoolean ? str :
`The value of "${str}" is out of range.`;
const received = inspect(input);
msg += ` It must be ${range}. Received ${received}`;
return msg;
}, RangeError);
const ERR_UNHANDLED_ERROR = E('ERR_UNHANDLED_ERROR',
err => {
const msg = 'Unhandled error.';
if (err === undefined) return msg;
return `${msg} (${err})`;
}, Error);
function validateBoolean(value, name) {
if (typeof value !== 'boolean')
throw new ERR_INVALID_ARG_TYPE(name, 'boolean', value);
}
function validateFunction(value, name) {
if (typeof value !== 'function')
throw new ERR_INVALID_ARG_TYPE(name, 'Function', value);
}
function validateString(value, name) {
if (typeof value !== 'string')
throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
}
function nc(cond, e) {
return cond === undefined || cond === null ? e : cond;
}
function oc(base, key) {
return base === undefined || base === null ? undefined : base[key];
}
const kCapture = Symbol('kCapture');
const kErrorMonitor = host.kErrorMonitor || Symbol('events.errorMonitor');
const kMaxEventTargetListeners = Symbol('events.maxEventTargetListeners');
const kMaxEventTargetListenersWarned =
Symbol('events.maxEventTargetListenersWarned');
const kIsEventTarget = SymbolFor('nodejs.event_target');
function isEventTarget(obj) {
return oc(oc(obj, 'constructor'), kIsEventTarget);
}
/**
* Creates a new `EventEmitter` instance.
* @param {{ captureRejections?: boolean; }} [opts]
* @constructs {EventEmitter}
*/
function EventEmitter(opts) {
EventEmitter.init.call(this, opts);
}
module.exports = EventEmitter;
if (host.once) module.exports.once = host.once;
if (host.on) module.exports.on = host.on;
if (host.getEventListeners) module.exports.getEventListeners = host.getEventListeners;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.usingDomains = false;
EventEmitter.captureRejectionSymbol = kRejection;
ObjectDefineProperty(EventEmitter, 'captureRejections', {
get() {
return EventEmitter.prototype[kCapture];
},
set(value) {
validateBoolean(value, 'EventEmitter.captureRejections');
EventEmitter.prototype[kCapture] = value;
},
enumerable: true
});
if (host.EventEmitterReferencingAsyncResource) {
const kAsyncResource = Symbol('kAsyncResource');
const EventEmitterReferencingAsyncResource = host.EventEmitterReferencingAsyncResource;
class EventEmitterAsyncResource extends EventEmitter {
/**
* @param {{
* name?: string,
* triggerAsyncId?: number,
* requireManualDestroy?: boolean,
* }} [options]
*/
constructor(options = undefined) {
let name;
if (typeof options === 'string') {
name = options;
options = undefined;
} else {
if (new.target === EventEmitterAsyncResource) {
validateString(oc(options, 'name'), 'options.name');
}
name = oc(options, 'name') || new.target.name;
}
super(options);
this[kAsyncResource] =
new EventEmitterReferencingAsyncResource(this, name, options);
}
/**
* @param {symbol,string} event
* @param {...any} args
* @returns {boolean}
*/
emit(event, ...args) {
if (this[kAsyncResource] === undefined)
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
const { asyncResource } = this;
ArrayPrototypeUnshift(args, super.emit, this, event);
return ReflectApply(asyncResource.runInAsyncScope, asyncResource,
args);
}
/**
* @returns {void}
*/
emitDestroy() {
if (this[kAsyncResource] === undefined)
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
this.asyncResource.emitDestroy();
}
/**
* @type {number}
*/
get asyncId() {
if (this[kAsyncResource] === undefined)
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
return this.asyncResource.asyncId();
}
/**
* @type {number}
*/
get triggerAsyncId() {
if (this[kAsyncResource] === undefined)
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
return this.asyncResource.triggerAsyncId();
}
/**
* @type {EventEmitterReferencingAsyncResource}
*/
get asyncResource() {
if (this[kAsyncResource] === undefined)
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
return this[kAsyncResource];
}
}
EventEmitter.EventEmitterAsyncResource = EventEmitterAsyncResource;
}
EventEmitter.errorMonitor = kErrorMonitor;
// The default for captureRejections is false
ObjectDefineProperty(EventEmitter.prototype, kCapture, {
value: false,
writable: true,
enumerable: false
});
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._eventsCount = 0;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
let defaultMaxListeners = 10;
function checkListener(listener) {
validateFunction(listener, 'listener');
}
ObjectDefineProperty(EventEmitter, 'defaultMaxListeners', {
enumerable: true,
get: function() {
return defaultMaxListeners;
},
set: function(arg) {
if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
throw new ERR_OUT_OF_RANGE('defaultMaxListeners',
'a non-negative number',
arg);
}
defaultMaxListeners = arg;
}
});
ObjectDefineProperties(EventEmitter, {
kMaxEventTargetListeners: {
value: kMaxEventTargetListeners,
enumerable: false,
configurable: false,
writable: false,
},
kMaxEventTargetListenersWarned: {
value: kMaxEventTargetListenersWarned,
enumerable: false,
configurable: false,
writable: false,
}
});
/**
* Sets the max listeners.
* @param {number} n
* @param {EventTarget[] | EventEmitter[]} [eventTargets]
* @returns {void}
*/
EventEmitter.setMaxListeners =
function(n = defaultMaxListeners, ...eventTargets) {
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n))
throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n);
if (eventTargets.length === 0) {
defaultMaxListeners = n;
} else {
for (let i = 0; i < eventTargets.length; i++) {
const target = eventTargets[i];
if (isEventTarget(target)) {
target[kMaxEventTargetListeners] = n;
target[kMaxEventTargetListenersWarned] = false;
} else if (typeof target.setMaxListeners === 'function') {
target.setMaxListeners(n);
} else {
throw new ERR_INVALID_ARG_TYPE(
'eventTargets',
['EventEmitter', 'EventTarget'],
target);
}
}
}
};
// If you're updating this function definition, please also update any
// re-definitions, such as the one in the Domain module (lib/domain.js).
EventEmitter.init = function(opts) {
if (this._events === undefined ||
this._events === ObjectGetPrototypeOf(this)._events) {
this._events = ObjectCreate(null);
this._eventsCount = 0;
}
this._maxListeners = this._maxListeners || undefined;
if (oc(opts, 'captureRejections')) {
validateBoolean(opts.captureRejections, 'options.captureRejections');
this[kCapture] = Boolean(opts.captureRejections);
} else {
// Assigning the kCapture property directly saves an expensive
// prototype lookup in a very sensitive hot path.
this[kCapture] = EventEmitter.prototype[kCapture];
}
};
function addCatch(that, promise, type, args) {
if (!that[kCapture]) {
return;
}
// Handle Promises/A+ spec, then could be a getter
// that throws on second use.
try {
const then = promise.then;
if (typeof then === 'function') {
then.call(promise, undefined, function(err) {
// The callback is called with nextTick to avoid a follow-up
// rejection from this promise.
process.nextTick(emitUnhandledRejectionOrErr, that, err, type, args);
});
}
} catch (err) {
that.emit('error', err);
}
}
function emitUnhandledRejectionOrErr(ee, err, type, args) {
if (typeof ee[kRejection] === 'function') {
ee[kRejection](err, type, ...args);
} else {
// We have to disable the capture rejections mechanism, otherwise
// we might end up in an infinite loop.
const prev = ee[kCapture];
// If the error handler throws, it is not catchable and it
// will end up in 'uncaughtException'. We restore the previous
// value of kCapture in case the uncaughtException is present
// and the exception is handled.
try {
ee[kCapture] = false;
ee.emit('error', err);
} finally {
ee[kCapture] = prev;
}
}
}
/**
* Increases the max listeners of the event emitter.
* @param {number} n
* @returns {EventEmitter}
*/
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n);
}
this._maxListeners = n;
return this;
};
function _getMaxListeners(that) {
if (that._maxListeners === undefined)
return EventEmitter.defaultMaxListeners;
return that._maxListeners;
}
/**
* Returns the current max listener value for the event emitter.
* @returns {number}
*/
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
return _getMaxListeners(this);
};
/**
* Synchronously calls each of the listeners registered
* for the event.
* @param {string | symbol} type
* @param {...any} [args]
* @returns {boolean}
*/
EventEmitter.prototype.emit = function emit(type, ...args) {
let doError = (type === 'error');
const events = this._events;
if (events !== undefined) {
if (doError && events[kErrorMonitor] !== undefined)
this.emit(kErrorMonitor, ...args);
doError = (doError && events.error === undefined);
} else if (!doError)
return false;
// If there is no 'error' event listener then throw.
if (doError) {
let er;
if (args.length > 0)
er = args[0];
if (er instanceof Error) {
try {
const capture = {};
ErrorCaptureStackTrace(capture, EventEmitter.prototype.emit);
} catch (e) {}
// Note: The comments on the `throw` lines are intentional, they show
// up in Node's output if this results in an unhandled exception.
throw er; // Unhandled 'error' event
}
let stringifiedEr;
try {
stringifiedEr = inspect(er);
} catch (e) {
stringifiedEr = er;
}
// At least give some kind of context to the user
const err = new ERR_UNHANDLED_ERROR(stringifiedEr);
err.context = er;
throw err; // Unhandled 'error' event
}
const handler = events[type];
if (handler === undefined)
return false;
if (typeof handler === 'function') {
const result = handler.apply(this, args);
// We check if result is undefined first because that
// is the most common case so we do not pay any perf
// penalty
if (result !== undefined && result !== null) {
addCatch(this, result, type, args);
}
} else {
const len = handler.length;
const listeners = arrayClone(handler);
for (let i = 0; i < len; ++i) {
const result = listeners[i].apply(this, args);
// We check if result is undefined first because that
// is the most common case so we do not pay any perf
// penalty.
// This code is duplicated because extracting it away
// would make it non-inlineable.
if (result !== undefined && result !== null) {
addCatch(this, result, type, args);
}
}
}
return true;
};
function _addListener(target, type, listener, prepend) {
let m;
let events;
let existing;
checkListener(listener);
events = target._events;
if (events === undefined) {
events = target._events = ObjectCreate(null);
target._eventsCount = 0;
} else {
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (events.newListener !== undefined) {
target.emit('newListener', type,
nc(listener.listener, listener));
// Re-assign `events` because a newListener handler could have caused the
// this._events to be assigned to a new object
events = target._events;
}
existing = events[type];
}
if (existing === undefined) {
// Optimize the case of one listener. Don't need the extra array object.
events[type] = listener;
++target._eventsCount;
} else {
if (typeof existing === 'function') {
// Adding the second element, need to change to array.
existing = events[type] =
prepend ? [listener, existing] : [existing, listener];
// If we've already got an array, just append.
} else if (prepend) {
existing.unshift(listener);
} else {
existing.push(listener);
}
// Check for listener leak
m = _getMaxListeners(target);
if (m > 0 && existing.length > m && !existing.warned) {
existing.warned = true;
// No error code for this since it is a Warning
// eslint-disable-next-line no-restricted-syntax
const w = new Error('Possible EventEmitter memory leak detected. ' +
`${existing.length} ${String(type)} listeners ` +
`added to ${inspect(target, { depth: -1 })}. Use ` +
'emitter.setMaxListeners() to increase limit');
w.name = 'MaxListenersExceededWarning';
w.emitter = target;
w.type = type;
w.count = existing.length;
process.emitWarning(w);
}
}
return target;
}
/**
* Adds a listener to the event emitter.
* @param {string | symbol} type
* @param {Function} listener
* @returns {EventEmitter}
*/
EventEmitter.prototype.addListener = function addListener(type, listener) {
return _addListener(this, type, listener, false);
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
/**
* Adds the `listener` function to the beginning of
* the listeners array.
* @param {string | symbol} type
* @param {Function} listener
* @returns {EventEmitter}
*/
EventEmitter.prototype.prependListener =
function prependListener(type, listener) {
return _addListener(this, type, listener, true);
};
function onceWrapper() {
if (!this.fired) {
this.target.removeListener(this.type, this.wrapFn);
this.fired = true;
if (arguments.length === 0)
return this.listener.call(this.target);
return this.listener.apply(this.target, arguments);
}
}
function _onceWrap(target, type, listener) {
const state = { fired: false, wrapFn: undefined, target, type, listener };
const wrapped = onceWrapper.bind(state);
wrapped.listener = listener;
state.wrapFn = wrapped;
return wrapped;
}
/**
* Adds a one-time `listener` function to the event emitter.
* @param {string | symbol} type
* @param {Function} listener
* @returns {EventEmitter}
*/
EventEmitter.prototype.once = function once(type, listener) {
checkListener(listener);
this.on(type, _onceWrap(this, type, listener));
return this;
};
/**
* Adds a one-time `listener` function to the beginning of
* the listeners array.
* @param {string | symbol} type
* @param {Function} listener
* @returns {EventEmitter}
*/
EventEmitter.prototype.prependOnceListener =
function prependOnceListener(type, listener) {
checkListener(listener);
this.prependListener(type, _onceWrap(this, type, listener));
return this;
};
/**
* Removes the specified `listener` from the listeners array.
* @param {string | symbol} type
* @param {Function} listener
* @returns {EventEmitter}
*/
EventEmitter.prototype.removeListener =
function removeListener(type, listener) {
checkListener(listener);
const events = this._events;
if (events === undefined)
return this;
const list = events[type];
if (list === undefined)
return this;
if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0)
this._events = ObjectCreate(null);
else {
delete events[type];
if (events.removeListener)
this.emit('removeListener', type, list.listener || listener);
}
} else if (typeof list !== 'function') {
let position = -1;
for (let i = list.length - 1; i >= 0; i--) {
if (list[i] === listener || list[i].listener === listener) {
position = i;
break;
}
}
if (position < 0)
return this;
if (position === 0)
list.shift();
else {
spliceOne(list, position);
}
if (list.length === 1)
events[type] = list[0];
if (events.removeListener !== undefined)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
/**
* Removes all listeners from the event emitter. (Only
* removes listeners for a specific event name if specified
* as `type`).
* @param {string | symbol} [type]
* @returns {EventEmitter}
*/
EventEmitter.prototype.removeAllListeners =
function removeAllListeners(type) {
const events = this._events;
if (events === undefined)
return this;
// Not listening for removeListener, no need to emit
if (events.removeListener === undefined) {
if (arguments.length === 0) {
this._events = ObjectCreate(null);
this._eventsCount = 0;
} else if (events[type] !== undefined) {
if (--this._eventsCount === 0)
this._events = ObjectCreate(null);
else
delete events[type];
}
return this;
}
// Emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (const key of ReflectOwnKeys(events)) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = ObjectCreate(null);
this._eventsCount = 0;
return this;
}
const listeners = events[type];
if (typeof listeners === 'function') {
this.removeListener(type, listeners);
} else if (listeners !== undefined) {
// LIFO order
for (let i = listeners.length - 1; i >= 0; i--) {
this.removeListener(type, listeners[i]);
}
}
return this;
};
function _listeners(target, type, unwrap) {
const events = target._events;
if (events === undefined)
return [];
const evlistener = events[type];
if (evlistener === undefined)
return [];
if (typeof evlistener === 'function')
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
return unwrap ?
unwrapListeners(evlistener) : arrayClone(evlistener);
}
/**
* Returns a copy of the array of listeners for the event name
* specified as `type`.
* @param {string | symbol} type
* @returns {Function[]}
*/
EventEmitter.prototype.listeners = function listeners(type) {
return _listeners(this, type, true);
};
/**
* Returns a copy of the array of listeners and wrappers for
* the event name specified as `type`.
* @param {string | symbol} type
* @returns {Function[]}
*/
EventEmitter.prototype.rawListeners = function rawListeners(type) {
return _listeners(this, type, false);
};
/**
* Returns the number of listeners listening to the event name
* specified as `type`.
* @deprecated since v3.2.0
* @param {EventEmitter} emitter
* @param {string | symbol} type
* @returns {number}
*/
EventEmitter.listenerCount = function(emitter, type) {
if (typeof emitter.listenerCount === 'function') {
return emitter.listenerCount(type);
}
return emitter.listenerCount(type);
};
EventEmitter.prototype.listenerCount = listenerCount;
/**
* Returns the number of listeners listening to event name
* specified as `type`.
* @param {string | symbol} type
* @returns {number}
*/
function listenerCount(type) {
const events = this._events;
if (events !== undefined) {
const evlistener = events[type];
if (typeof evlistener === 'function') {
return 1;
} else if (evlistener !== undefined) {
return evlistener.length;
}
}
return 0;
}
/**
* Returns an array listing the events for which
* the emitter has registered listeners.
* @returns {any[]}
*/
EventEmitter.prototype.eventNames = function eventNames() {
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
};
function arrayClone(arr) {
// At least since V8 8.3, this implementation is faster than the previous
// which always used a simple for-loop
switch (arr.length) {
case 2: return [arr[0], arr[1]];
case 3: return [arr[0], arr[1], arr[2]];
case 4: return [arr[0], arr[1], arr[2], arr[3]];
case 5: return [arr[0], arr[1], arr[2], arr[3], arr[4]];
case 6: return [arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]];
}
return ArrayPrototypeSlice(arr);
}
function unwrapListeners(arr) {
const ret = arrayClone(arr);
for (let i = 0; i < ret.length; ++i) {
const orig = ret[i].listener;
if (typeof orig === 'function')
ret[i] = orig;
}
return ret;
}

49849
dist/index.js vendored

File diff suppressed because one or more lines are too long

469
dist/setup-node-sandbox.js vendored Normal file
View file

@ -0,0 +1,469 @@
/* global host, data, VMError */
'use strict';
const LocalError = Error;
const LocalTypeError = TypeError;
const LocalWeakMap = WeakMap;
const {
apply: localReflectApply,
defineProperty: localReflectDefineProperty
} = Reflect;
const {
set: localWeakMapSet,
get: localWeakMapGet
} = LocalWeakMap.prototype;
const {
isArray: localArrayIsArray
} = Array;
function uncurryThis(func) {
return (thiz, ...args) => localReflectApply(func, thiz, args);
}
const localArrayPrototypeSlice = uncurryThis(Array.prototype.slice);
const localArrayPrototypeIncludes = uncurryThis(Array.prototype.includes);
const localArrayPrototypePush = uncurryThis(Array.prototype.push);
const localArrayPrototypeIndexOf = uncurryThis(Array.prototype.indexOf);
const localArrayPrototypeSplice = uncurryThis(Array.prototype.splice);
const localStringPrototypeStartsWith = uncurryThis(String.prototype.startsWith);
const localStringPrototypeSlice = uncurryThis(String.prototype.slice);
const localStringPrototypeIndexOf = uncurryThis(String.prototype.indexOf);
const {
argv: optionArgv,
env: optionEnv,
console: optionConsole,
vm,
resolver,
extensions
} = data;
function ensureSandboxArray(a) {
return localArrayPrototypeSlice(a);
}
const globalPaths = ensureSandboxArray(resolver.globalPaths);
class Module {
constructor(id, path, parent) {
this.id = id;
this.filename = id;
this.path = path;
this.parent = parent;
this.loaded = false;
this.paths = path ? ensureSandboxArray(resolver.genLookupPaths(path)) : [];
this.children = [];
this.exports = {};
}
_updateChildren(child, isNew) {
const children = this.children;
if (children && (isNew || !localArrayPrototypeIncludes(children, child))) {
localArrayPrototypePush(children, child);
}
}
require(id) {
return requireImpl(this, id, false);
}
}
const originalRequire = Module.prototype.require;
const cacheBuiltins = {__proto__: null};
function requireImpl(mod, id, direct) {
if (direct && mod.require !== originalRequire) {
return mod.require(id);
}
const filename = resolver.resolve(mod, id, undefined, Module._extensions, direct);
if (localStringPrototypeStartsWith(filename, 'node:')) {
id = localStringPrototypeSlice(filename, 5);
let nmod = cacheBuiltins[id];
if (!nmod) {
nmod = resolver.loadBuiltinModule(vm, id);
if (!nmod) throw new VMError(`Cannot find module '${filename}'`, 'ENOTFOUND');
cacheBuiltins[id] = nmod;
}
return nmod;
}
const cachedModule = Module._cache[filename];
if (cachedModule !== undefined) {
mod._updateChildren(cachedModule, false);
return cachedModule.exports;
}
let nmod = cacheBuiltins[id];
if (nmod) return nmod;
nmod = resolver.loadBuiltinModule(vm, id);
if (nmod) {
cacheBuiltins[id] = nmod;
return nmod;
}
const path = resolver.pathDirname(filename);
const module = new Module(filename, path, mod);
resolver.registerModule(module, filename, path, mod, direct);
mod._updateChildren(module, true);
try {
Module._cache[filename] = module;
const handler = findBestExtensionHandler(filename);
handler(module, filename);
module.loaded = true;
} catch (e) {
delete Module._cache[filename];
const children = mod.children;
if (localArrayIsArray(children)) {
const index = localArrayPrototypeIndexOf(children, module);
if (index !== -1) {
localArrayPrototypeSplice(children, index, 1);
}
}
throw e;
}
return module.exports;
}
Module.builtinModules = ensureSandboxArray(resolver.getBuiltinModulesList());
Module.globalPaths = globalPaths;
Module._extensions = {__proto__: null};
Module._cache = {__proto__: null};
{
const keys = Object.getOwnPropertyNames(extensions);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const handler = extensions[key];
Module._extensions[key] = (mod, filename) => handler(mod, filename);
}
}
function findBestExtensionHandler(filename) {
const name = resolver.pathBasename(filename);
for (let i = 0; (i = localStringPrototypeIndexOf(name, '.', i + 1)) !== -1;) {
const ext = localStringPrototypeSlice(name, i);
const handler = Module._extensions[ext];
if (handler) return handler;
}
const js = Module._extensions['.js'];
if (js) return js;
const keys = Object.getOwnPropertyNames(Module._extensions);
if (keys.length === 0) throw new VMError(`Failed to load '${filename}': Unknown type.`, 'ELOADFAIL');
return Module._extensions[keys[0]];
}
function createRequireForModule(mod) {
// eslint-disable-next-line no-shadow
function require(id) {
return requireImpl(mod, id, true);
}
function resolve(id, options) {
return resolver.resolve(mod, id, options, Module._extensions, true);
}
require.resolve = resolve;
function paths(id) {
return ensureSandboxArray(resolver.lookupPaths(mod, id));
}
resolve.paths = paths;
require.extensions = Module._extensions;
require.cache = Module._cache;
return require;
}
/**
* Prepare sandbox.
*/
const TIMERS = new LocalWeakMap();
class Timeout {
}
class Interval {
}
class Immediate {
}
function clearTimer(timer) {
const obj = localReflectApply(localWeakMapGet, TIMERS, [timer]);
if (obj) {
obj.clear(obj.value);
}
}
// This is a function and not an arrow function, since the original is also a function
// eslint-disable-next-line no-shadow
global.setTimeout = function setTimeout(callback, delay, ...args) {
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
const obj = new Timeout(callback, args);
const cb = () => {
localReflectApply(callback, null, args);
};
const tmr = host.setTimeout(cb, delay);
const ref = {
__proto__: null,
clear: host.clearTimeout,
value: tmr
};
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
return obj;
};
// eslint-disable-next-line no-shadow
global.setInterval = function setInterval(callback, interval, ...args) {
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
const obj = new Interval();
const cb = () => {
localReflectApply(callback, null, args);
};
const tmr = host.setInterval(cb, interval);
const ref = {
__proto__: null,
clear: host.clearInterval,
value: tmr
};
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
return obj;
};
// eslint-disable-next-line no-shadow
global.setImmediate = function setImmediate(callback, ...args) {
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
const obj = new Immediate();
const cb = () => {
localReflectApply(callback, null, args);
};
const tmr = host.setImmediate(cb);
const ref = {
__proto__: null,
clear: host.clearImmediate,
value: tmr
};
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
return obj;
};
// eslint-disable-next-line no-shadow
global.clearTimeout = function clearTimeout(timeout) {
clearTimer(timeout);
};
// eslint-disable-next-line no-shadow
global.clearInterval = function clearInterval(interval) {
clearTimer(interval);
};
// eslint-disable-next-line no-shadow
global.clearImmediate = function clearImmediate(immediate) {
clearTimer(immediate);
};
const localProcess = host.process;
function vmEmitArgs(event, args) {
const allargs = [event];
for (let i = 0; i < args.length; i++) {
if (!localReflectDefineProperty(allargs, i + 1, {
__proto__: null,
value: args[i],
writable: true,
enumerable: true,
configurable: true
})) throw new LocalError('Unexpected');
}
return localReflectApply(vm.emit, vm, allargs);
}
const LISTENERS = new LocalWeakMap();
const LISTENER_HANDLER = new LocalWeakMap();
/**
*
* @param {*} name
* @param {*} handler
* @this process
* @return {this}
*/
function addListener(name, handler) {
if (name !== 'beforeExit' && name !== 'exit') {
throw new LocalError(`Access denied to listen for '${name}' event.`);
}
let cb = localReflectApply(localWeakMapGet, LISTENERS, [handler]);
if (!cb) {
cb = () => {
handler();
};
localReflectApply(localWeakMapSet, LISTENER_HANDLER, [cb, handler]);
localReflectApply(localWeakMapSet, LISTENERS, [handler, cb]);
}
localProcess.on(name, cb);
return this;
}
/**
*
* @this process
* @return {this}
*/
// eslint-disable-next-line no-shadow
function process() {
return this;
}
const baseUptime = localProcess.uptime();
// FIXME wrong class structure
global.process = {
__proto__: process.prototype,
argv: optionArgv !== undefined ? optionArgv : [],
title: localProcess.title,
version: localProcess.version,
versions: localProcess.versions,
arch: localProcess.arch,
platform: localProcess.platform,
env: optionEnv !== undefined ? optionEnv : {},
pid: localProcess.pid,
features: localProcess.features,
nextTick: function nextTick(callback, ...args) {
if (typeof callback !== 'function') {
throw new LocalError('Callback must be a function.');
}
localProcess.nextTick(()=>{
localReflectApply(callback, null, args);
});
},
hrtime: function hrtime(time) {
return localProcess.hrtime(time);
},
uptime: function uptime() {
return localProcess.uptime() - baseUptime;
},
cwd: function cwd() {
return localProcess.cwd();
},
addListener,
on: addListener,
once: function once(name, handler) {
if (name !== 'beforeExit' && name !== 'exit') {
throw new LocalError(`Access denied to listen for '${name}' event.`);
}
let triggered = false;
const cb = () => {
if (triggered) return;
triggered = true;
localProcess.removeListener(name, cb);
handler();
};
localReflectApply(localWeakMapSet, LISTENER_HANDLER, [cb, handler]);
localProcess.on(name, cb);
return this;
},
listeners: function listeners(name) {
if (name !== 'beforeExit' && name !== 'exit') {
// Maybe add ({__proto__:null})[name] to throw when name fails in https://tc39.es/ecma262/#sec-topropertykey.
return [];
}
// Filter out listeners, which were not created in this sandbox
const all = localProcess.listeners(name);
const filtered = [];
let j = 0;
for (let i = 0; i < all.length; i++) {
const h = localReflectApply(localWeakMapGet, LISTENER_HANDLER, [all[i]]);
if (h) {
if (!localReflectDefineProperty(filtered, j, {
__proto__: null,
value: h,
writable: true,
enumerable: true,
configurable: true
})) throw new LocalError('Unexpected');
j++;
}
}
return filtered;
},
removeListener: function removeListener(name, handler) {
if (name !== 'beforeExit' && name !== 'exit') {
return this;
}
const cb = localReflectApply(localWeakMapGet, LISTENERS, [handler]);
if (cb) localProcess.removeListener(name, cb);
return this;
},
umask: function umask() {
if (arguments.length) {
throw new LocalError('Access denied to set umask.');
}
return localProcess.umask();
}
};
if (optionConsole === 'inherit') {
global.console = host.console;
} else if (optionConsole === 'redirect') {
global.console = {
debug(...args) {
vmEmitArgs('console.debug', args);
},
log(...args) {
vmEmitArgs('console.log', args);
},
info(...args) {
vmEmitArgs('console.info', args);
},
warn(...args) {
vmEmitArgs('console.warn', args);
},
error(...args) {
vmEmitArgs('console.error', args);
},
dir(...args) {
vmEmitArgs('console.dir', args);
},
time() {},
timeEnd() {},
trace(...args) {
vmEmitArgs('console.trace', args);
}
};
}
return {
__proto__: null,
Module,
jsonParse: JSON.parse,
createRequireForModule,
requireImpl
};

457
dist/setup-sandbox.js vendored Normal file
View file

@ -0,0 +1,457 @@
/* global host, bridge, data, context */
'use strict';
const {
Object: localObject,
Array: localArray,
Error: LocalError,
Reflect: localReflect,
Proxy: LocalProxy,
WeakMap: LocalWeakMap,
Function: localFunction,
Promise: localPromise,
eval: localEval
} = global;
const {
freeze: localObjectFreeze
} = localObject;
const {
getPrototypeOf: localReflectGetPrototypeOf,
apply: localReflectApply,
deleteProperty: localReflectDeleteProperty,
has: localReflectHas,
defineProperty: localReflectDefineProperty,
setPrototypeOf: localReflectSetPrototypeOf,
getOwnPropertyDescriptor: localReflectGetOwnPropertyDescriptor
} = localReflect;
const {
isArray: localArrayIsArray
} = localArray;
const {
ensureThis,
ReadOnlyHandler,
from,
fromWithFactory,
readonlyFactory,
connect,
addProtoMapping,
VMError,
ReadOnlyMockHandler
} = bridge;
const {
allowAsync,
GeneratorFunction,
AsyncFunction,
AsyncGeneratorFunction
} = data;
const {
get: localWeakMapGet,
set: localWeakMapSet
} = LocalWeakMap.prototype;
function localUnexpected() {
return new VMError('Should not happen');
}
// global is originally prototype of host.Object so it can be used to climb up from the sandbox.
if (!localReflectSetPrototypeOf(context, localObject.prototype)) throw localUnexpected();
Object.defineProperties(global, {
global: {value: global, writable: true, configurable: true, enumerable: true},
globalThis: {value: global, writable: true, configurable: true},
GLOBAL: {value: global, writable: true, configurable: true},
root: {value: global, writable: true, configurable: true},
Error: {value: LocalError}
});
if (!localReflectDefineProperty(global, 'VMError', {
__proto__: null,
value: VMError,
writable: true,
enumerable: false,
configurable: true
})) throw localUnexpected();
// Fixes buffer unsafe allocation
/* eslint-disable no-use-before-define */
class BufferHandler extends ReadOnlyHandler {
apply(target, thiz, args) {
if (args.length > 0 && typeof args[0] === 'number') {
return LocalBuffer.alloc(args[0]);
}
return localReflectApply(LocalBuffer.from, LocalBuffer, args);
}
construct(target, args, newTarget) {
if (args.length > 0 && typeof args[0] === 'number') {
return LocalBuffer.alloc(args[0]);
}
return localReflectApply(LocalBuffer.from, LocalBuffer, args);
}
}
/* eslint-enable no-use-before-define */
const LocalBuffer = fromWithFactory(obj => new BufferHandler(obj), host.Buffer);
if (!localReflectDefineProperty(global, 'Buffer', {
__proto__: null,
value: LocalBuffer,
writable: true,
enumerable: false,
configurable: true
})) throw localUnexpected();
addProtoMapping(LocalBuffer.prototype, host.Buffer.prototype, 'Uint8Array');
/**
*
* @param {*} size Size of new buffer
* @this LocalBuffer
* @return {LocalBuffer}
*/
function allocUnsafe(size) {
return LocalBuffer.alloc(size);
}
connect(allocUnsafe, host.Buffer.allocUnsafe);
/**
*
* @param {*} size Size of new buffer
* @this LocalBuffer
* @return {LocalBuffer}
*/
function allocUnsafeSlow(size) {
return LocalBuffer.alloc(size);
}
connect(allocUnsafeSlow, host.Buffer.allocUnsafeSlow);
/**
* Replacement for Buffer inspect
*
* @param {*} recurseTimes
* @param {*} ctx
* @this LocalBuffer
* @return {string}
*/
function inspect(recurseTimes, ctx) {
// Mimic old behavior, could throw but didn't pass a test.
const max = host.INSPECT_MAX_BYTES;
const actualMax = Math.min(max, this.length);
const remaining = this.length - max;
let str = this.hexSlice(0, actualMax).replace(/(.{2})/g, '$1 ').trim();
if (remaining > 0) str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
return `<${this.constructor.name} ${str}>`;
}
connect(inspect, host.Buffer.prototype.inspect);
connect(localFunction.prototype.bind, host.Function.prototype.bind);
connect(localObject.prototype.__defineGetter__, host.Object.prototype.__defineGetter__);
connect(localObject.prototype.__defineSetter__, host.Object.prototype.__defineSetter__);
connect(localObject.prototype.__lookupGetter__, host.Object.prototype.__lookupGetter__);
connect(localObject.prototype.__lookupSetter__, host.Object.prototype.__lookupSetter__);
/*
* PrepareStackTrace sanitization
*/
const oldPrepareStackTraceDesc = localReflectGetOwnPropertyDescriptor(LocalError, 'prepareStackTrace');
let currentPrepareStackTrace = LocalError.prepareStackTrace;
const wrappedPrepareStackTrace = new LocalWeakMap();
if (typeof currentPrepareStackTrace === 'function') {
wrappedPrepareStackTrace.set(currentPrepareStackTrace, currentPrepareStackTrace);
}
let OriginalCallSite;
LocalError.prepareStackTrace = (e, sst) => {
OriginalCallSite = sst[0].constructor;
};
new LocalError().stack;
if (typeof OriginalCallSite === 'function') {
LocalError.prepareStackTrace = undefined;
function makeCallSiteGetters(list) {
const callSiteGetters = [];
for (let i=0; i<list.length; i++) {
const name = list[i];
const func = OriginalCallSite.prototype[name];
callSiteGetters[i] = {__proto__: null,
name,
propName: '_' + name,
func: (thiz) => {
return localReflectApply(func, thiz, []);
}
};
}
return callSiteGetters;
}
function applyCallSiteGetters(thiz, callSite, getters) {
for (let i=0; i<getters.length; i++) {
const getter = getters[i];
localReflectDefineProperty(thiz, getter.propName, {
__proto__: null,
value: getter.func(callSite)
});
}
}
const callSiteGetters = makeCallSiteGetters([
'getTypeName',
'getFunctionName',
'getMethodName',
'getFileName',
'getLineNumber',
'getColumnNumber',
'getEvalOrigin',
'isToplevel',
'isEval',
'isNative',
'isConstructor',
'isAsync',
'isPromiseAll',
'getPromiseIndex'
]);
class CallSite {
constructor(callSite) {
applyCallSiteGetters(this, callSite, callSiteGetters);
}
getThis() {
return undefined;
}
getFunction() {
return undefined;
}
toString() {
return 'CallSite {}';
}
}
for (let i=0; i<callSiteGetters.length; i++) {
const name = callSiteGetters[i].name;
const funcProp = localReflectGetOwnPropertyDescriptor(OriginalCallSite.prototype, name);
if (!funcProp) continue;
const propertyName = callSiteGetters[i].propName;
const func = {func() {
return this[propertyName];
}}.func;
const nameProp = localReflectGetOwnPropertyDescriptor(func, 'name');
if (!nameProp) throw localUnexpected();
nameProp.value = name;
if (!localReflectDefineProperty(func, 'name', nameProp)) throw localUnexpected();
funcProp.value = func;
if (!localReflectDefineProperty(CallSite.prototype, name, funcProp)) throw localUnexpected();
}
if (!localReflectDefineProperty(LocalError, 'prepareStackTrace', {
configurable: false,
enumerable: false,
get() {
return currentPrepareStackTrace;
},
set(value) {
if (typeof(value) !== 'function') {
currentPrepareStackTrace = value;
return;
}
const wrapped = localReflectApply(localWeakMapGet, wrappedPrepareStackTrace, [value]);
if (wrapped) {
currentPrepareStackTrace = wrapped;
return;
}
const newWrapped = (error, sst) => {
if (localArrayIsArray(sst)) {
for (let i=0; i < sst.length; i++) {
const cs = sst[i];
if (typeof cs === 'object' && localReflectGetPrototypeOf(cs) === OriginalCallSite.prototype) {
sst[i] = new CallSite(cs);
}
}
}
return value(error, sst);
};
localReflectApply(localWeakMapSet, wrappedPrepareStackTrace, [value, newWrapped]);
localReflectApply(localWeakMapSet, wrappedPrepareStackTrace, [newWrapped, newWrapped]);
currentPrepareStackTrace = newWrapped;
}
})) throw localUnexpected();
} else if (oldPrepareStackTraceDesc) {
localReflectDefineProperty(LocalError, 'prepareStackTrace', oldPrepareStackTraceDesc);
} else {
localReflectDeleteProperty(LocalError, 'prepareStackTrace');
}
/*
* Exception sanitization
*/
const withProxy = localObjectFreeze({
__proto__: null,
has(target, key) {
if (key === host.INTERNAL_STATE_NAME) return false;
return localReflectHas(target, key);
}
});
const interanState = localObjectFreeze({
__proto__: null,
wrapWith(x) {
if (x === null || x === undefined) return x;
return new LocalProxy(localObject(x), withProxy);
},
handleException: ensureThis,
import(what) {
throw new VMError('Dynamic Import not supported');
}
});
if (!localReflectDefineProperty(global, host.INTERNAL_STATE_NAME, {
__proto__: null,
configurable: false,
enumerable: false,
writable: false,
value: interanState
})) throw localUnexpected();
/*
* Eval sanitization
*/
function throwAsync() {
return new VMError('Async not available');
}
function makeFunction(inputArgs, isAsync, isGenerator) {
const lastArgs = inputArgs.length - 1;
let code = lastArgs >= 0 ? `${inputArgs[lastArgs]}` : '';
let args = lastArgs > 0 ? `${inputArgs[0]}` : '';
for (let i = 1; i < lastArgs; i++) {
args += `,${inputArgs[i]}`;
}
try {
code = host.transformAndCheck(args, code, isAsync, isGenerator, allowAsync);
} catch (e) {
throw bridge.from(e);
}
return localEval(code);
}
const FunctionHandler = {
__proto__: null,
apply(target, thiz, args) {
return makeFunction(args, this.isAsync, this.isGenerator);
},
construct(target, args, newTarget) {
return makeFunction(args, this.isAsync, this.isGenerator);
}
};
const EvalHandler = {
__proto__: null,
apply(target, thiz, args) {
if (args.length === 0) return undefined;
let code = `${args[0]}`;
try {
code = host.transformAndCheck(null, code, false, false, allowAsync);
} catch (e) {
throw bridge.from(e);
}
return localEval(code);
}
};
const AsyncErrorHandler = {
__proto__: null,
apply(target, thiz, args) {
throw throwAsync();
},
construct(target, args, newTarget) {
throw throwAsync();
}
};
function makeCheckFunction(isAsync, isGenerator) {
if (isAsync && !allowAsync) return AsyncErrorHandler;
return {
__proto__: FunctionHandler,
isAsync,
isGenerator
};
}
function overrideWithProxy(obj, prop, value, handler) {
const proxy = new LocalProxy(value, handler);
if (!localReflectDefineProperty(obj, prop, {__proto__: null, value: proxy})) throw localUnexpected();
return proxy;
}
const proxiedFunction = overrideWithProxy(localFunction.prototype, 'constructor', localFunction, makeCheckFunction(false, false));
if (GeneratorFunction) {
if (!localReflectSetPrototypeOf(GeneratorFunction, proxiedFunction)) throw localUnexpected();
overrideWithProxy(GeneratorFunction.prototype, 'constructor', GeneratorFunction, makeCheckFunction(false, true));
}
if (AsyncFunction) {
if (!localReflectSetPrototypeOf(AsyncFunction, proxiedFunction)) throw localUnexpected();
overrideWithProxy(AsyncFunction.prototype, 'constructor', AsyncFunction, makeCheckFunction(true, false));
}
if (AsyncGeneratorFunction) {
if (!localReflectSetPrototypeOf(AsyncGeneratorFunction, proxiedFunction)) throw localUnexpected();
overrideWithProxy(AsyncGeneratorFunction.prototype, 'constructor', AsyncGeneratorFunction, makeCheckFunction(true, true));
}
global.Function = proxiedFunction;
global.eval = new LocalProxy(localEval, EvalHandler);
/*
* Promise sanitization
*/
if (localPromise && !allowAsync) {
const PromisePrototype = localPromise.prototype;
overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, AsyncErrorHandler);
// This seems not to work, and will produce
// UnhandledPromiseRejectionWarning: TypeError: Method Promise.prototype.then called on incompatible receiver [object Object].
// This is likely caused since the host.Promise.prototype.then cannot use the VM Proxy object.
// Contextify.connect(host.Promise.prototype.then, Promise.prototype.then);
if (PromisePrototype.finally) {
overrideWithProxy(PromisePrototype, 'finally', PromisePrototype.finally, AsyncErrorHandler);
// Contextify.connect(host.Promise.prototype.finally, Promise.prototype.finally);
}
if (Promise.prototype.catch) {
overrideWithProxy(PromisePrototype, 'catch', PromisePrototype.catch, AsyncErrorHandler);
// Contextify.connect(host.Promise.prototype.catch, Promise.prototype.catch);
}
}
function readonly(other, mock) {
// Note: other@other(unsafe) mock@other(unsafe) returns@this(unsafe) throws@this(unsafe)
if (!mock) return fromWithFactory(readonlyFactory, other);
const tmock = from(mock);
return fromWithFactory(obj=>new ReadOnlyMockHandler(obj, tmock), other);
}
return {
__proto__: null,
readonly,
global
};

931
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@
"@octokit/core": "^3.5.1",
"@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^5.13.0",
"https-proxy-agent": "^5.0.0",
"proxy-agent": "^5.0.0",
"uuid": "^8.3.2"
},
"devDependencies": {

View file

@ -1,7 +1,7 @@
import {Octokit as Core} from '@octokit/core'
import {paginateRest} from '@octokit/plugin-paginate-rest'
import {restEndpointMethods} from '@octokit/plugin-rest-endpoint-methods'
import {HttpsProxyAgent} from 'https-proxy-agent'
import ProxyAgent from 'proxy-agent'
export {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods'
export {OctokitOptions} from '@octokit/core/dist-types/types'
@ -11,23 +11,18 @@ export const Octokit = Core.plugin(
autoProxyAgent
)
// Octokit plugin to support the https_proxy and no_proxy environment variable
// Octokit plugin to support the standard environment variables http_proxy, https_proxy and no_proxy
function autoProxyAgent(octokit: Core) {
const proxy = process.env.https_proxy || process.env.HTTPS_PROXY
const noProxy = process.env.no_proxy || process.env.NO_PROXY
let noProxyArray: string[] = []
if (noProxy) {
noProxyArray = noProxy.split(',')
}
const proxy =
process.env.https_proxy ||
process.env.HTTPS_PROXY ||
process.env.http_proxy ||
process.env.HTTP_PROXY
if (!proxy) return
const agent = new HttpsProxyAgent(proxy)
const agent = new ProxyAgent()
octokit.hook.before('request', options => {
if (noProxyArray.includes(options.request.hostname)) {
return
}
options.request.agent = agent
})
}