+1
-0
@@ -221,2 +221,3 @@ /** | ||
| methodName === '_hasFinishedExecuting' || | ||
| methodName === '_hasAlreadyWaitedAtLeastOneTick' || | ||
| methodName === '_hasTimedOut' || | ||
@@ -223,0 +224,0 @@ methodName === '_handleExec' || |
+158
-63
@@ -152,26 +152,9 @@ /** | ||
| // This variable (`cb`) is used as our callback. In the next few lines, we determine | ||
| // what it will be. This is just a potentially-more-efficient alternative to a series | ||
| // of self-calling functions that we use to afford better performance in the general case. | ||
| // (Normally, this sort of micro-optimization wouldn't matter, but this is an extradordinarily | ||
| // hot code path. Note that if we can prove self-calling functions are just as good, or even | ||
| // good enough, it would be preferable to use them instead (not only for consistency, but | ||
| // certainly for clarity as well).) | ||
| var cb; | ||
| // Impose arbitrary restriction against an edge case that would hurt performance for us to implement. | ||
| // FUTURE: maybe solve this, but see note below -- might not even be relevant... | ||
| if (self._interceptAfterExec && !_.isUndefined(handleUncaughtException)){ | ||
| throw new Error('Consistency violation: Currently, the 2nd argument to .exec() may not be used, since this Deferred was built with a custom `interceptAfterExec` handler. Please avoid using the 2nd argument to .exec() and use ES8 async/await instead, if possible.'); | ||
| } | ||
| // If 2nd argument (handleUncaughtException) was provided, then wrap `_cb` in another function | ||
| // that protects against uncaught exceptions. | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
| // FUTURE: Consider adding a deprecation notice to this behavior and eventually removing | ||
| // support (now that ES8 async/await widely available on the server, and should be available | ||
| // in the browser... soonish?) | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
| if (!_.isUndefined(handleUncaughtException)) { | ||
| // Check usage of 2nd argument to .exec(). | ||
| if (handleUncaughtException !== undefined) { | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
| // FUTURE: Consider adding a deprecation notice to this behavior, and then remove support | ||
| // altogether. (This isn't really as necessary anymore now that ES8 async/await is widely | ||
| // available on the server, and should be available in the browser... soonish?) | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
| if (!_.isFunction(handleUncaughtException)) { | ||
@@ -186,48 +169,133 @@ throw flaverr({ | ||
| }, self._omen); | ||
| }//-• | ||
| }//• | ||
| cb = function _tryToRunCb() { | ||
| // Impose arbitrary restriction against an unsupported edge case. | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
| // FUTURE: maybe remove this restriction. But also... might not even be relevant, since | ||
| // we'll probably get rid of support for this usage (see above) | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
| if (self._interceptAfterExec){ | ||
| throw new Error('Consistency violation: Currently, the 2nd argument to .exec() may not be used, since this Deferred was built with a custom `interceptAfterExec` handler. Please avoid using the 2nd argument to .exec() and use ES8 async/await instead, if possible.'); | ||
| }//• | ||
| }//fi | ||
| // This variable (`cb`) is used as our callback. In the next few lines, we determine | ||
| // what it will be. This is just a potentially-more-efficient alternative to a series | ||
| // of self-calling functions, We only do this to afford better performance in the general case. | ||
| // | ||
| // > (Normally, this sort of micro-optimization wouldn't matter, but this is an extradordinarily | ||
| // > hot code path. Note that if we can prove self-calling functions are just as good, or even | ||
| // > good enough, it would be preferable to use them instead (not only for consistency, but | ||
| // > certainly for clarity as well).) | ||
| var cb; | ||
| // To begin with, no matter what, intercept `_cb` by wrapping it in another function | ||
| // (a new one that we'll call `cb`) which adds some additional checks. | ||
| // | ||
| // > Note that we don't use .slice() on the `arguments` keyword -- this is for perf. | ||
| // > (see https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#what-is-safe-arguments-usage) | ||
| cb = function _tryToRunCb(/*…*/) { | ||
| // If this Deferred was built with an `interceptAfterExec` lifecycle callback, | ||
| // then intercept our normal flow to call that lifecycle callback, picking up | ||
| // the potentially-changed (even potentially-reconstructed!) error or result. | ||
| if (self._interceptAfterExec) { | ||
| if (arguments[0]) { | ||
| arguments[0] = self._interceptAfterExec(arguments[0]); | ||
| } | ||
| else { | ||
| arguments[1] = self._interceptAfterExec(undefined, arguments[1]); | ||
| } | ||
| }//fi | ||
| // If this callback is being called after at least one tick has elapsed... | ||
| if (self._hasAlreadyWaitedAtLeastOneTick) { | ||
| // If 2nd argument (handleUncaughtException) was provided to .exec(), then run that | ||
| // instead of throwing. This protects against unexpected, uncaught exceptions in | ||
| // asynchronous callbacks. | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
| // FUTURE: Probably deprecate this, then remove support (see above). | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
| if (handleUncaughtException) { | ||
| try { | ||
| return _cb.apply(undefined, arguments); | ||
| } catch (unexpectedErrorFromCallback) { | ||
| return handleUncaughtException(unexpectedErrorFromCallback); | ||
| } | ||
| }//• | ||
| // Otherwise, just trigger the callback as-is. | ||
| // (If it throws, it will crash the process!) | ||
| return _cb.apply(undefined, arguments); | ||
| }//• | ||
| //‡ | ||
| // Otherwise, our logic is synchronous (i.e. <1 async tick has elapsed at the time it's being | ||
| // called). So wrap the `_cb` from userland in a try/catch. If an unhandled error of any kind | ||
| // is thrown from the userland cb, our wrapper uses a special Envelope to bust out of the `try` | ||
| // block, ensuring that the unhandled exception is thrown up to userland. | ||
| // | ||
| // > NOTE: | ||
| // > Without this extra code here, we'd end up with the old behavior: outputting a puzzling error | ||
| // > message -- e.g. about something unexpected things happening in the Deferred, or a warning | ||
| // > about triggering the callback twice (when actually, the issue is that something went wrong | ||
| // > in the callback-- and that the Deferred logic happened to be synchronous, so it wasn't able | ||
| // > to escape parley's internal `try` block.) | ||
| // > | ||
| // > Some relevant links for reference: | ||
| // > • https://github.com/node-machine/machine/blob/7fdcf8a869605d0951909725061379cd27bd7f0d/lib/private/intercept-exit-callbacks.js#L186-L238 | ||
| // > • https://github.com/node-machine/machine/search?utf8=%E2%9C%93&q=_hasFnYieldedYet&type= | ||
| // > • https://github.com/node-machine/machine/search?utf8=%E2%9C%93&q=_runningSynchronously&type= | ||
| else { | ||
| try { | ||
| // > Note that we don't use .slice() -- this is for perf. | ||
| // > (see https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#what-is-safe-arguments-usage) | ||
| return _cb.apply(undefined, arguments); | ||
| } catch (e) { return handleUncaughtException(e); } | ||
| }; | ||
| }//‡ | ||
| // If this Deferred was built with an `interceptAfterExec` lifecycle callback, then wrap | ||
| // `_cb` in another function that intercepts the error or result. | ||
| else if (self._interceptAfterExec){ | ||
| cb = function _performInterceptAfterExec(err, result){ | ||
| if (err) { | ||
| err = self._interceptAfterExec(err); | ||
| return _cb(err); | ||
| } catch (unexpectedErrorFromCallback) { | ||
| throw flaverr({ | ||
| name: 'Envelope', | ||
| code: 'E_ESCAPE_HATCH', | ||
| traceRef: self, | ||
| raw: unexpectedErrorFromCallback | ||
| }); | ||
| } | ||
| else { | ||
| result = self._interceptAfterExec(undefined, result); | ||
| return _cb(undefined, result); | ||
| } | ||
| }; | ||
| }//‡ | ||
| // Otherwise, just use `_cb` as-is. | ||
| else { | ||
| }//• | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
| // FUTURE: Consider wrapping cb in a function that injects a try/catch. If an unhandled | ||
| // exception is thrown, our wrapper could check synchronicity and, if synchronous, inject | ||
| // a `setImmediate()` call to ensure that the process crashes from an unhandled exception, | ||
| // rather than outputting a rather puzzling error message -- e.g. about something unexpected | ||
| // happening in the Deferred (when actually, the issue is that something went wrong in the | ||
| // callback-- and that the Deferred logic happened to be synchronous.) | ||
| // FUTURE: Additionally, this additional layer of wrapping could take care of improving | ||
| // stack traces, even in the case where an Error comes up from inside the implementation. | ||
| // If done carefully, this can be done in a way that protects characteristics of the | ||
| // internal Error (e.g. its "code", etc.), while also providing a better stack trace. | ||
| // | ||
| // This would take care of weird errors that have stuff like this in them: | ||
| // "Also, here are the available keys on `self` at this point:\n```\n_handleExec,meta,usingConnection,where,limit,skip,paginate,sort,sum,avg,min,max,groupBy,select,omit,populateAll,populate,_WLModel,_wlQueryInfo,_hasBegunExecuting,_hasFinishedExecuting" | ||
| // | ||
| // Some relevant links: | ||
| // • https://github.com/node-machine/machine/blob/7fdcf8a869605d0951909725061379cd27bd7f0d/lib/private/intercept-exit-callbacks.js#L186-L238 | ||
| // • https://github.com/node-machine/machine/search?utf8=%E2%9C%93&q=_hasFnYieldedYet&type= | ||
| // • https://github.com/node-machine/machine/search?utf8=%E2%9C%93&q=_runningSynchronously&type= | ||
| // For example, something like this: | ||
| // ``` | ||
| // var relevantPropNames = _.difference( | ||
| // _.union( | ||
| // ['name', 'message'], | ||
| // Object.getOwnPropertyNames(underlyingError) | ||
| // ), | ||
| // ['stack'] | ||
| // ); | ||
| // var errTemplate = _.pick(underlyingError, relevantPropNames); | ||
| // errTemplate.raw = underlyingError;//<< could override stuff-- that's ok (see below). | ||
| // var newError = flaverr(errTemplate, omen); | ||
| // ``` | ||
| // > Note that, above, we also kept the original error (and thus _its_ trace) and | ||
| // > attached that as a separate property. If the original error already has "raw", | ||
| // > that's ok. This is one thing that it makes sense for us to mutate-- and any | ||
| // > attempt to do otherwise would probably be more confusing (you can imagine a while | ||
| // > loop where we add underscores in front of the string "raw", and use that as a keyname. | ||
| // > But again, that ends up being more confusing from a userland perspective.) | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
| cb = _cb; | ||
| }//>- | ||
| };//ƒ | ||
| // Userland spinlock | ||
@@ -306,3 +374,3 @@ if (self._hasBegunExecuting) { | ||
| }, self._timeout);// _∏_ | ||
| }, self._timeout);// _∏_ (invoking `setTimeout()`) | ||
| }//>- | ||
@@ -312,6 +380,6 @@ | ||
| // Trigger the executioner function. | ||
| // | ||
| // > Note that we always wrap the executioner in a `try` block to prevent common issues from | ||
| // > uncaught exceptions, at least within the tick. | ||
| try { | ||
| self._handleExec(function (err, result) { | ||
@@ -378,5 +446,9 @@ | ||
| self._hasFinishedExecuting = true; | ||
| return cb(err); | ||
| }//-• | ||
| // IWMIH, there was no error. | ||
| self._hasFinishedExecuting = true; | ||
@@ -408,2 +480,10 @@ | ||
| // Check to make sure this error isn't a special "escape hatch" from | ||
| // the edge case where an error was thrown from within the userland callback | ||
| // provided to .exec() -- specifically in the case where the handleExec logic | ||
| // is synchronous (i.e. non-blocking- triggering its `done` within 1 tick.) | ||
| if (e.name === 'Envelope' && e.code === 'E_ESCAPE_HATCH' && e.traceRef === self) { | ||
| throw e.raw; | ||
| }//• | ||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
@@ -497,2 +577,17 @@ // NOTE: The following code is ALMOST exactly the same as the code above. | ||
| }//</catch> | ||
| // Use `self._hasAlreadyWaitedAtLeastOneTick` to track whether or not this logic is asynchronous. | ||
| if (self._hasFinishedExecuting) { | ||
| // IWMIH and we've already finished running `handleExec`, then we know | ||
| // it must have been composed purely of blocking (i.e. synchronous) logic. | ||
| self._hasAlreadyWaitedAtLeastOneTick = false; | ||
| } | ||
| else { | ||
| // Otherwise, IWMIH we know that the callback hasn't been called yet-- meaning | ||
| // that we're likely dealing with some non-blocking (i.e. asynchronous) logic. | ||
| // (Or possibly a bug where the callback isn't getting called -_-) | ||
| self._hasAlreadyWaitedAtLeastOneTick = true; | ||
| } | ||
| }; | ||
@@ -499,0 +594,0 @@ |
+1
-1
| { | ||
| "name": "parley", | ||
| "version": "2.4.0-3", | ||
| "version": "3.0.0-0", | ||
| "description": "Practical, lightweight flow control for Node.js. Supports callbacks and promises.", | ||
@@ -5,0 +5,0 @@ "main": "lib/parley.js", |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
170714
2.42%2491
3.06%15
-28.57%