import { nanoid } from 'nanoid/non-secure'; export default function (data) { let timeout; const instanceId = nanoid(); const scriptId = `script${data.id}`; const propertyName = `automa${data.id}`; const isScriptExists = document.querySelector(`#${scriptId}`); if (isScriptExists) { window.top.postMessage( { id: data.id, type: 'sandbox', result: { columns: {}, variables: {}, }, }, '*' ); return; } const preloadScripts = data.preloadScripts.map((item) => { const scriptEl = document.createElement('script'); scriptEl.textContent = item.script; (document.body || document.documentElement).appendChild(scriptEl); return scriptEl; }); if (!data.blockData.code.includes('automaNextBlock')) { data.blockData.code += `\n automaNextBlock()`; } const script = document.createElement('script'); script.id = scriptId; script.textContent = ` (() => { function automaRefData(keyword, path = '') { if (!keyword) return null; if (!path) return ${propertyName}.refData[keyword]; return window.$getNestedProperties(${propertyName}.refData, keyword + '.' + path); } function automaSetVariable(name, value) { const variables = ${propertyName}.refData.variables; if (!variables) ${propertyName}.refData.variables = {} ${propertyName}.refData.variables[name] = value; } function automaNextBlock(data = {}, insert = true) { ${propertyName}.nextBlock({ data, insert }); } function automaResetTimeout() { ${propertyName}.resetTimeout(); } function automaFetch(type, resource) { return ${propertyName}.fetch(type, resource); } try { ${data.blockData.code} } catch (error) { console.error(error); automaNextBlock({ $error: true, message: error.message }); } })(); `; function cleanUp() { script.remove(); preloadScripts.forEach((preloadScript) => { preloadScript.remove(); }); delete window[propertyName]; } window[propertyName] = { refData: data.refData, nextBlock: (result) => { cleanUp(); window.top.postMessage( { id: data.id, type: 'sandbox', result: { variables: data?.refData?.variables, columns: { data: result?.data, insert: result?.insert, }, }, }, '*' ); }, resetTimeout: () => { clearTimeout(timeout); timeout = setTimeout(cleanUp, data.blockData.timeout); }, fetch: (type, resource) => { return new Promise((resolve, reject) => { const types = ['json', 'text']; if (!type || !types.includes(type)) { reject(new Error('The "type" must be "text" or "json"')); return; } window.top.postMessage( { type: 'automa-fetch', data: { id: instanceId, type, resource }, }, '*' ); const eventName = `automa-fetch-response-${instanceId}`; const eventListener = ({ detail }) => { window.removeEventListener(eventName, eventListener); if (detail.isError) { reject(new Error(detail.result)); } else { resolve(detail.result); } }; window.addEventListener(eventName, eventListener); }); }, }; timeout = setTimeout(cleanUp, data.blockData.timeout); (document.body || document.documentElement).appendChild(script); }