As explained here, I've used function constructor in order to avoid evil method. Didn't find a better way to inject the context:
function evalContext(context: Record<string, unknown>) {
const injectContext = Object.keys(context).reduce(
(acc, key) => `${acc}${key}=context.${key};`,
'',
);
return Function(`context`, `${injectContext}${script}`)(context);
}
const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = useEventCallback((event) => {
if (event.code === 'KeyE' && event.metaKey) {
evalContext({ a: 3, b: 4, log: console.log });
event.preventDefault();
event.stopPropagation();
}
});
Still, it works (no need to prefix the keys with this). The main question is would it be possible to "hide" browser objects (window, document, location, ...). From the aspect of security, the script used in the function constructor will be visible only to the owner of the account. Hope this is safe.
As a side question, tried to use a few code editor libs: monaco-editor, react-simple-code-editor, @uiw/react-textarea-code-editor, @patternfly/react-code-editor... Haven't managed to run any of them (broken this, broken that in the next.js context). Please could you suggest any of them that works fine in the most recent version on NJS?
Update:
Based on @kelly's suggestion:
function evalContext(context: Record<string, unknown>) {
const injectContext = Object.keys(context).reduce(
(acc, key) => `${acc}${key}=context.${key};`,
'',
);
return Function(
'context',
'window',
'document',
'location',
'localStorage',
'navigation',
'fetch',
'frames',
'history',
`(function () {${injectContext}${script}}).call({})`,
)(context);
}

