@honeybadger-io/js 6.16.0 → 6.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -856,8 +856,36 @@ var require$$0$1 = /*@__PURE__*/getAugmentedNamespace(stackTraceParser_esm);
856
856
  return formattedVars;
857
857
  }
858
858
  exports.formatCGIData = formatCGIData;
859
+ /**
860
+ * Deep-copies a value exactly the way a JSON round trip does -- `toJSON` is
861
+ * honored, so dates become ISO strings -- except that circular references are
862
+ * replaced with '[RECURSION]' instead of throwing.
863
+ *
864
+ * Only true cycles are replaced: a value referenced twice in sibling branches
865
+ * is copied twice, as a JSON round trip would.
866
+ *
867
+ * Anything else a round trip rejects (a BigInt, a getter that throws) still
868
+ * throws here. Callers that must not fail are expected to handle it: silently
869
+ * substituting a placeholder would let a malformed value -- a string where an
870
+ * object is expected, say -- travel on as though it were valid.
871
+ */
859
872
  function clone(obj) {
860
- return JSON.parse(JSON.stringify(obj));
873
+ var ancestors = [];
874
+ return JSON.parse(JSON.stringify(obj, function (_key, value) {
875
+ if (typeof value !== 'object' || value === null) {
876
+ return value;
877
+ }
878
+ // `this` is the object `value` sits in, so anything stacked above it has
879
+ // been fully visited and is no longer an ancestor of `value`.
880
+ while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) {
881
+ ancestors.pop();
882
+ }
883
+ if (ancestors.indexOf(value) !== -1) {
884
+ return '[RECURSION]';
885
+ }
886
+ ancestors.push(value);
887
+ return value;
888
+ }));
861
889
  }
862
890
  exports.clone = clone;
863
891
  var THRESHOLD_COLUMN_NUMBER = 10000;
