import type {EvalScriptIds} from '../evalScripts';
import {evalScripts} from '../evalScripts';
type ExceptionInfo = {
code: ?string,
description: ?string,
isError: boolean,
isException: boolean,
value: any,
};
const EVAL_TIMEOUT = 1000 * 10;
let evalRequestId = 0;
const evalRequestCallbacks = new Map<
number,
(value: {result: any, error: any}) => void,
>();
function fallbackEvalInInspectedWindow(
scriptId: EvalScriptIds,
args: any[],
callback: (value: any, exceptionInfo: ?ExceptionInfo) => void,
) {
if (!evalScripts[scriptId]) {
throw new Error(`No eval script with id "${scriptId}" exists.`);
}
const code = evalScripts[scriptId].code.apply(null, args);
const tabId = chrome.devtools.inspectedWindow.tabId;
const requestId = evalRequestId++;
chrome.runtime.sendMessage({
source: 'devtools-page',
payload: {
type: 'eval-in-inspected-window',
tabId,
requestId,
scriptId,
args,
},
});
const timeout = setTimeout(() => {
evalRequestCallbacks.delete(requestId);
if (callback) {
callback(null, {
code,
description:
'Timed out while waiting for eval response from the inspected window.',
isError: true,
isException: false,
value: undefined,
});
}
}, EVAL_TIMEOUT);
evalRequestCallbacks.set(requestId, ({result, error}) => {
clearTimeout(timeout);
evalRequestCallbacks.delete(requestId);
if (callback) {
if (error) {
callback(null, {
code,
description: undefined,
isError: false,
isException: true,
value: error,
});
return;
}
callback(result, null);
}
});
}
export function evalInInspectedWindow(
scriptId: EvalScriptIds,
args: any[],
callback: (value: any, exceptionInfo: ?ExceptionInfo) => void,
) {
if (!evalScripts[scriptId]) {
throw new Error(`No eval script with id "${scriptId}" exists.`);
}
const code = evalScripts[scriptId].code.apply(null, args);
chrome.devtools.inspectedWindow.eval(code, (result, exceptionInfo) => {
if (!exceptionInfo) {
callback(result, exceptionInfo);
return;
}
fallbackEvalInInspectedWindow(scriptId, args, callback);
});
}
chrome.runtime.onMessage.addListener(({payload, source}) => {
if (source === 'react-devtools-background') {
switch (payload?.type) {
case 'eval-in-inspected-window-response': {
const {requestId, result, error} = payload;
const callback = evalRequestCallbacks.get(requestId);
if (callback) {
callback({result, error});
}
break;
}
}
}
});