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

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);
@@ -326,7 +326,7 @@
326
326
  }
327
327
  // Serialize inside arrays
328
328
  if (Array.isArray(obj)) {
329
- return obj.map(function (o) { return serialize(o, depth + 1); });
329
+ return obj.map(function (o) { return safeSerialize(o, depth + 1); });
330
330
  }
331
331
  // Serialize inside objects
332
332
  if (typeof (obj) === 'object') {
@@ -334,7 +334,7 @@
334
334
  for (var k in obj) {
335
335
  var v = obj[k];
336
336
  if (Object.prototype.hasOwnProperty.call(obj, k) && (k != null) && (v != null)) {
337
- ret[k] = serialize(v, depth + 1);
337
+ ret[k] = safeSerialize(v, depth + 1);
338
338
  }
339
339
  }
340
340
  return ret;
@@ -342,7 +342,16 @@
342
342
  // Return everything else untouched
343
343
  return obj;
344
344
  }
345
- return serialize(obj);
345
+ function safeSerialize(obj, depth) {
346
+ if (depth === void 0) { depth = 0; }
347
+ try {
348
+ return serialize(obj, depth);
349
+ }
350
+ catch (e) {
351
+ return "[ERROR] ".concat(e);
352
+ }
353
+ }
354
+ return safeSerialize(obj);
346
355
  }
347
356
  function logger(client) {
348
357
  var log = function (method) {
@@ -381,7 +390,7 @@
381
390
  if (!thing) {
382
391
  notice = {};
383
392
  }
384
- else if (Object.prototype.toString.call(thing) === '[object Error]') {
393
+ else if (thing instanceof Error || Object.prototype.toString.call(thing) === '[object Error]') {
385
394
  var e = thing;
386
395
  notice = merge(thing, { name: e.name, message: e.message, stack: e.stack });
387
396
  }
@@ -553,33 +562,44 @@
553
562
  return result;
554
563
  }
555
564
 
565
+ var GlobalStore = /** @class */ (function () {
566
+ function GlobalStore(store) {
567
+ this.store = store;
568
+ }
569
+ GlobalStore.prototype.getStore = function () {
570
+ return this.store;
571
+ };
572
+ GlobalStore.prototype.run = function (store, callback) {
573
+ var args = [];
574
+ for (var _i = 2; _i < arguments.length; _i++) {
575
+ args[_i - 2] = arguments[_i];
576
+ }
577
+ this.store = store;
578
+ return callback.apply(void 0, args);
579
+ };
580
+ return GlobalStore;
581
+ }());
582
+
556
583
  var notifier = {
557
584
  name: 'honeybadger-js',
558
585
  url: 'https://github.com/honeybadger-io/honeybadger-js',
559
- version: '4.0.0-beta.0'
586
+ version: '4.0.0-beta.1'
560
587
  };
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 = '';
588
+ // Split at commas and spaces
589
+ var TAG_SEPARATOR = /,|\s+/;
567
590
  // Checks for non-blank characters
568
591
  var NOT_BLANK = /\S/;
569
592
  var Client = /** @class */ (function () {
570
593
  function Client(opts) {
571
594
  if (opts === void 0) { opts = {}; }
572
- /** @internal */
573
595
  this.__pluginsExecuted = false;
574
- /** @internal */
575
- this.__context = {};
576
- /** @internal */
577
- this.__breadcrumbs = [];
578
- /** @internal */
596
+ this.__store = null;
579
597
  this.__beforeNotifyHandlers = [];
580
- /** @internal */
581
598
  this.__afterNotifyHandlers = [];
582
599
  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);
600
+ // First, we go with the global (shared) store.
601
+ // Webserver middleware can then switch to the AsyncStore for async context tracking.
602
+ this.__store = new GlobalStore({ context: {}, breadcrumbs: [] });
583
603
  this.logger = logger(this);
584
604
  }
585
605
  Client.prototype.factory = function (_opts) {
@@ -600,6 +620,10 @@
600
620
  }
601
621
  return this;
602
622
  };
623
+ /** @internal */
624
+ Client.prototype.__setStore = function (store) {
625
+ this.__store = store;
626
+ };
603
627
  Client.prototype.beforeNotify = function (handler) {
604
628
  this.__beforeNotifyHandlers.push(handler);
605
629
  return this;
@@ -610,23 +634,26 @@
610
634
  };
611
635
  Client.prototype.setContext = function (context) {
612
636
  if (typeof context === 'object') {
613
- this.__context = merge(this.__context, context);
637
+ var store = this.__store.getStore();
638
+ store.context = merge(store.context, context);
614
639
  }
615
640
  return this;
616
641
  };
617
642
  Client.prototype.resetContext = function (context) {
618
643
  this.logger.warn('Deprecation warning: `Honeybadger.resetContext()` has been deprecated; please use `Honeybadger.clear()` instead.');
644
+ var store = this.__store.getStore();
619
645
  if (typeof context === 'object' && context !== null) {
620
- this.__context = merge({}, context);
646
+ store.context = context;
621
647
  }
622
648
  else {
623
- this.__context = {};
649
+ store.context = {};
624
650
  }
625
651
  return this;
626
652
  };
627
653
  Client.prototype.clear = function () {
628
- this.__context = {};
629
- this.__breadcrumbs = [];
654
+ var store = this.__store.getStore();
655
+ store.context = {};
656
+ store.breadcrumbs = [];
630
657
  return this;
631
658
  };
632
659
  Client.prototype.notify = function (noticeable, name, extra) {
@@ -668,10 +695,11 @@
668
695
  stack: notice.stack
669
696
  }
670
697
  });