@@ -995,7 +1023,11 @@ var GlobalStore = /** @class */ (function () {
995
1023
  };
996
1024
  GlobalStore.prototype.getContents = function (key) {
997
1025
  var value = key ? this.contents[key] : this.contents;
998
- return JSON.parse(JSON.stringify(value));
1026
+ // `clone` keeps JSON round trip semantics but tolerates values a bare
1027
+ // round trip throws on -- notably circular references, which arrive via
1028
+ // context or breadcrumb metadata the host application controls.
1029
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1030
+ return (0, util_1$7.clone)(value);
999
1031
  };
1000
1032
  GlobalStore.prototype.setContext = function (context) {
1001
1033
  this.contents.context = (0, util_1$7.merge)(this.contents.context, context || {});
@@ -1441,7 +1473,7 @@ var Client = /** @class */ (function () {
1441
1473
  this.__notifier = {
1442
1474
  name: '@honeybadger-io/core',
1443
1475
  url: 'https://github.com/honeybadger-io/honeybadger-js/tree/master/packages/core',
1444
- version: '6.16.0'
1476
+ version: '6.16.2'
1445
1477
  };
1446
1478
  this.config = __assign$1(__assign$1({}, defaults_1.CONFIG), opts);
1447
1479
  this.__initStore();
@@ -1540,31 +1572,63 @@ var Client = /** @class */ (function () {
1540
1572
  this.__store.clear();
1541
1573
  return this;
1542
1574
  };
1575
+ /**
1576
+ * Reporting an error must never break the host application, so any failure
1577
+ * inside the reporting path is logged and swallowed rather than thrown back
1578
+ * into the caller.
1579
+ */
1543
1580
  Client.prototype.notify = function (noticeable, name, extra) {
1544
1581
  var _this = this;
1545
1582
  if (name === void 0) { name = undefined; }
1546
1583
  if (extra === void 0) { extra = undefined; }
1547
- var notice = this.makeNotice(noticeable, name, extra);
1548
- // we need to have the source file data before the beforeNotifyHandlers,
1549
- // in case they modify them
1550
- var sourceCodeData = notice && notice.backtrace ? notice.backtrace.map(function (trace) { return (0, util_1$5.shallowClone)(trace); }) : null;
1551
- var preConditionsResult = this.__runPreconditions(notice);
1552
- if (preConditionsResult instanceof Error) {
1553
- (0, util_1$5.runAfterNotifyHandlers)(notice, this.__afterNotifyHandlers, preConditionsResult);
1584
+ // The body is inlined in this try/catch rather than delegated to a private
1585
+ // method: generated backtraces are trimmed by a fixed frame count
1586
+ // (DEFAULT_BACKTRACE_SHIFT), so an extra call frame here would shift every
1587
+ // generated backtrace into Honeybadger's own source.
1588
+ try {
1589
+ var notice_1 = this.makeNotice(noticeable, name, extra);
1590
+ // we need to have the source file data before the beforeNotifyHandlers,
1591
+ // in case they modify them
1592
+ var sourceCodeData_1 = notice_1 && notice_1.backtrace ? notice_1.backtrace.map(function (trace) { return (0, util_1$5.shallowClone)(trace); }) : null;
1593
+ var preConditionsResult = this.__runPreconditions(notice_1);
1594
+ if (preConditionsResult instanceof Error) {
1595
+ (0, util_1$5.runAfterNotifyHandlers)(notice_1, this.__afterNotifyHandlers, preConditionsResult);
1596
+ return false;
1597
+ }
1598
+ if (preConditionsResult instanceof Promise) {
1599
+ preConditionsResult.then(function (result) {
1600
+ if (result instanceof Error) {
1601
+ (0, util_1$5.runAfterNotifyHandlers)(notice_1, _this.__afterNotifyHandlers, result);
1602
+ return false;
1603
+ }
1604
+ return _this.__send(notice_1, sourceCodeData_1);
1605
+ }).catch(function (err) {
1606
+ // __send installs its own catch, which logs and runs the afterNotify
1607
+ // handlers. Anything arriving here failed before that chain existed,
1608
+ // so it is still unreported -- and notify() has already returned
1609
+ // true, leaving notifyAsync() waiting on those handlers.
1610
+ _this.__logReportingFailure(err);
1611
+ (0, util_1$5.runAfterNotifyHandlers)(notice_1, _this.__afterNotifyHandlers, err instanceof Error ? err : new Error(String(err)));
1612
+ });
1613
+ return true;
1614
+ }
1615
+ this.__send(notice_1, sourceCodeData_1).catch(function (_err) { });
1616
+ return true;
1617
+ }
1618
+ catch (err) {
1619
+ // Reporting an error must never break the host application, so a failure
1620
+ // in the reporting path is logged rather than thrown back at the caller.
1621
+ // notifyAsync() settles on the false return below.
1622
+ this.__logReportingFailure(err);
1554
1623
  return false;
1555
1624
  }
1556
- if (preConditionsResult instanceof Promise) {
1557
- preConditionsResult.then(function (result) {
1558
- if (result instanceof Error) {
1559
- (0, util_1$5.runAfterNotifyHandlers)(notice, _this.__afterNotifyHandlers, result);
1560
- return false;
1561
- }
1562
- return _this.__send(notice, sourceCodeData);
1563
- });
1564
- return true;
1625
+ };
1626
+ /** The logger is host-supplied, so even reporting a failure gets a guard. */
1627
+ Client.prototype.__logReportingFailure = function (err) {
1628
+ try {
1629
+ this.logger.error('Error report failed: an internal error occurred while reporting', err);
1565
1630
  }
1566
- this.__send(notice, sourceCodeData).catch(function (_err) { });
1567
- return true;
1631
+ catch (_loggerErr) { /* nothing left to report it with */ }
1568
1632
  };
1569
1633
  /**
1570
1634
  * An async version of {@link notify} that resolves only after the notice has been reported to Honeybadger.
@@ -1580,11 +1644,19 @@ var Client = /** @class */ (function () {
1580
1644
  var applyAfterNotify = function (partialNotice) {
1581
1645
  var originalAfterNotify = partialNotice.afterNotify;
1582
1646
  partialNotice.afterNotify = function (err) {
1583
- originalAfterNotify === null || originalAfterNotify === void 0 ? void 0 : originalAfterNotify.call(_this, err);
1584
- if (err) {
1585
- return reject(err);
1647
+ // Settle from a `finally` so a throwing handler cannot leave the
1648
+ // caller awaiting forever; its error propagates as it always has.
1649
+ try {
1650
+ originalAfterNotify === null || originalAfterNotify === void 0 ? void 0 : originalAfterNotify.call(_this, err);
1651
+ }
1652
+ finally {
1653
+ if (err) {
1654
+ reject(err);
1655
+ }
1656
+ else {
1657
+ resolve();
1658
+ }
1586
1659
  }
1587
- resolve();
1588
1660
  };
1589
1661
  };
1590
1662
  // We have to respect any afterNotify hooks that come from the arguments
@@ -1608,7 +1680,14 @@ var Client = /** @class */ (function () {
1608
1680
  objectToOverride = name = {};
1609
1681
  }
1610
1682
  applyAfterNotify(objectToOverride);
1611
- _this.notify(noticeable, name, extra);
1683
+ // `notify` never throws, so a false return is the only signal that the
1684
+ // report was abandoned. Every expected failure has already settled this
1685
+ // promise through the afterNotify hook above (a second reject is a
1686
+ // no-op); this catches the unexpected ones, which would otherwise leave
1687
+ // the caller awaiting forever.
1688
+ if (!_this.notify(noticeable, name, extra)) {
1689
+ reject(new Error('Error report failed: see logs for details'));
1690
+ }
1612
1691
  });
1613
1692
  };
1614
1693
  Client.prototype.makeNotice = function (noticeable, name, extra) {
@@ -2238,7 +2317,7 @@ http_event.buildRequestEventPayload = buildRequestEventPayload;
2238
2317
  Object.defineProperty(aws_lambda, "__esModule", { value: true });
2239
2318
  aws_lambda.removeAwsDefaultUncaughtExceptionListener = aws_lambda.lambdaHandler = void 0;
2240
2319
  /* eslint-disable @typescript-eslint/no-explicit-any */
2241
- var core_1$4 = src;
2320
+ var core_1$5 = src;
2242
2321
  var http_event_1$1 = http_event;
2243
2322
  function isHandlerSync(handler) {
2244
2323
  return handler.length > 2;
@@ -2336,7 +2415,7 @@ function seedLambdaEventContext(hb, event, context) {
2336
2415
  function createLambdaRequestEmitter(hb, event) {
2337
2416
  if (!isHttpLambdaEvent(event))
2338
2417
  return null;
2339
- if (!core_1$4.Util.resolveInsights(hb.config).http)
2418
+ if (!core_1$5.Util.resolveInsights(hb.config).http)
2340
2419
  return null;
2341
2420
  var start = (0, http_event_1$1.startTimer)();
2342
2421
  var emitted = false;
@@ -2797,7 +2876,7 @@ var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || func
2797
2876
  Object.defineProperty(middleware, "__esModule", { value: true });
2798
2877
  middleware.errorHandler = middleware.requestHandler = void 0;
2799
2878
  var url_1$1 = __importDefault(require$$0__default$2["default"]);
2800
- var core_1$3 = src;
2879
+ var core_1$4 = src;
2801
2880
  var http_event_1 = http_event;
2802
2881
  function fullUrl(req) {
2803
2882
  var connection = req.connection;
@@ -2845,7 +2924,7 @@ function requestHandler(req, res, next) {
2845
2924
  var _this = this;
2846
2925
  this.withRequest(req, function () {
2847
2926
  _this.setEventContext((0, http_event_1.seedRequestEventContext)(req.headers));
2848
- if (core_1$3.Util.resolveInsights(_this.config).http) {
2927
+ if (core_1$4.Util.resolveInsights(_this.config).http) {
2849
2928
  instrumentInboundRequest(_this, req, res);
2850
2929
  }
2851
2930
  next();
@@ -2907,12 +2986,12 @@ var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (
2907
2986
  };
2908
2987
  Object.defineProperty(transport, "__esModule", { value: true });
2909
2988
  transport.ServerTransport = void 0;
2910
- var core_1$2 = src;
2989
+ var core_1$3 = src;
2911
2990
  var url_1 = require$$0__default$2["default"];
2912
2991
  var util_1 = util;
2913
2992
  var http = __importStar(require$$3__default$1["default"]);
2914
2993
  var https = __importStar(require$$4__default["default"]);
2915
- var sanitize = core_1$2.Util.sanitize;
2994
+ var sanitize = core_1$3.Util.sanitize;
2916
2995
  var ServerTransport = /** @class */ (function () {
2917
2996
  function ServerTransport(headers) {
2918
2997
  if (headers === void 0) { headers = {}; }
@@ -2988,6 +3067,8 @@ var async_store = {};
2988
3067
 
2989
3068
  Object.defineProperty(async_store, "__esModule", { value: true });
2990
3069
  async_store.AsyncStore = void 0;
3070
+ var core_1$2 = src;
3071
+ var clone = core_1$2.Util.clone;
2991
3072
  var kHoneybadgerStore = Symbol.for('kHoneybadgerStore');
2992
3073
  var AsyncStore = /** @class */ (function () {
2993
3074
  function AsyncStore(asyncLocalStorage, contents, breadcrumbsLimit) {
@@ -3018,7 +3099,10 @@ var AsyncStore = /** @class */ (function () {
3018
3099
  };
3019
3100
  AsyncStore.prototype.getContents = function (key) {
3020
3101
  var value = key ? this.__currentContents()[key] : this.__currentContents();
3021
- return JSON.parse(JSON.stringify(value));
3102
+ // Deep copy like a JSON round trip, but tolerate circular references in
3103
+ // host-supplied context and breadcrumb metadata. See GlobalStore.
3104
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3105
+ return clone(value);
3022
3106
  };
3023
3107
  AsyncStore.prototype.available = function () {
3024
3108
  return !!this.als.getStore();
@@ -3905,7 +3989,7 @@ client.CheckInsClient = CheckInsClient;
3905
3989
  var NOTIFIER = {
3906
3990
  name: '@honeybadger-io/js',
3907
3991
  url: 'https://github.com/honeybadger-io/honeybadger-js/tree/master/packages/js',
3908
- version: '6.16.0'
3992
+ version: '6.16.2'
3909
3993
  };
3910
3994
  var userAgent = function () {
3911
3995
  return "Honeybadger JS Server Client ".concat(NOTIFIER.version, ", ").concat(os_1.default.version(), "; ").concat(os_1.default.platform());