@honeybadger-io/js 4.8.2 → 4.9.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.
@@ -0,0 +1,278 @@
1
+ (function (window, document) {
2
+ // eslint-disable-next-line quotes
3
+ const TEMPLATE = `<style>
4
+ #honeybadger-feedback-wrapper {
5
+ display: block;
6
+ outline: none;
7
+ position: fixed;
8
+ z-index: 999;
9
+ width: 100%;
10
+ height: 100%;
11
+ text-align: center;
12
+ top: 0;
13
+ left: 0;
14
+ background: rgba(0, 0, 0, 0.6);
15
+ overflow: auto;
16
+ }
17
+
18
+ #honeybadger-feedback {
19
+ font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
20
+ padding: 1em 3em 1em 2em;
21
+ max-width: 400px;
22
+ max-height: 80%;
23
+ margin: 4% auto 0;
24
+ text-align: left;
25
+ background: #1a202c;
26
+ color: #9CA3AF;
27
+ border-radius: 5px;
28
+ }
29
+ #honeybadger-feedback-name, #honeybadger-feedback-email, #honeybadger-feedback-comment { width: 100%; padding: 0.5em; }
30
+ #honeybadger-feedback-comment {
31
+ font-family: inherit;
32
+ height: 10em;
33
+ }
34
+
35
+ #honeybadger-feedback-error {
36
+ color: #cc0000;
37
+ }
38
+
39
+ #honeybadger-feedback-error-detail {
40
+ font-size: small;
41
+ }
42
+
43
+ .honeybadger-feedback-button {
44
+ color: initial;
45
+ padding: 0.5em 1em;
46
+ cursor: pointer;
47
+ }
48
+
49
+ .honeybadger-feedback-button.plain {
50
+ text-decoration: underline;
51
+ border: none;
52
+ background: none;
53
+ color: #9CA3AF;
54
+ }
55
+
56
+ #honeybadger-feedback-close {
57
+ padding-left: 0;
58
+ }
59
+
60
+ #honeybadger-feedback-footer {
61
+ text-align: right;
62
+ }
63
+ #honeybadger-feedback-footer img {
64
+ vertical-align: middle;
65
+ }
66
+ #honeybadger-feedback-link {
67
+ text-decoration: underline;
68
+ color: #9CA3AF;
69
+ }
70
+
71
+ @media screen and (max-height: 570px) {
72
+ #honeybadger-feedback {
73
+ max-height: none;
74
+ margin-top: 0;
75
+ }
76
+ }
77
+
78
+ @media screen and (max-height: 660px) {
79
+ #honeybadger-feedback {
80
+ max-width: none;
81
+ }
82
+ }
83
+ </style>
84
+
85
+ <div id="honeybadger-feedback">
86
+
87
+ <h2 id="honeybadger-feedback-heading">
88
+ Care to help us fix this?
89
+ </h2>
90
+
91
+ <p id="honeybadger-feedback-explanation">
92
+ Any information you can provide will help our technical team get to the bottom of this issue.
93
+ </p>
94
+
95
+ <div id="honeybadger-feedback-thanks" style="display:none;">
96
+ <p><strong>Thanks for the feedback!</strong></p>
97
+ <input type="button" class="honeybadger-feedback-button plain" id="honeybadger-feedback-close" value="Close">
98
+ </div>
99
+
100
+ <form id="honeybadger-feedback-form">
101
+ <p>
102
+ <label for="honeybadger-feedback-name" id="honeybadger-feedback-label-name">
103
+ Name
104
+ </label><br>
105
+ <input type="text" name="name" id="honeybadger-feedback-name">
106
+ </p>
107
+
108
+ <p>
109
+ <label for="honeybadger-feedback-email" id="honeybadger-feedback-label-email">
110
+ Your email address
111
+ </label><br>
112
+ <input type="email" name="email" id="honeybadger-feedback-email" value="">
113
+ </p>
114
+
115
+ <p>
116
+ <label for="honeybadger-feedback-comment" id="honeybadger-feedback-label-comment">
117
+ Comment (required)
118
+ </label><br>
119
+ <textarea name="comment" id="honeybadger-feedback-comment" cols="50" rows="6" required></textarea>
120
+ </p>
121
+
122
+ <p id="honeybadger-feedback-error" style="display: none">
123
+ There was an error. Please try again later.
124
+ <br/>
125
+ <span id="honeybadger-feedback-error-detail"></span>
126
+ </p>
127
+
128
+ <p>
129
+ <input type="submit" class="honeybadger-feedback-button" id="honeybadger-feedback-submit" value="Send">
130
+ <input type="button" class="honeybadger-feedback-button plain" id="honeybadger-feedback-cancel" value="Cancel">
131
+ </p>
132
+ </form>
133
+
134
+ <p id="honeybadger-feedback-footer">
135
+ <a id="honeybadger-feedback-link" href="https://www.honeybadger.io/" target="_blank" title="Exception, uptime, and performance monitoring for PHP.">
136
+ Powered by
137
+ <img src="https://www.honeybadger.io/images/navbar_logo.svg?1670031500" width="100"/>
138
+ </a>
139
+ </p>
140
+ </div>
141
+ `
142
+ const OPTIONS_KEY = 'honeybadgerUserFeedbackOptions'
143
+
144
+ const HoneybadgerUserFeedbackForm = function () {};
145
+ HoneybadgerUserFeedbackForm.prototype.build = function () {
146
+ const self = this
147
+ self.element = document.createElement('div')
148
+ self.element.id = 'honeybadger-feedback-wrapper'
149
+ self.element.innerHTML = TEMPLATE
150
+ self.element.onclick = function (e) {
151
+ if (e.target !== self.element) return;
152
+ self.close();
153
+ }
154
+
155
+ document.body.appendChild(self.element)
156
+
157
+ self.form = self.element.getElementsByTagName('form')[0]
158
+ self.form.addEventListener('submit', function (e) {
159
+ e.preventDefault()
160
+ self.submit()
161
+ })
162
+
163
+ const cancelButton = document.getElementById('honeybadger-feedback-cancel')
164
+ cancelButton.onclick = (e) => {
165
+ e.preventDefault()
166
+ self.close()
167
+ }
168
+ const closeButton = document.getElementById('honeybadger-feedback-close')
169
+ closeButton.onclick = (e) => {
170
+ e.preventDefault()
171
+ self.close()
172
+ }
173
+
174
+ self.applyLabelsFromOptions()
175
+ };
176
+
177
+ HoneybadgerUserFeedbackForm.prototype.applyLabelsFromOptions = function () {
178
+ const self = this
179
+
180
+ const formOptions = self.getOptions()
181
+ const { messages = {}, buttons = {}, labels = {} } = formOptions
182
+ for (let key in messages) {
183
+ const element = document.getElementById(`honeybadger-feedback-${key}`)
184
+ if (element) {
185
+ element.innerText = messages[key]
186
+ }
187
+ }
188
+ for (let key in labels) {
189
+ const element = document.getElementById(`honeybadger-feedback-label-${key}`)
190
+ if (element) {
191
+ element.innerText = labels[key]
192
+ }
193
+ }
194
+ for (let key in buttons) {
195
+ const element = document.getElementById(`honeybadger-feedback-${key}`)
196
+ if (element) {
197
+ element.value = buttons[key]
198
+ }
199
+ }
200
+ };
201
+
202
+ HoneybadgerUserFeedbackForm.prototype.close = function () {
203
+ const self = this
204
+ self.element.parentNode.removeChild(self.element);
205
+ };
206
+
207
+ HoneybadgerUserFeedbackForm.prototype.submit = function () {
208
+ const self = this
209
+ if (self.loading) return
210
+
211
+ self.loading = true
212
+ document.getElementById('honeybadger-feedback-error').style.display = 'none'
213
+ document.getElementById('honeybadger-feedback-submit').disabled = true
214
+
215
+ const script = document.createElement('script')
216
+ const form = document.getElementById('honeybadger-feedback-form')
217
+ script.src = self.getEndpoint() +
218
+ '?format=js' +
219
+ `&api_key=${self.getApiKey()}` +
220
+ `&token=${self.getLastNoticeId()}` +
221
+ `&name=${encodeURIComponent(self.form.name.value)}` +
222
+ `&email=${encodeURIComponent(self.form.email.value)}` +
223
+ `&comment=${encodeURIComponent(self.form.comment.value)}`
224
+ script.onerror = function () {
225
+ self.loading = false
226
+ // unfortunately we don't get any info here about the error (i.e. HTTP 403)
227
+ self.onFormError('')
228
+ // remove script so that user can try again
229
+ form.removeChild(script)
230
+ }
231
+ form.appendChild(script);
232
+ };
233
+
234
+ HoneybadgerUserFeedbackForm.prototype.onSuccess = function () {
235
+ document.getElementById('honeybadger-feedback-thanks').style.display = 'block'
236
+ document.getElementById('honeybadger-feedback-form').style.display = 'none'
237
+ document.getElementById('honeybadger-feedback-submit').disabled = false
238
+ };
239
+
240
+ HoneybadgerUserFeedbackForm.prototype.onFormError = function (message) {
241
+ document.getElementById('honeybadger-feedback-error').style.display = 'block'
242
+ document.getElementById('honeybadger-feedback-error-detail').innerText = message
243
+ document.getElementById('honeybadger-feedback-submit').disabled = false
244
+ };
245
+
246
+ HoneybadgerUserFeedbackForm.prototype.getOptions = function () {
247
+ return window[OPTIONS_KEY]
248
+ }
249
+
250
+ HoneybadgerUserFeedbackForm.prototype.getApiKey = function () {
251
+ return this.getOptions().apiKey
252
+ }
253
+
254
+ HoneybadgerUserFeedbackForm.prototype.getLastNoticeId = function () {
255
+ return this.getOptions().noticeId
256
+ }
257
+
258
+ HoneybadgerUserFeedbackForm.prototype.getEndpoint = function () {
259
+ return this.getOptions().endpoint
260
+ }
261
+
262
+ const form = new HoneybadgerUserFeedbackForm()
263
+ form.build()
264
+
265
+ // this function needs to be defined and will be called from the feedback script submission
266
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
267
+ window['honeybadgerFeedbackResponse'] = function honeybadgerFeedbackResponse(data) {
268
+ form.loading = false
269
+
270
+ if (data['result'] === 'OK') {
271
+ form.onSuccess()
272
+
273
+ return
274
+ }
275
+
276
+ form.onFormError(data['error'] || 'An unknown error occurred.')
277
+ }
278
+ })(window, document)
@@ -1,11 +1,16 @@
1
1
  import { Types, Client } from '@honeybadger-io/core';
