@honeybadger-io/js 4.8.2 → 4.9.0

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;
@@ -798,7 +798,7 @@
798
798
  var notifier = {
799
799
  name: 'honeybadger-js',
800
800
  url: 'https://github.com/honeybadger-io/honeybadger-js',
801
- version: '4.8.2'
801
+ version: '4.9.0'
802
802
  };
803
803
  // Split at commas and spaces
804
804
  var TAG_SEPARATOR = /,|\s+/;
@@ -1941,11 +1941,47 @@
1941
1941
  };
1942
1942
  return __assign.apply(this, arguments);
1943
1943
  };
1944
+ var __awaiter = (commonjsGlobal && commonjsGlobal.__awaiter) || function (thisArg, _arguments, P, generator) {
1945
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1946
+ return new (P || (P = Promise))(function (resolve, reject) {
1947
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1948
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1949
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1950
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
1951
+ });
1952
+ };
1953
+ var __generator = (commonjsGlobal && commonjsGlobal.__generator) || function (thisArg, body) {
1954
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
1955
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
1956
+ function verb(n) { return function (v) { return step([n, v]); }; }
1957
+ function step(op) {
1958
+ if (f) throw new TypeError("Generator is already executing.");
1959
+ while (_) try {
1960
+ 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;
1961
+ if (y = 0, t) op = [op[0] & 2, t.value];
1962
+ switch (op[0]) {
1963
+ case 0: case 1: t = op; break;
1964
+ case 4: _.label++; return { value: op[1], done: false };
1965
+ case 5: _.label++; y = op[1]; op = [0]; continue;
1966
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
1967
+ default:
1968
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
1969
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
1970
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
1971
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
1972
+ if (t[2]) _.ops.pop();
1973
+ _.trys.pop(); continue;
1974
+ }
1975
+ op = body.call(thisArg, _);
1976
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
1977
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
1978
+ }
1979
+ };
1944
1980
  var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
1945
1981
  return (mod && mod.__esModule) ? mod : { "default": mod };
1946
1982
  };
1947
1983
  Object.defineProperty(exports, "__esModule", { value: true });
1948
- exports.Types = void 0;
1984
+ exports.Types = exports.getUserFeedbackScriptUrl = void 0;
1949
1985
  var core_1 = src;
1950
1986
  var util_1 = util;
1951
1987
  var onerror_1 = onerror;
@@ -1955,23 +1991,32 @@
1955
1991
  var event_listeners_1 = __importDefault(event_listeners);
1956
1992
  var transport_1 = transport;
1957
1993
  var merge = core_1.Util.merge, filter = core_1.Util.filter, objectIsExtensible = core_1.Util.objectIsExtensible;
1994
+ var getProjectRoot = function () {
1995
+ var global = (0, util_1.globalThisOrWindow)();
1996
+ var projectRoot = '';
1997
+ // Cloudflare workers do not have access to location API.
1998
+ if (global.location != null) {
1999
+ projectRoot = global.location.protocol + '//' + global.location.host;
2000
+ }
2001
+ return projectRoot;
2002
+ };
2003
+ var getUserFeedbackScriptUrl = function (version) {
2004
+ var majorMinorVersion = version.split('.').slice(0, 2).join('.');
2005
+ return "https://js.honeybadger.io/v".concat(majorMinorVersion, "/honeybadger-feedback-form.js");
2006
+ };
2007
+ exports.getUserFeedbackScriptUrl = getUserFeedbackScriptUrl;
1958
2008
  var Honeybadger = /** @class */ (function (_super) {
1959
2009
  __extends(Honeybadger, _super);
1960
2010
  function Honeybadger(opts) {
1961
2011
  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;
2012
+ 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
2013
  /** @internal */
1971
2014
  _this.__errorsSent = 0;
1972
2015
  /** @internal */
1973
2016
  _this.__lastWrapErr = undefined;
1974
2017
  /** @internal */
2018
+ _this.__lastNoticeId = undefined;
2019
+ /** @internal */
1975
2020
  _this.__beforeNotifyHandlers = [
1976
2021
  function (notice) {
1977
2022
  if (_this.__exceedsMaxErrors()) {
@@ -1985,6 +2030,14 @@
1985
2030
  return true;
1986
2031
  }
1987
2032
  ];
2033
+ _this.__afterNotifyHandlers = [
2034
+ function (_error, notice) {
2035
+ if (notice) {
2036
+ _this.__lastNoticeId = notice.id;
2037
+ }
2038
+ return true;
2039
+ }
2040
+ ];
1988
2041
  return _this;
1989
2042
  }
1990
2043
  Honeybadger.prototype.configure = function (opts) {
@@ -2001,6 +2054,54 @@
2001
2054
  Honeybadger.prototype.checkIn = function (_id) {
2002
2055
  throw new Error('Honeybadger.checkIn() is not supported on the browser');
2003
2056
  };
2057
+ Honeybadger.prototype.showUserFeedbackForm = function (options) {
2058
+ if (options === void 0) { options = {}; }
2059
+ return __awaiter(this, void 0, void 0, function () {
2060
+ var global, script;
2061
+ return __generator(this, function (_a) {
2062
+ if (!this.config || !this.config.apiKey) {
2063
+ this.logger.debug('Client not initialized');
2064
+ return [2 /*return*/];
2065
+ }
2066
+ if (!this.__lastNoticeId) {
2067
+ this.logger.debug("Can't show user feedback form without a notice already reported");
2068
+ return [2 /*return*/];
2069
+ }
2070
+ global = (0, util_1.globalThisOrWindow)();
2071
+ if (typeof global.document === 'undefined') {
2072
+ this.logger.debug('global.document is undefined. Cannot attach script');
2073
+ return [2 /*return*/];
2074
+ }
2075
+ if (this.isUserFeedbackScriptUrlAlreadyVisible()) {
2076
+ this.logger.debug('User feedback form is already visible');
2077
+ return [2 /*return*/];
2078
+ }
2079
+ global['honeybadgerUserFeedbackOptions'] = __assign(__assign({}, options), { apiKey: this.config.apiKey, endpoint: this.config.userFeedbackEndpoint, noticeId: this.__lastNoticeId });
2080
+ script = global.document.createElement('script');
2081
+ script.setAttribute('src', this.getUserFeedbackSubmitUrl());
2082
+ script.setAttribute('async', 'true');
2083
+ if (options.onLoad) {
2084
+ script.onload = options.onLoad;
2085
+ }
2086
+ (global.document.head || global.document.body).appendChild(script);
2087
+ return [2 /*return*/];
2088
+ });
2089
+ });
2090
+ };
2091
+ Honeybadger.prototype.isUserFeedbackScriptUrlAlreadyVisible = function () {
2092
+ var global = (0, util_1.globalThisOrWindow)();
2093
+ var feedbackScriptUrl = this.getUserFeedbackSubmitUrl();
2094
+ for (var i = 0; i < global.document.scripts.length; i++) {
2095
+ var script = global.document.scripts[i];
2096
+ if (script.src === feedbackScriptUrl) {
2097
+ return true;
2098
+ }
2099
+ }
2100
+ return false;
2101
+ };
2102
+ Honeybadger.prototype.getUserFeedbackSubmitUrl = function () {
2103
+ return (0, exports.getUserFeedbackScriptUrl)(this.getVersion());
2104
+ };
2004
2105
  /** @internal */
2005
2106
  Honeybadger.prototype.__buildPayload = function (notice) {
2006
2107
  var cgiData = {