{"version":3,"file":"iframe.cjs","sourceRoot":"","sources":["../src/iframe.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,YAAY,CAAC,EACjC,GAAG,EACH,EAAE,EACF,OAAO,GAAG,IAAI,EACd,MAAM,GAAG,cAAc,GAMxB;IACC,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3C,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,uEAAuE;QACvE,yCAAyC;QACzC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9B,MAAM,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAE3C,IAAI,OAAO,EAAE,CAAC;YACZ,gGAAgG;YAChG,kEAAkE;YAClE,WAAW;YACX,qFAAqF;YACrF,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;QAClD,CAAC;QAED,uEAAuE;QACvE,yEAAyE;QACzE,uEAAuE;QACvE,wEAAwE;QACxE,uBAAuB;QACvB,EAAE;QACF,mEAAmE;QACnE,kCAAkC;QAClC,EAAE;QACF,mGAAmG;QACnG,iJAAiJ;QACjJ,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAElC,MAAM,CAAC,gBAAgB,CACrB,MAAM,EACN,GAAG,EAAE;YACH,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;gBACzB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,qEAAqE;gBACrE,mBAAmB;gBACnB,MAAM,CACJ,IAAI,KAAK,CACP,qDAAqD,EAAE,IAAI,CAC5D,CACF,CAAC;YACJ,CAAC;QACH,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AA1DD,oCA0DC","sourcesContent":["/**\n * Creates the iframe to be used as the execution environment. This may run\n * forever if the iframe never loads, but the promise should be wrapped in\n * an initialization timeout in the SnapController.\n *\n * @param options - The options for createWindow.\n * @param options.uri - The iframe URI.\n * @param options.id - The ID to assign to the iframe.\n * @param options.sandbox - Whether to enable the sandbox attribute.\n * @param options.testId - The data-testid attribute to assign to the iframe.\n * @returns A promise that resolves to the contentWindow of the iframe.\n */\nexport async function createWindow({\n  uri,\n  id,\n  sandbox = true,\n  testId = 'snaps-iframe',\n}: {\n  uri: string;\n  id: string;\n  sandbox?: boolean;\n  testId?: string;\n}): Promise<Window> {\n  return await new Promise((resolve, reject) => {\n    const iframe = document.createElement('iframe');\n    // The order of operations appears to matter for everything except this\n    // attribute. We may as well set it here.\n    iframe.setAttribute('id', id);\n    iframe.setAttribute('data-testid', testId);\n\n    if (sandbox) {\n      // For the sandbox property to have any effect it needs to be set before the iframe is appended.\n      // We apply this property as a principle of least authority (POLA)\n      // measure.\n      // Ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox\n      iframe.setAttribute('sandbox', 'allow-scripts');\n    }\n\n    // In the past, we've had problems that appear to be symptomatic of the\n    // iframe firing the `load` event before its scripts are actually loaded,\n    // which has prevented snaps from executing properly. Therefore, we set\n    // the `src` attribute and append the iframe to the DOM before attaching\n    // the `load` listener.\n    //\n    // `load` should only fire when \"all dependent resources\" have been\n    // loaded, which includes scripts.\n    //\n    // MDN article for `load` event: https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event\n    // Re: `load` firing twice: https://stackoverflow.com/questions/10781880/dynamically-created-iframe-triggers-onload-event-twice/15880489#15880489\n    iframe.setAttribute('src', uri);\n    document.body.appendChild(iframe);\n\n    iframe.addEventListener(\n      'load',\n      () => {\n        if (iframe.contentWindow) {\n          resolve(iframe.contentWindow);\n        } else {\n          // We don't know of a case when this would happen, but better to fail\n          // fast if it does.\n          reject(\n            new Error(\n              `iframe.contentWindow not present on load for job \"${id}\".`,\n            ),\n          );\n        }\n      },\n      { once: true },\n    );\n  });\n}\n"]}