2
+ export declare const getUserFeedbackScriptUrl: (version: string) => string;
2
3
  declare class Honeybadger extends Client {
3
4
  config: Types.BrowserConfig;
5
+ protected __afterNotifyHandlers: Types.AfterNotifyHandler[];
4
6
  constructor(opts?: Partial<Types.BrowserConfig>);
5
7
  configure(opts?: Partial<Types.BrowserConfig>): this;
6
8
  resetMaxErrors(): number;
7
9
  factory(opts?: Partial<Types.BrowserConfig>): this;
8
10
  checkIn(_id: string): Promise<void>;
11
+ showUserFeedbackForm(options?: Types.UserFeedbackFormOptions): Promise<void>;
12
+ private isUserFeedbackScriptUrlAlreadyVisible;
13
+ private getUserFeedbackSubmitUrl;
9
14
  }
10
15
  export { Types } from '@honeybadger-io/core';
11
16
  declare const _default: Honeybadger;
@@ -576,16 +576,18 @@
576
576
  if (!object || !name || !replacement || !(name in object)) {
577
577
  return;
578
578
  }
579
- var original = object[name];
580
- while (original && original.__hb_original) {
581
- original = original.__hb_original;
582
- }
583
579
  try {
580
+ var original = object[name];
581
+ while (original && original.__hb_original) {
582
+ original = original.__hb_original;
583
+ }
584
584
  object[name] = replacement(original);
585
585
  object[name].__hb_original = original;
586
586
  }
