@honeybadger-io/js 4.0.0-beta.0 → 4.0.0-beta.3

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.
@@ -263,7 +263,7 @@
263
263
  }
264
264
  function runAfterNotifyHandlers(notice, handlers, error) {
265
265
  if (notice && notice.afterNotify) {
266
- handlers.unshift(notice.afterNotify);
266
+ notice.afterNotify(error, notice);
267
267
  }
268
268
  for (var i = 0, len = handlers.length; i < len; i++) {
269
269
  handlers[i](error, notice);
@@ -271,7 +271,7 @@
271
271
  return true;
272
272
  }
273
273
  // Returns a new object with properties from other object.
274
- function newObject(obj) {
274
+ function shallowClone(obj) {
275
275
  if (typeof (obj) !== 'object' || obj === null) {
276
276
  return {};
277
277
  }
@@ -298,8 +298,14 @@
298
298
  return false;
299
299
  }
300
300
  function canSerialize(obj) {
301
- // Functions are TMI and Symbols can't convert to strings.
302
- if (/function|symbol/.test(typeof (obj))) {
301
+ var typeOfObj = typeof obj;
302
+ // Functions are TMI
303
+ if (/function/.test(typeOfObj)) {
304
+ // Let special toJSON method pass as it's used by JSON.stringify (#722)
305
+ return obj.name === 'toJSON';
306
+ }
307
+ // Symbols can't convert to strings.
308
+ if (/symbol/.test(typeOfObj)) {
303
309
  return false;
304
310
  }
305
311
  if (obj === null) {
@@ -326,7 +332,7 @@
326
332
  }
327
333
  // Serialize inside arrays
328
334
  if (Array.isArray(obj)) {
329
- return obj.map(function (o) { return serialize(o, depth + 1); });
335
+ return obj.map(function (o) { return safeSerialize(o, depth + 1); });
330
336
  }
331
337
  // Serialize inside objects
332
338
  if (typeof (obj) === 'object') {
@@ -334,7 +340,7 @@
334
340
  for (var k in obj) {
335
341
  var v = obj[k];
336
342
  if (Object.prototype.hasOwnProperty.call(obj, k) && (k != null) && (v != null)) {
337
- ret[k] = serialize(v, depth + 1);
343
+ ret[k] = safeSerialize(v, depth + 1);
338
344
  }
339
345
  }
340
346
  return ret;
@@ -342,7 +348,16 @@
342
348
  // Return everything else untouched
343
349
  return obj;
344
350
  }
345
- return serialize(obj);
351
+ function safeSerialize(obj, depth) {
352
+ if (depth === void 0) { depth = 0; }
353
+ try {
354
+ return serialize(obj, depth);
355
+ }
356
+ catch (e) {
357
+ return "[ERROR] ".concat(e);
358
+ }
359
+ }
360
+ return safeSerialize(obj);
346
361
  }
347
362
  function logger(client) {
348
363
  var log = function (method) {
@@ -381,12 +396,12 @@
381
396
  if (!thing) {
382
397
  notice = {};
383
398
  }
384
- else if (Object.prototype.toString.call(thing) === '[object Error]') {
399
+ else if (thing instanceof Error || Object.prototype.toString.call(thing) === '[object Error]') {
385
400
  var e = thing;
386
401
  notice = merge(thing, { name: e.name, message: e.message, stack: e.stack });
387
402
  }
388
403
  else if (typeof thing === 'object') {
389
- notice = newObject(thing);
404
+ notice = shallowClone(thing);
390
405
  }
391
406
  else {
392
407
  var m = String(thing);
@@ -553,33 +568,44 @@
553
568
  return result;
554
569
  }
555
570
 
571
+ var GlobalStore = /** @class */ (function () {
572
+ function GlobalStore(store) {
573
+ this.store = store;
574
+ }
575
+ GlobalStore.prototype.getStore = function () {
576
+ return this.store;
577
+ };
578
+ GlobalStore.prototype.run = function (store, callback) {
579
+ var args = [];
580
+ for (var _i = 2; _i < arguments.length; _i++) {
581
+ args[_i - 2] = arguments[_i];
582
+ }
583
+ this.store = store;
584
+ return callback.apply(void 0, args);
585
+ };
586
+ return GlobalStore;
587
+ }());
588
+
556
589
  var notifier = {
557
590
  name: 'honeybadger-js',
558
591
  url: 'https://github.com/honeybadger-io/honeybadger-js',
559
- version: '4.0.0-beta.0'
592
+ version: '4.0.0-beta.3'
560
593
  };
561
- // Split at commas
562
- var TAG_SEPARATOR = /,/;
563
- // Removes any non-word characters
564
- var TAG_SANITIZER = /[^\w]/g;
565
- // Checks for blank strings
566
- var STRING_EMPTY = '';
594
+ // Split at commas and spaces
595
+ var TAG_SEPARATOR = /,|\s+/;
567
596
  // Checks for non-blank characters
568
597
  var NOT_BLANK = /\S/;
569
598
  var Client = /** @class */ (function () {
570
599
  function Client(opts) {
571
600
  if (opts === void 0) { opts = {}; }
572
- /** @internal */
573
601
  this.__pluginsExecuted = false;
574
- /** @internal */
575
- this.__context = {};
576
- /** @internal */
577
- this.__breadcrumbs = [];
578
- /** @internal */
602
+ this.__store = null;
579
603
  this.__beforeNotifyHandlers = [];
580
- /** @internal */
581
604
  this.__afterNotifyHandlers = [];
582
605
  this.config = __assign({ apiKey: null, endpoint: 'https://api.honeybadger.io', environment: null, hostname: null, projectRoot: null, component: null, action: null, revision: null, reportData: null, breadcrumbsEnabled: true, maxBreadcrumbs: 40, maxObjectDepth: 8, logger: console, developmentEnvironments: ['dev', 'development', 'test'], debug: false, tags: null, enableUncaught: true, enableUnhandledRejection: true, afterUncaught: function () { return true; }, filters: ['creditcard', 'password'], __plugins: [] }, opts);
606
+ // First, we go with the global (shared) store.
607
+ // Webserver middleware can then switch to the AsyncStore for async context tracking.
608
+ this.__store = new GlobalStore({ context: {}, breadcrumbs: [] });
583
609
  this.logger = logger(this);
584
610
  }
585
611
  Client.prototype.factory = function (_opts) {
@@ -600,6 +626,10 @@
600
626
  }
601
627
  return this;
602
628
  };
629
+ /** @internal */
630
+ Client.prototype.__setStore = function (store) {
631
+ this.__store = store;
632
+ };
603
633
  Client.prototype.beforeNotify = function (handler) {
604
634
  this.__beforeNotifyHandlers.push(handler);
605
635
  return this;
@@ -610,23 +640,26 @@
610
640
  };
611
641
  Client.prototype.setContext = function (context) {
612
642
  if (typeof context === 'object') {
613
- this.__context = merge(this.__context, context);
643
+ var store = this.__store.getStore();
644
+ store.context = merge(store.context, context);
614
645
  }
615
646
  return this;
616
647
  };
617
648
  Client.prototype.resetContext = function (context) {
618
649
  this.logger.warn('Deprecation warning: `Honeybadger.resetContext()` has been deprecated; please use `Honeybadger.clear()` instead.');
650
+ var store = this.__store.getStore();
619
651
  if (typeof context === 'object' && context !== null) {
620
- this.__context = merge({}, context);
652
+ store.context = context;
621
653
  }
622
654
  else {
623
- this.__context = {};
655
+ store.context = {};
624
656
  }
625
657
  return this;
626
658
  };
627
659
  Client.prototype.clear = function () {
628
- this.__context = {};
629
- this.__breadcrumbs = [];
660
+ var store = this.__store.getStore();
661
+ store.context = {};
662
+ store.breadcrumbs = [];
630
663
  return this;
631
664
  };
632
665
  Client.prototype.notify = function (noticeable, name, extra) {
@@ -668,10 +701,11 @@
668
701
  stack: notice.stack
669
702
  }
670
703
  });
671
- notice.__breadcrumbs = this.config.breadcrumbsEnabled ? this.__breadcrumbs.slice() : [];
704
+ var breadcrumbs = this.__getStoreContentsOrDefault().breadcrumbs;
705
+ notice.__breadcrumbs = this.config.breadcrumbsEnabled ? breadcrumbs.slice() : [];
672
706
  // we need to have the source file data before the beforeNotifyHandlers,
673
707
  // in case they modify them
674
- var sourceCodeData = notice ? notice.backtrace.slice() : null;
708
+ var sourceCodeData = notice && notice.backtrace ? notice.backtrace.map(function (trace) { return shallowClone(trace); }) : null;
675
709
  getSourceForBacktrace(sourceCodeData, this.__getSourceFileHandler, function (sourcePerTrace) {
676
710
  sourcePerTrace.forEach(function (source, index) {
677
711
  notice.backtrace[index].source = source;
@@ -742,15 +776,16 @@
742
776
  if (objectIsEmpty(notice)) {
743
777
  return null;
744
778
  }
779
+ var context = this.__getStoreContentsOrDefault().context;
745
780
  var noticeTags = this.__constructTags(notice.tags);
746
- var contextTags = this.__constructTags(this.__context["tags"]);
781
+ var contextTags = this.__constructTags(context["tags"]);
747
782
  var configTags = this.__constructTags(this.config.tags);
748
783
  // Turning into a Set will remove duplicates
749
784
  var tags = noticeTags.concat(contextTags).concat(configTags);
750
785
  var uniqueTags = tags.filter(function (item, index) { return tags.indexOf(item) === index; });
751
786
  notice = merge(notice, {
752
787
  name: notice.name || 'Error',
753
- context: merge(this.__context, notice.context),
788
+ context: merge(context, notice.context),
754
789
  projectRoot: notice.projectRoot || this.config.projectRoot,
755
790
  environment: notice.environment || this.config.environment,
756
791
  component: notice.component || this.config.component,
@@ -771,33 +806,33 @@
771
806
  return;
772
807
  }
773
808
  opts = opts || {};
774
- var metadata = newObject(opts.metadata);
809
+ var metadata = shallowClone(opts.metadata);
775
810
  var category = opts.category || 'custom';
776
811
  var timestamp = new Date().toISOString();
777
- this.__breadcrumbs.push({
812
+ var store = this.__store.getStore();
813
+ var breadcrumbs = store.breadcrumbs;
814
+ breadcrumbs.push({
778
815
  category: category,
779
816
  message: message,
780
817
  metadata: metadata,
781
818
  timestamp: timestamp
782
819
  });
783
820
  var limit = this.config.maxBreadcrumbs;
784
- if (this.__breadcrumbs.length > limit) {
785
- this.__breadcrumbs = this.__breadcrumbs.slice(this.__breadcrumbs.length - limit);
821
+ if (breadcrumbs.length > limit) {
822
+ breadcrumbs = breadcrumbs.slice(breadcrumbs.length - limit);
786
823
  }
824
+ store.breadcrumbs = breadcrumbs;
787
825
  return this;
788
826
  };
789
- /** @internal */
790
827
  Client.prototype.__developmentMode = function () {
791
828
  if (this.config.reportData === true) {
792
829
  return false;
793
830
  }
794
831
  return (this.config.environment && this.config.developmentEnvironments.includes(this.config.environment));
795
832
  };
796
- /** @internal */
797
833
  Client.prototype.__send = function (_notice) {
798
834
  throw (new Error('Must implement send in subclass'));
799
835
  };
800
- /** @internal */
801
836
  Client.prototype.__buildPayload = function (notice) {
802
837
  var headers = filter(notice.headers, this.config.filters) || {};
803
838
  var cgiData = filter(__assign(__assign({}, notice.cgiData), formatCGIData(headers, 'HTTP_')), this.config.filters);
@@ -833,14 +868,22 @@
833
868
  details: notice.details || {}
834
869
  };
835
870
  };
836
- /** @internal */
837
871
  Client.prototype.__constructTags = function (tags) {
838
872
  if (!tags) {
839
873
  return [];
840
874
  }
841
- return tags.toString().split(TAG_SEPARATOR).map(function (tag) {
842
- return tag.replace(TAG_SANITIZER, STRING_EMPTY);
843
- }).filter(function (tag) { return NOT_BLANK.test(tag); });
875
+ return tags.toString().split(TAG_SEPARATOR).filter(function (tag) { return NOT_BLANK.test(tag); });
876
+ };
877
+ /**
878
+ * For ALS, the store may be uninitialized (if .run()` has not been called).
879
+ * This provides an easy way to read the existing store object or fall back to a default.
880
+ * Returns *a copy* of the store contents.
881
+ * @internal
882
+ */
883
+ Client.prototype.__getStoreContentsOrDefault = function () {
884
+ var existingStoreContents = this.__store.getStore();
885
+ var storeContents = existingStoreContents || {};
886
+ return __assign({ context: {}, breadcrumbs: [] }, storeContents);
844
887
  };
845
888
  return Client;
846
889
  }());
@@ -1528,10 +1571,11 @@
1528
1571
  _this.logger.debug("Unable to send error report: ".concat(x_1.status, ": ").concat(x_1.statusText), x_1, notice);
1529
1572
  return;
1530
1573
  }
1574
+ var uuid = JSON.parse(x_1.response).id;
1531
1575
  runAfterNotifyHandlers(merge(notice, {
1532
- id: JSON.parse(x_1.response).id
1576
+ id: uuid
1533
1577
  }), _this.__afterNotifyHandlers);
1534
- _this.logger.debug('Error report sent', notice);
1578
+ _this.logger.debug("Error report sent \u26A1 https://app.honeybadger.io/notice/".concat(uuid));
1535
1579
  };
1536
1580
  }
1537
1581
  catch (err) {