Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/* globals startBackground, analytics, communication, catcher, log, browser, getStrings */
"use strict";
this.senderror = (function () {
const exports = {};
// Do not show an error more than every ERROR_TIME_LIMIT milliseconds:
const ERROR_TIME_LIMIT = 3000;
const messages = {
REQUEST_ERROR: {
titleKey: "screenshots-request-error-title",
infoKey: "screenshots-request-error-details",
},
CONNECTION_ERROR: {
titleKey: "screenshots-connection-error-title",
infoKey: "screenshots-connection-error-details",
},
LOGIN_ERROR: {
titleKey: "screenshots-request-error-title",
infoKey: "screenshots-login-error-details",
},
LOGIN_CONNECTION_ERROR: {
titleKey: "screenshots-connection-error-title",
infoKey: "screenshots-connection-error-details",
},
UNSHOOTABLE_PAGE: {
titleKey: "screenshots-unshootable-page-error-title",
infoKey: "screenshots-unshootable-page-error-details",
},
EMPTY_SELECTION: {
titleKey: "screenshots-empty-selection-error-title",
},
PRIVATE_WINDOW: {
titleKey: "screenshots-private-window-error-title",
infoKey: "screenshots-private-window-error-details",
},
generic: {
titleKey: "screenshots-generic-error-title",
infoKey: "screenshots-generic-error-details",
showMessage: true,
},
};
communication.register("reportError", (sender, error) => {
catcher.unhandled(error);
});
let lastErrorTime;
exports.showError = async function (error) {
if (lastErrorTime && Date.now() - lastErrorTime < ERROR_TIME_LIMIT) {
return;
}
lastErrorTime = Date.now();
const id = crypto.randomUUID();
let popupMessage = error.popupMessage || "generic";
if (!messages[popupMessage]) {
popupMessage = "generic";
}
let item = messages[popupMessage];
if (!("title" in item)) {
let keys = [{ id: item.titleKey }];
if ("infoKey" in item) {
keys.push({ id: item.infoKey });
}
[item.title, item.info] = await getStrings(keys);
}
let title = item.title;
let message = item.info || "";
const showMessage = item.showMessage;
if (error.message && showMessage) {
if (message) {
message += "\n" + error.message;
} else {
message = error.message;
}
}
if (Date.now() - startBackground.startTime > 5 * 1000) {
browser.notifications.create(id, {
type: "basic",
// FIXME: need iconUrl for an image, see #2239
title,
message,
});
}
};
exports.reportError = function (e) {
if (!analytics.isTelemetryEnabled()) {
log.error("Telemetry disabled. Not sending critical error:", e);
return;
}
const exception = new Error(e.message);
exception.stack = e.multilineStack || e.stack || undefined;
// To improve Sentry reporting & grouping, replace the
// moz-extension://$uuid base URL with a generic resource:// URL.
if (exception.stack) {
exception.stack = exception.stack.replace(
/moz-extension:\/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/g,
);
}
const rest = {};
for (const attr in e) {
if (
![
"name",
"message",
"stack",
"multilineStack",
"popupMessage",
"version",
"sentryPublicDSN",
"help",
"fromMakeError",
].includes(attr)
) {
rest[attr] = e[attr];
}
}
rest.stack = exception.stack;
};
catcher.registerHandler(errorObj => {
if (!errorObj.noPopup) {
exports.showError(errorObj);
}
if (!errorObj.noReport) {
exports.reportError(errorObj);
}
});
return exports;
})();