587
587
  catch (_e) {
588
- // Ignores errors like this one:
588
+ // Ignores errors where "original" is a restricted object (see #1001)
589
+ // Uncaught Error: Permission denied to access property "__hb_original"
590
+ // Also ignores:
589
591
  // Error: TypeError: Cannot set property onunhandledrejection of [object Object] which has only a getter
590
592
  // User-Agent: Mozilla/5.0 (Linux; Android 10; SAMSUNG SM-G960F) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/12.1 Chrome/79.0.3945.136 Mobile Safari/537.36
591
593
  }
@@ -798,7 +800,7 @@
798
800
  var notifier = {
799
801
  name: 'honeybadger-js',
800
802
  url: 'https://github.com/honeybadger-io/honeybadger-js',
801
- version: '4.8.2'
803
+ version: '4.9.2'
802
804
  };
803
805
  // Split at commas and spaces
804
806
  var TAG_SEPARATOR = /,|\s+/;
@@ -1712,15 +1714,11 @@
1712
1714
  }
1713
1715
  });
1714
1716
  }
1715
- // https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate
1716
- instrument$2(_window, 'onpopstate', function (original) {
1717
- return function () {
1717
+ if (typeof addEventListener === 'function') {
1718
+ addEventListener('popstate', function (_event) {
1718
1719
  recordUrlChange(lastHref, _window.location.href);
1719
- if (original) {
1720
- return original.apply(this, arguments);
1721
- }
1722
- };
1723
- });
1720
+ });
1721
+ }
1724
1722
  // https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