671
- notice.__breadcrumbs = this.config.breadcrumbsEnabled ? this.__breadcrumbs.slice() : [];
698
+ var breadcrumbs = this.__getStoreOrDefaultObject().breadcrumbs;
699
+ notice.__breadcrumbs = this.config.breadcrumbsEnabled ? breadcrumbs.slice() : [];
672
700
  // we need to have the source file data before the beforeNotifyHandlers,
673
701
  // in case they modify them
674
- var sourceCodeData = notice ? notice.backtrace.slice() : null;
702
+ var sourceCodeData = notice && notice.backtrace ? notice.backtrace.map(function (trace) { return newObject(trace); }) : null;
675
703
  getSourceForBacktrace(sourceCodeData, this.__getSourceFileHandler, function (sourcePerTrace) {
676
704
  sourcePerTrace.forEach(function (source, index) {
677
705
  notice.backtrace[index].source = source;
@@ -742,15 +770,16 @@
742
770
  if (objectIsEmpty(notice)) {
743
771
  return null;
744
772
  }
773
+ var context = this.__getStoreOrDefaultObject().context;
745
774
  var noticeTags = this.__constructTags(notice.tags);
746
- var contextTags = this.__constructTags(this.__context["tags"]);
775
+ var contextTags = this.__constructTags(context["tags"]);
747
776
  var configTags = this.__constructTags(this.config.tags);
748
777
  // Turning into a Set will remove duplicates
749
778
  var tags = noticeTags.concat(contextTags).concat(configTags);
750
779
  var uniqueTags = tags.filter(function (item, index) { return tags.indexOf(item) === index; });
751
780
  notice = merge(notice, {
752
781
  name: notice.name || 'Error',
753
- context: merge(this.__context, notice.context),
782
+ context: merge(context, notice.context),
754
783
  projectRoot: notice.projectRoot || this.config.projectRoot,
755
784
  environment: notice.environment || this.config.environment,
756
785
  component: notice.component || this.config.component,
@@ -774,30 +803,30 @@
774
803
  var metadata = newObject(opts.metadata);
775
804
  var category = opts.category || 'custom';
776
805
  var timestamp = new Date().toISOString();
777
- this.__breadcrumbs.push({
806
+ var store = this.__store.getStore();
807
+ var breadcrumbs = store.breadcrumbs;
808
+ breadcrumbs.push({
778
809
  category: category,
779
810
  message: message,
780
811
  metadata: metadata,
781
812
  timestamp: timestamp
782
813
  });
783
814
  var limit = this.config.maxBreadcrumbs;
784
- if (this.__breadcrumbs.length > limit) {
785
- this.__breadcrumbs = this.__breadcrumbs.slice(this.__breadcrumbs.length - limit);
815
+ if (breadcrumbs.length > limit) {
816
+ breadcrumbs = breadcrumbs.slice(breadcrumbs.length - limit);
786
817
  }
818
+ store.breadcrumbs = breadcrumbs;
787
819
  return this;
788
820
  };
789
- /** @internal */
790
821
  Client.prototype.__developmentMode = function () {
791
822
  if (this.config.reportData === true) {
792
823
  return false;
793
824
  }
794
825
  return (this.config.environment && this.config.developmentEnvironments.includes(this.config.environment));
795
826
  };
796
- /** @internal */
797
827
  Client.prototype.__send = function (_notice) {
798
828
  throw (new Error('Must implement send in subclass'));
799
829
  };
800
- /** @internal */
801
830
  Client.prototype.__buildPayload = function (notice) {
802
831
  var headers = filter(notice.headers, this.config.filters) || {};
803
832
  var cgiData = filter(__assign(__assign({}, notice.cgiData), formatCGIData(headers, 'HTTP_')), this.config.filters);
@@ -833,14 +862,22 @@
833
862
  details: notice.details || {}
834
863
  };
835
864
  };
836
- /** @internal */
837
865
  Client.prototype.__constructTags = function (tags) {
838
866
  if (!tags) {
839
867
  return [];
840
868
  }
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); });
869
+ return tags.toString().split(TAG_SEPARATOR).filter(function (tag) { return NOT_BLANK.test(tag); });
870
+ };
871
+ /**
872
+ * For ALS, the store may be uninitialized (if .run()` has not been called).
873
+ * This provides an easy way to read the existing store object or fall back to a default.
874
+ * Returns *a copy* of the store.
875
+ * @internal
876
+ */
877
+ Client.prototype.__getStoreOrDefaultObject = function () {
878
+ var existingStore = this.__store.getStore();
879
+ var store = existingStore || {};
880
+ return __assign({ context: {}, breadcrumbs: [] }, store);
844
881
  };
845
882
  return Client;
846
883
  }());
@@ -1528,10 +1565,11 @@
1528
1565
  _this.logger.debug("Unable to send error report: ".concat(x_1.status, ": ").concat(x_1.statusText), x_1, notice);
1529
1566
  return;
1530
1567
  }
1568
+ var uuid = JSON.parse(x_1.response).id;
1531
1569
  runAfterNotifyHandlers(merge(notice, {
1532
- id: JSON.parse(x_1.response).id
1570
+ id: uuid
1533
1571
  }), _this.__afterNotifyHandlers);
1534
- _this.logger.debug('Error report sent', notice);
1572
+ _this.logger.debug("Error report sent \u26A1 https://app.honeybadger.io/notice/".concat(uuid));
1535
1573
  };
1536
1574
  }
1537
1575
  catch (err) {