diff --git a/src/ui/widgets/EmbeddedDisplay/scripts/scriptExecutor.ts b/src/ui/widgets/EmbeddedDisplay/scripts/scriptExecutor.ts index 74da7ca..6aea48b 100644 --- a/src/ui/widgets/EmbeddedDisplay/scripts/scriptExecutor.ts +++ b/src/ui/widgets/EmbeddedDisplay/scripts/scriptExecutor.ts @@ -2,6 +2,7 @@ import log from "loglevel"; import { v4 as uuidv4 } from "uuid"; let iFrameSandboxScriptRunner: HTMLIFrameElement | null = null; +let iFrameSandboxReady = false; export interface ScriptResponse { functionReturnValue: any; @@ -88,12 +89,14 @@ const buildSandboxIframe = async (): Promise => { iFrameSandboxScriptRunner.style.display = "none"; iFrameSandboxScriptRunner.id = "script-runner-iframe"; - // This adds an event listen to recieve the IFRAME_READY message, that is sent by the iFrame when it is ready to run scripts. + // This adds an event listen to receive the IFRAME_READY message, that is sent by the iFrame when it is ready to run scripts. const onMessage = (event: MessageEvent) => { - if (event.data === "IFRAME_READY") { - log.debug( - `The script runner iframe has started the following messeage was recievd: ${event.data}` - ); + if ( + event.data === "IFRAME_READY" && + event.source === iFrameSandboxScriptRunner?.contentWindow + ) { + log.debug("The script runner iframe has started"); + iFrameSandboxReady = true; window.removeEventListener("message", onMessage); resolve(iFrameSandboxScriptRunner as HTMLIFrameElement); } @@ -101,19 +104,14 @@ const buildSandboxIframe = async (): Promise => { window.addEventListener("message", onMessage); - iFrameSandboxScriptRunner.onload = () => { - if (!iFrameSandboxScriptRunner) { - return; - } - iFrameSandboxScriptRunner.srcdoc = iFrameScriptExecutionHandlerCode; - }; - - document.body.appendChild(iFrameSandboxScriptRunner); - setTimeout(() => { window.removeEventListener("message", onMessage); reject(new Error("The creation of a script execution iframe timed out")); }, 1000); + + iFrameSandboxScriptRunner.srcdoc = iFrameScriptExecutionHandlerCode; + + document.body.appendChild(iFrameSandboxScriptRunner); }); }; @@ -133,6 +131,18 @@ export const executeDynamicScriptInSandbox = async ( await buildSandboxIframe(); } + if (!iFrameSandboxReady) { + // The iFrame sandbox is still starting up, this can happen on app startup. + // We don't want to block, so log and return an empty response. + log.warn( + "The Iframe sandbox is starting up, dynamic script execution skipped on this occasion." + ); + return { + functionReturnValue: "", + widgetProps: {} + }; + } + if (!iFrameSandboxScriptRunner?.contentWindow) { throw new Error("Iframe content window not available"); } @@ -140,7 +150,7 @@ export const executeDynamicScriptInSandbox = async ( return new Promise((resolve, reject) => { const id = uuidv4(); - // Define a message handler to recieve the responses from the IFrame. + // Define a message handler to receive the responses from the IFrame. const messageHandler = (event: MessageEvent) => { if ( event.data?.id === id && @@ -149,7 +159,7 @@ export const executeDynamicScriptInSandbox = async ( ) { window.removeEventListener("message", messageHandler); if (!event.data?.error) { - // Sucess return the response data. + // Success return the response data. resolve({ functionReturnValue: event.data?.functionReturnValue, widgetProps: event.data?.widgetProps