1725
1723
  // https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState
1726
1724
  function historyWrapper(original) {
@@ -1941,11 +1939,47 @@
1941
1939
  };
1942
1940
  return __assign.apply(this, arguments);
1943
1941
  };
1942
+ var __awaiter = (commonjsGlobal && commonjsGlobal.__awaiter) || function (thisArg, _arguments, P, generator) {
1943
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1944
+ return new (P || (P = Promise))(function (resolve, reject) {
1945
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1946
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1947
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1948
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
1949
+ });
1950
+ };
1951
+ var __generator = (commonjsGlobal && commonjsGlobal.__generator) || function (thisArg, body) {
1952
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
1953
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
1954
+ function verb(n) { return function (v) { return step([n, v]); }; }
1955
+ function step(op) {
1956
+ if (f) throw new TypeError("Generator is already executing.");
1957
+ while (_) try {
1958
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
1959
+ if (y = 0, t) op = [op[0] & 2, t.value];
1960
+ switch (op[0]) {
1961
+ case 0: case 1: t = op; break;
1962
+ case 4: _.label++; return { value: op[1], done: false };
1963
+ case 5: _.label++; y = op[1]; op = [0]; continue;
1964
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
1965
+ default:
1966
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
1967
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
1968
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
1969
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
1970
+ if (t[2]) _.ops.pop();
1971
+ _.trys.pop(); continue;
1972
+ }
1973
+ op = body.call(thisArg, _);
1974
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
1975
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
1976
+ }
1977
+ };
1944
1978
  var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
1945
1979
  return (mod && mod.__esModule) ? mod : { "default": mod };
1946
1980
  };
1947
1981
  Object.defineProperty(exports, "__esModule", { value: true });
1948
- exports.Types = void 0;
1982
+ exports.Types = exports.getUserFeedbackScriptUrl = void 0;
1949
1983
  var core_1 = src;
1950
1984
  var util_1 = util;
1951
1985
  var onerror_1 = onerror;
@@ -1955,23 +1989,32 @@
1955
1989
  var event_listeners_1 = __importDefault(event_listeners);
1956
1990
  var transport_1 = transport;
1957
1991
  var merge = core_1.Util.merge, filter = core_1.Util.filter, objectIsExtensible = core_1.Util.objectIsExtensible;
