add a callstack to errors in browser, API, msg

This commit is contained in:
tophf 2021-12-16 16:20:05 +03:00
parent 9d2854c272
commit b132fecbcd
2 changed files with 33 additions and 16 deletions

View File

@ -78,12 +78,12 @@
send(data, target = 'extension') {
return browser.runtime.sendMessage({data, target})
.then(unwrapResponse);
.then(unwrapResponseFactory('send'));
},
sendTab(tabId, data, options, target = 'tab') {
return browser.tabs.sendMessage(tabId, {data, target}, options)
.then(unwrapResponse);
.then(unwrapResponseFactory('sendTab'));
},
_execute(types, ...args) {
@ -138,9 +138,15 @@
};
}
function unwrapResponse({data, error} = {error: {message: ERR_NO_RECEIVER}}) {
function unwrapResponseFactory(name) {
return unwrapResponse.bind(null, new Error(`Callstack before invoking msg.${name}:`));
}
function unwrapResponse(localErr, {data, error} = {error: {message: ERR_NO_RECEIVER}}) {
return error
? Promise.reject(Object.assign(new Error(error.message), error))
? Promise.reject(Object.assign(localErr, error, {
stack: `${error.stack}\n${localErr.stack}`,
}))
: data;
}
@ -154,18 +160,23 @@
const bg = getExtBg() ||
chrome.tabs && await browser.runtime.getBackgroundPage().catch(() => {});
const message = {method: 'invokeAPI', path, args};
let res;
// content scripts, probably private tabs, and our extension tab during Chrome startup
if (!bg) {
res = msg.send(message);
} else {
res = deepMerge(await bg.msg._execute(TARGETS.extension, message, {
return msg.send(message);
}
const err = new Error(`Callstack before invoking API.${path.join('.')}:`);
try {
return deepMerge(await bg.msg._execute(TARGETS.extension, message, {
frameId: 0, // false in case of our Options frame but we really want to fetch styles early
tab: NEEDS_TAB_IN_SENDER.includes(path.join('.')) && await getOwnTab(),
url: location.href,
}));
} catch (bgError) {
err.stack = `${bgError.stack}\n${err.stack}`;
err.message = bgError.message;
// Not using `throw` to avoid pausing debugger when it's configured to pause on exceptions
return Promise.reject(err);
}
return res;
},
};
/** @type {API} */

View File

@ -23,14 +23,20 @@
};
const promisify = function (fn, ...args) {
let res;
let resolve, reject;
const err = new Error();
try {
let resolve, reject;
/* Some callbacks have 2 parameters so we're resolving as an array in that case.
For example, chrome.runtime.requestUpdateCheck and chrome.webRequest.onAuthRequired */
args.push((...results) =>
chrome.runtime.lastError ?
reject(new Error(chrome.runtime.lastError.message)) :
resolve(results.length <= 1 ? results[0] : results));
args.push((...results) => {
const {lastError} = chrome.runtime;
if (lastError) {
err.message = lastError.message;
reject(err);
} else {
/* Some callbacks have 2 parameters so we're resolving as an array in that case.
For example, chrome.runtime.requestUpdateCheck and chrome.webRequest.onAuthRequired */
resolve(results.length <= 1 ? results[0] : results);
}
});
fn.apply(this, args);
res = new Promise((...rr) => ([resolve, reject] = rr));
} catch (err) {