1992
+ var getProjectRoot = function () {
1993
+ var global = (0, util_1.globalThisOrWindow)();
1994
+ var projectRoot = '';
1995
+ // Cloudflare workers do not have access to location API.
1996
+ if (global.location != null) {
1997
+ projectRoot = global.location.protocol + '//' + global.location.host;
1998
+ }
1999
+ return projectRoot;
2000
+ };
2001
+ var getUserFeedbackScriptUrl = function (version) {
2002
+ var majorMinorVersion = version.split('.').slice(0, 2).join('.');
2003
+ return "https://js.honeybadger.io/v".concat(majorMinorVersion, "/honeybadger-feedback-form.js");
2004
+ };
2005
+ exports.getUserFeedbackScriptUrl = getUserFeedbackScriptUrl;
1958
2006
  var Honeybadger = /** @class */ (function (_super) {
1959
2007
  __extends(Honeybadger, _super);
1960
2008
  function Honeybadger(opts) {
1961
2009
  if (opts === void 0) { opts = {}; }
1962
- var _this = this;
1963
- var global = (0, util_1.globalThisOrWindow)();
1964
- var projectRoot = '';
1965
- // Cloudflare workers do not have access to location API.
1966
- if (global.location != null) {
1967
- projectRoot = global.location.protocol + '//' + global.location.host;
1968
- }
1969
- _this = _super.call(this, __assign({ async: true, maxErrors: null, projectRoot: projectRoot }, opts), new transport_1.BrowserTransport()) || this;
2010
+ var _this = _super.call(this, __assign({ userFeedbackEndpoint: 'https://api.honeybadger.io/v2/feedback', async: true, maxErrors: null, projectRoot: getProjectRoot() }, opts), new transport_1.BrowserTransport()) || this;
1970
2011
  /** @internal */
1971
2012
  _this.__errorsSent = 0;
1972
2013
  /** @internal */
1973
2014
  _this.__lastWrapErr = undefined;
1974
2015
  /** @internal */
2016
+ _this.__lastNoticeId = undefined;
2017
+ /** @internal */
1975
2018
  _this.__beforeNotifyHandlers = [
1976
2019
  function (notice) {
1977
2020
  if (_this.__exceedsMaxErrors()) {
@@ -1985,6 +2028,14 @@
1985
2028
  return true;
1986
2029
  }
1987
2030
  ];
2031
+ _this.__afterNotifyHandlers = [
2032
+ function (_error, notice) {
2033
+ if (notice) {
2034
+ _this.__lastNoticeId = notice.id;
2035
+ }
2036
+ return true;
2037
+ }
2038
+ ];
1988
2039
  return _this;
1989
2040
  }
1990
2041
  Honeybadger.prototype.configure = function (opts) {
@@ -2001,6 +2052,54 @@
2001
2052
  Honeybadger.prototype.checkIn = function (_id) {
2002
2053
  throw new Error('Honeybadger.checkIn() is not supported on the browser');
2003
2054
  };
2055
+ Honeybadger.prototype.showUserFeedbackForm = function (options) {
2056
+ if (options === void 0) { options = {}; }
2057
+ return __awaiter(this, void 0, void 0, function () {
2058
+ var global, script;
2059
+ return __generator(this, function (_a) {
2060
+ if (!this.config || !this.config.apiKey) {
2061
+ this.logger.debug('Client not initialized');
2062
+ return [2 /*return*/];
2063
+ }
2064
+ if (!this.__lastNoticeId) {
2065
+ this.logger.debug("Can't show user feedback form without a notice already reported");
2066
+ return [2 /*return*/];
2067
+ }
2068
+ global = (0, util_1.globalThisOrWindow)();
2069
+ if (typeof global.document === 'undefined') {
2070
+ this.logger.debug('global.document is undefined. Cannot attach script');
2071
+ return [2 /*return*/];
2072
+ }
2073
+ if (this.isUserFeedbackScriptUrlAlreadyVisible()) {
2074
+ this.logger.debug('User feedback form is already visible');
2075
+ return [2 /*return*/];
2076
+ }
2077
+ global['honeybadgerUserFeedbackOptions'] = __assign(__assign({}, options), { apiKey: this.config.apiKey, endpoint: this.config.userFeedbackEndpoint, noticeId: this.__lastNoticeId });
2078
+ script = global.document.createElement('script');
2079
+ script.setAttribute('src', this.getUserFeedbackSubmitUrl());
2080
+ script.setAttribute('async', 'true');
2081
+ if (options.onLoad) {
2082
+ script.onload = options.onLoad;
2083
+ }
2084
+ (global.document.head || global.document.body).appendChild(script);
2085
+ return [2 /*return*/];
2086
+ });
2087
+ });
2088
+ };
2089
+ Honeybadger.prototype.isUserFeedbackScriptUrlAlreadyVisible = function () {
2090
+ var global = (0, util_1.globalThisOrWindow)();
2091
+ var feedbackScriptUrl = this.getUserFeedbackSubmitUrl();
2092
+ for (var i = 0; i < global.document.scripts.length; i++) {
2093
+ var script = global.document.scripts[i];
2094
+ if (script.src === feedbackScriptUrl) {
2095
+ return true;
2096
+ }
2097
+ }
2098
+ return false;
2099
+ };
2100
+ Honeybadger.prototype.getUserFeedbackSubmitUrl = function () {
2101
+ return (0, exports.getUserFeedbackScriptUrl)(this.getVersion());
2102
+ };
2004
2103
  /** @internal */
2005
2104
  Honeybadger.prototype.__buildPayload = function (notice) {
2006
2105
  var cgiData = {