@myop/sdk 0.3.32 → 0.3.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/bundled-declarations.d.ts +199 -50
  2. package/dist/cjs/_IframeSDK.c2225e19.min.js +1 -0
  3. package/dist/cjs/{_IframeSDK.8ce25264.js → _IframeSDK.c7926c56.js} +262 -48
  4. package/dist/cjs/_IframeSDK.c7926c56.js.map +7 -0
  5. package/dist/cjs/{_MyopHelpers.95610381.js → _MyopHelpers.08d1cf5d.js} +68 -20
  6. package/dist/cjs/_MyopHelpers.08d1cf5d.js.map +7 -0
  7. package/dist/cjs/_MyopHelpers.59521d8f.min.js +1 -0
  8. package/dist/cjs/_WebComponentSDK.0caec562.min.js +1 -0
  9. package/dist/cjs/{_WebComponentSDK.1aa213d9.js → _WebComponentSDK.501a71f9.js} +262 -48
  10. package/dist/cjs/_WebComponentSDK.501a71f9.js.map +7 -0
  11. package/dist/cjs/_hostSDK.02edf3e2.min.js +1 -0
  12. package/dist/cjs/{_hostSDK.c7ca0fae.js → _hostSDK.cdbc1f60.js} +262 -48
  13. package/dist/cjs/_hostSDK.cdbc1f60.js.map +7 -0
  14. package/dist/cjs/myop_sdk.js +14 -14
  15. package/dist/cjs/myop_sdk.js.map +1 -1
  16. package/dist/cjs/myop_sdk.min.js +1 -1
  17. package/dist/cjs-bundled/myop_sdk.bundled.js +272 -50
  18. package/dist/cjs-bundled/myop_sdk.bundled.js.map +3 -3
  19. package/dist/cjs-bundled/myop_sdk.bundled.min.js +1 -1
  20. package/dist/module/Iframe/index.js +322 -49
  21. package/dist/module/Iframe/index.js.map +2 -2
  22. package/dist/module/SDK.js +331 -50
  23. package/dist/module/SDK.js.map +3 -3
  24. package/dist/module/common/index.d.ts +26 -0
  25. package/dist/module/common/index.js +1 -1
  26. package/dist/module/common/index.js.map +2 -2
  27. package/dist/module/embeddedSDK.js +1 -1
  28. package/dist/module/helpers/CloudRepository.d.ts +43 -0
  29. package/dist/module/helpers/cloudRepositoryHelpers.d.ts +21 -2
  30. package/dist/module/helpers/index.js +70 -21
  31. package/dist/module/helpers/index.js.map +2 -2
  32. package/dist/module/host/components/myopExtractedWebComponent.d.ts +1 -0
  33. package/dist/module/host/components/myopIframeComponent.d.ts +17 -0
  34. package/dist/module/host/embeddedSDK.js +1 -1
  35. package/dist/module/host/hostSDK.d.ts +15 -0
  36. package/dist/module/host/index.d.ts +1 -1
  37. package/dist/module/host/index.js +322 -49
  38. package/dist/module/host/index.js.map +2 -2
  39. package/dist/module/host/loaders/HTMLComponentLoader.d.ts +29 -1
  40. package/dist/module/webcomponent/index.js +322 -49
  41. package/dist/module/webcomponent/index.js.map +2 -2
  42. package/package.json +1 -1
  43. package/dist/cjs/_IframeSDK.07df88d3.min.js +0 -1
  44. package/dist/cjs/_IframeSDK.8ce25264.js.map +0 -7
  45. package/dist/cjs/_MyopHelpers.172384f4.min.js +0 -1
  46. package/dist/cjs/_MyopHelpers.95610381.js.map +0 -7
  47. package/dist/cjs/_WebComponentSDK.1aa213d9.js.map +0 -7
  48. package/dist/cjs/_WebComponentSDK.92468fac.min.js +0 -1
  49. package/dist/cjs/_hostSDK.c7ca0fae.js.map +0 -7
  50. package/dist/cjs/_hostSDK.dc198afa.min.js +0 -1
@@ -1023,6 +1023,19 @@ var MyopExtractedWebComponent = class extends BaseMyopComponent {
1023
1023
  __publicField(this, "ctaCleanup");
1024
1024
  __publicField(this, "_ctaHandler");
1025
1025
  __publicField(this, "_ctaQueue", []);
1026
+ // A single 'myop-cta' listener, attached at construction so CTAs a component
1027
+ // dispatches during its first initWithData() render — before the host attaches
1028
+ // a handler — are buffered (and flushed on setCtaHandler), matching the iframe
1029
+ // path's pre-handler CTA queue.
1030
+ __publicField(this, "_ctaListener", (e) => {
1031
+ const detail = e.detail;
1032
+ if (!(detail == null ? void 0 : detail.action)) return;
1033
+ if (this._ctaHandler && !this.markedForDisposed) {
1034
+ this._ctaHandler(detail.action, detail.payload);
1035
+ } else if (!this._ctaHandler) {
1036
+ this._ctaQueue.push({ action: detail.action, payload: detail.payload });
1037
+ }
1038
+ });
1026
1039
  __publicField(this, "cleanupInspect", () => {
1027
1040
  });
1028
1041
  /**
@@ -1043,6 +1056,8 @@ var MyopExtractedWebComponent = class extends BaseMyopComponent {
1043
1056
  (_a = this.customElement.parentNode) == null ? void 0 : _a.removeChild(this.customElement);
1044
1057
  });
1045
1058
  this.element = customElement;
1059
+ this.customElement.addEventListener("myop-cta", this._ctaListener);
1060
+ this.ctaCleanup = () => this.customElement.removeEventListener("myop-cta", this._ctaListener);
1046
1061
  this.setInitiated();
1047
1062
  }
1048
1063
  inspect() {
@@ -1087,9 +1102,6 @@ var MyopExtractedWebComponent = class extends BaseMyopComponent {
1087
1102
  * Called via props.myop_cta_handler = handler
1088
1103
  */
1089
1104
  setCtaHandler(handler) {
1090
- if (this.ctaCleanup) {
1091
- this.ctaCleanup();
1092
- }
1093
1105
  this._ctaHandler = handler;
1094
1106
  if (this._ctaQueue.length > 0) {
1095
1107
  const queue = [...this._ctaQueue];
@@ -1100,24 +1112,6 @@ var MyopExtractedWebComponent = class extends BaseMyopComponent {
1100
1112
  }
1101
1113
  });
1102
1114
  }
1103
- const listener = (e) => {
1104
- var _a;
1105
- const customEvent = e;
1106
- if ((_a = customEvent.detail) == null ? void 0 : _a.action) {
1107
- if (this._ctaHandler && !this.markedForDisposed) {
1108
- this._ctaHandler(customEvent.detail.action, customEvent.detail.payload);
1109
- } else if (!this._ctaHandler) {
1110
- this._ctaQueue.push({
1111
- action: customEvent.detail.action,
1112
- payload: customEvent.detail.payload
1113
- });
1114
- }
1115
- }
1116
- };
1117
- this.customElement.addEventListener("myop-cta", listener);
1118
- this.ctaCleanup = () => {
1119
- this.customElement.removeEventListener("myop-cta", listener);
1120
- };
1121
1115
  }
1122
1116
  };
1123
1117
 
@@ -1186,6 +1180,17 @@ var connectProps = (component, propsConfig, selectedSkin) => {
1186
1180
  }
1187
1181
  return void 0;
1188
1182
  }
1183
+ if (component instanceof MyopIframeComponent && component.isolated) {
1184
+ const typedPropBehavior = propConfig.behavior;
1185
+ const propName = typedPropBehavior.remap || prop;
1186
+ if (propName === "myop_init_interface") {
1187
+ return (data) => {
1188
+ if (data === void 0) return component.getData();
1189
+ component.initWithData(data);
1190
+ };
1191
+ }
1192
+ return void 0;
1193
+ }
1189
1194
  if (selectedSkin.loader.type === SkinLoaders.HTMLLoader) {
1190
1195
  const typedLoader = selectedSkin.loader;
1191
1196
  if (typedLoader.shadowRootMode === ShadowRootModeType.localFrame) {
@@ -1232,6 +1237,18 @@ var connectProps = (component, propsConfig, selectedSkin) => {
1232
1237
  return true;
1233
1238
  }
1234
1239
  }
1240
+ if (component instanceof MyopIframeComponent && component.isolated) {
1241
+ const typedPropBehavior = propConfig.behavior;
1242
+ const propName = typedPropBehavior.remap || prop;
1243
+ if (propName === "myop_cta_handler") {
1244
+ component.setCtaHandler(value);
1245
+ return true;
1246
+ }
1247
+ if (propName === "myop_init_interface") {
1248
+ component.initWithData(value);
1249
+ return true;
1250
+ }
1251
+ }
1235
1252
  if (selectedSkin.loader.type === SkinLoaders.HTMLLoader) {
1236
1253
  const typedLoader = selectedSkin.loader;
1237
1254
  if (typedLoader.shadowRootMode === ShadowRootModeType.localFrame) {
@@ -1437,6 +1454,7 @@ var connectRefs = async (component, componentConfig, components, withoutRefCompo
1437
1454
 
1438
1455
  // src/host/components/myopIframeComponent.ts
1439
1456
  var MyopIframeComponent = class extends BaseMyopComponent {
1457
+ // last reported size (for the enable race)
1440
1458
  constructor(componentConfig, skin, container, IframeElement, options) {
1441
1459
  super(componentConfig, container, options);
1442
1460
  this.componentConfig = componentConfig;
@@ -1445,6 +1463,17 @@ var MyopIframeComponent = class extends BaseMyopComponent {
1445
1463
  __publicField(this, "_autoSizeCleanup");
1446
1464
  __publicField(this, "_autoSizeOptions");
1447
1465
  __publicField(this, "_autoSizeUpdate");
1466
+ // ── Isolation (sandboxed cross-origin frame) — postMessage bridge, host side ──
1467
+ __publicField(this, "isolated", false);
1468
+ __publicField(this, "_lastData");
1469
+ // cached last-sent data (sync getData)
1470
+ __publicField(this, "_ctaHandler");
1471
+ __publicField(this, "_ctaQueue", []);
1472
+ __publicField(this, "_isoMsgHandler");
1473
+ __publicField(this, "_isoSizeOpts");
1474
+ __publicField(this, "_isoAutoSize", false);
1475
+ // bridge sizing only when auto-size is on
1476
+ __publicField(this, "_isoLastSize");
1448
1477
  __publicField(this, "sizeMeta");
1449
1478
  __publicField(this, "cleanupInspect");
1450
1479
  __publicField(this, "setHeightBasedOnDocumentElement", () => {
@@ -1484,6 +1513,15 @@ var MyopIframeComponent = class extends BaseMyopComponent {
1484
1513
  */
1485
1514
  __publicField(this, "observeAutoSize", (options) => {
1486
1515
  this._autoSizeOptions = options;
1516
+ if (this.isolated) {
1517
+ this._isoSizeOpts = options;
1518
+ this._isoAutoSize = true;
1519
+ if (this._isoLastSize) this._applyIsoSize(this._isoLastSize.height, this._isoLastSize.width);
1520
+ return () => {
1521
+ this._isoAutoSize = false;
1522
+ this._isoSizeOpts = void 0;
1523
+ };
1524
+ }
1487
1525
  if (this._autoSizeCleanup && this._autoSizeUpdate) {
1488
1526
  this._autoSizeUpdate();
1489
1527
  return this._autoSizeCleanup;
@@ -1686,12 +1724,73 @@ var MyopIframeComponent = class extends BaseMyopComponent {
1686
1724
  this._autoSizeCleanup();
1687
1725
  this._autoSizeCleanup = void 0;
1688
1726
  }
1727
+ if (this._isoMsgHandler) {
1728
+ window.removeEventListener("message", this._isoMsgHandler);
1729
+ this._isoMsgHandler = void 0;
1730
+ }
1689
1731
  if (this.cleanupInspect)
1690
1732
  this.cleanupInspect();
1691
1733
  super.dispose();
1692
1734
  this.IframeElement.parentNode.removeChild(this.IframeElement);
1693
1735
  });
1694
1736
  this.element = this.IframeElement;
1737
+ this._lastData = options == null ? void 0 : options.data;
1738
+ }
1739
+ // ── Isolation bridge (host side) ─────────────────────────────────────────
1740
+ /** Attach the host-side postMessage listener for a sandboxed frame. */
1741
+ enableIsolation() {
1742
+ this.isolated = true;
1743
+ this.setInitiated();
1744
+ this._isoMsgHandler = (e) => {
1745
+ if (e.source !== this.IframeElement.contentWindow) return;
1746
+ const d = e.data;
1747
+ if (!d || d.__myop !== true) return;
1748
+ if (d.type === "myop:cta") {
1749
+ if (this._ctaHandler && !this.markedForDisposed) this._ctaHandler(d.action, d.payload);
1750
+ else if (!this._ctaHandler) this._ctaQueue.push({ action: d.action, payload: d.payload });
1751
+ } else if (d.type === "myop:size") {
1752
+ this._applyIsoSize(d.height, d.width);
1753
+ }
1754
+ };
1755
+ window.addEventListener("message", this._isoMsgHandler);
1756
+ }
1757
+ /** Data-in — unified with the extracted-WC API. Posts init over the bridge. */
1758
+ initWithData(data) {
1759
+ var _a, _b;
1760
+ this._lastData = data;
1761
+ (_b = (_a = this.IframeElement) == null ? void 0 : _a.contentWindow) == null ? void 0 : _b.postMessage({ __myop: true, type: "myop:init", data }, "*");
1762
+ }
1763
+ /** Data-in getter — returns the last data the host sent (cached, synchronous). */
1764
+ getData() {
1765
+ return this._lastData;
1766
+ }
1767
+ /** Data-out — unified with the extracted-WC API. Flushes CTAs queued pre-handler. */
1768
+ setCtaHandler(handler) {
1769
+ this._ctaHandler = handler;
1770
+ if (this._ctaQueue.length > 0) {
1771
+ const queue = [...this._ctaQueue];
1772
+ this._ctaQueue = [];
1773
+ queue.forEach((item) => {
1774
+ if (!this.markedForDisposed) handler(item.action, item.payload);
1775
+ });
1776
+ }
1777
+ }
1778
+ _applyIsoSize(height, width) {
1779
+ var _a;
1780
+ if (!height || Number.isNaN(height)) return;
1781
+ this._isoLastSize = { height, width };
1782
+ if (!this._isoAutoSize) return;
1783
+ const opts = this._isoSizeOpts;
1784
+ const toNum = (v) => v === void 0 ? void 0 : typeof v === "number" ? v : isNaN(parseFloat(v)) ? void 0 : parseFloat(v);
1785
+ const min = toNum(opts == null ? void 0 : opts.minHeight), max = toNum(opts == null ? void 0 : opts.maxHeight);
1786
+ let h = height;
1787
+ if (min !== void 0 && h < min) h = min;
1788
+ if (max !== void 0 && h > max) h = max;
1789
+ this.IframeElement.style.position = "relative";
1790
+ this.IframeElement.style.inset = "auto";
1791
+ this.IframeElement.style.height = h + "px";
1792
+ this.IframeElement.style.width = "100%";
1793
+ (_a = opts == null ? void 0 : opts.onSizeChange) == null ? void 0 : _a.call(opts, { width: width != null ? width : this.IframeElement.clientWidth, height: h, autoSizingWidth: false, autoSizingHeight: true });
1695
1794
  }
1696
1795
  inspect() {
1697
1796
  if (this.cleanupInspect) {
@@ -1900,7 +1999,7 @@ var WebcomponentLoader = class extends BaseMyopLoader {
1900
1999
  };
1901
2000
 
1902
2001
  // version:myop-sdk-version
1903
- var myop_sdk_version_default = "0.3.32";
2002
+ var myop_sdk_version_default = "0.3.34";
1904
2003
 
1905
2004
  // src/webcomponent/messageHandlers/BaseWebComponentMessageHandler.ts
1906
2005
  var BaseWebComponentMessageHandler = class extends BaseContextMessageHandler {
@@ -2293,7 +2392,15 @@ var HTMLComponentLoader = class extends BaseMyopLoader {
2293
2392
  __publicField(this, "type", SkinLoaders.HTMLLoader);
2294
2393
  __publicField(this, "load", async (componentDefinition, skin, container, options) => {
2295
2394
  const loaderConfig = skin.loader;
2296
- if (this.isMyopWebComponent(loaderConfig.HTML)) {
2395
+ const isWC = this.isMyopWebComponent(loaderConfig.HTML);
2396
+ const { mode, isolate } = await this.resolveRenderMode(componentDefinition, skin, loaderConfig, isWC, options);
2397
+ if (mode === false) {
2398
+ throw new Error('[Myop] Rendering blocked by render policy for component "'.concat(componentDefinition.id, '"'));
2399
+ }
2400
+ if (isWC) {
2401
+ if (mode !== "webComponent") {
2402
+ throw new Error('[Myop] Web-component rendering denied by render policy for component "'.concat(componentDefinition.id, '"'));
2403
+ }
2297
2404
  return this.loadExtractedWebComponent(componentDefinition, skin, container, loaderConfig.HTML, options);
2298
2405
  }
2299
2406
  let domId = "myop-comp-".concat(uuidv4());
@@ -2303,12 +2410,28 @@ var HTMLComponentLoader = class extends BaseMyopLoader {
2303
2410
  const domId2 = "myop-comp-".concat(uniqId);
2304
2411
  let IframeElement = document.createElement("iframe");
2305
2412
  IframeElement.id = domId2;
2413
+ if (isolate) {
2414
+ IframeElement.setAttribute("sandbox", "allow-scripts allow-forms allow-popups");
2415
+ }
2306
2416
  IframeElement.style.cssText = "\n display: block;\n padding: 0;\n margin: 0;\n position: absolute;\n inset: 0;\n overflow: hidden;\n border: none;\n opacity: ".concat((options == null ? void 0 : options.hidden) ? "0" : "1", ";\n width: 100%;\n height: 100%;\n pointer-events: ").concat((options == null ? void 0 : options.hidden) ? "none" : "all", ";\n ");
2307
2417
  if (!container.querySelector('[id^="myop-comp-"]'))
2308
2418
  container.innerHTML = "";
2309
2419
  IframeElement = this.appendChild(container, IframeElement, options);
2310
- const doc = IframeElement.contentDocument || IframeElement.contentWindow.document;
2311
- doc.open();
2420
+ const __srcParts = [];
2421
+ const doc = isolate ? {
2422
+ open() {
2423
+ },
2424
+ writeln(s) {
2425
+ __srcParts.push(s);
2426
+ },
2427
+ close() {
2428
+ IframeElement.srcdoc = __srcParts.join("\n");
2429
+ }
2430
+ } : (() => {
2431
+ const d = IframeElement.contentDocument || IframeElement.contentWindow.document;
2432
+ d.open();
2433
+ return d;
2434
+ })();
2312
2435
  let parsedSizeMeta = null;
2313
2436
  {
2314
2437
  const _preParser = new DOMParser();
@@ -2348,22 +2471,29 @@ var HTMLComponentLoader = class extends BaseMyopLoader {
2348
2471
  const _doc = parser.parseFromString(HTML2Render, "text/html");
2349
2472
  const styleTag = _doc.createElement("style");
2350
2473
  styleTag.setAttribute("data-myop-injected", "true");
2351
- styleTag.textContent = options.injectCss;
2474
+ styleTag.textContent = options.injectCss.replace(/<\s*\/\s*style/gi, "<\\/style");
2352
2475
  (_doc.head || _doc.documentElement).appendChild(styleTag);
2353
2476
  HTML2Render = "<!DOCTYPE html>" + _doc.documentElement.outerHTML;
2354
2477
  }
2355
2478
  doc.writeln(HTML2Render);
2356
2479
  const sdkScript = HAS_EMBEDDED_SDK ? "<script>".concat(EMBEDDED_SDK_CONTENT, "<\/script>") : '<script src="'.concat(window.myop.__ROOT_SDK_PUBLIC_URL__, '"><\/script>');
2357
2480
  const initScript = HAS_EMBEDDED_SDK ? "<script>\n const __myop_init = async () => {\n const iframeModule = await MyopSDK.getIframeModule();\n const IframeSDK = iframeModule.IframeSDK;\n const sdk = new IframeSDK();\n sdk.init();\n }\n __myop_init().then();\n <\/script>" : "<script>\n window.__federation__.__public_path__ = window.__federation__.__public_path__;\n const __myop_init = async () => {\n const {IframeSDK} = (await window.myop.rootSDK.getIframeModule());\n const sdk = new IframeSDK();\n sdk.init();\n }\n __myop_init().then();\n <\/script>";
2358
- doc.writeln("".concat(sdkScript).concat(initScript));
2359
- if ((options == null ? void 0 : options.data) !== void 0) {
2481
+ if (!isolate) {
2482
+ doc.writeln("".concat(sdkScript).concat(initScript));
2483
+ }
2484
+ if (!isolate && (options == null ? void 0 : options.data) !== void 0) {
2360
2485
  const ctaQueueScript = "<script>\n window.__myop_cta_queue = [];\n window.myop_cta_handler = function(action, payload) {\n window.__myop_cta_queue.push({action: action, payload: payload});\n };\n <\/script>";
2361
2486
  const escapedData = JSON.stringify(options.data).replace(/<\/script/gi, "\\u003c/script");
2362
2487
  const dataScript = '<script id="__myop_init_data_script">\n (function() {\n var data = '.concat(escapedData, ";\n var scriptEl = document.getElementById('__myop_init_data_script');\n\n var callInitInterface = function(fn) {\n var startTime = performance.now();\n // Mark as pre-injected data call for extension tracking\n window.__myop_init_preinjected = true;\n try {\n fn(data);\n } finally {\n window.__myop_init_preinjected = false;\n }\n var duration = performance.now() - startTime;\n\n // Notify extension via postMessage (init* = pre-injected)\n try {\n window.parent.postMessage({\n type: 'MYOP_PREINJECTED_INIT',\n payload: {\n data: data,\n duration: duration,\n timestamp: Date.now()\n }\n }, '*');\n } catch (e) {}\n\n // Cleanup: remove script tag and stored data\n if (scriptEl && scriptEl.parentNode) {\n scriptEl.parentNode.removeChild(scriptEl);\n }\n delete window.__myop_init_data;\n };\n\n if (typeof window.myop_init_interface === 'function') {\n // Function already exists - call immediately\n callInitInterface(window.myop_init_interface);\n } else {\n // Function not yet defined - store data and watch for definition\n window.__myop_init_data = data;\n\n var _original;\n Object.defineProperty(window, 'myop_init_interface', {\n configurable: true,\n enumerable: true,\n set: function(fn) {\n _original = fn;\n if (window.__myop_init_data !== undefined) {\n var storedData = window.__myop_init_data;\n delete window.__myop_init_data;\n callInitInterface(fn);\n }\n },\n get: function() {\n return _original;\n }\n });\n }\n })();\n <\/script>");
2363
2488
  doc.writeln(ctaQueueScript + dataScript);
2364
2489
  }
2490
+ if (isolate) {
2491
+ const escapedData = (options == null ? void 0 : options.data) !== void 0 ? JSON.stringify(options.data).replace(/<\/script/gi, "\\u003c/script") : "undefined";
2492
+ doc.writeln(this.buildIsolationBridge(escapedData));
2493
+ }
2365
2494
  doc.close();
2366
2495
  const comp = new MyopIframeComponent(componentDefinition, skin, container, IframeElement, options);
2496
+ if (isolate) comp.enableIsolation();
2367
2497
  comp.sizeMeta = parsedSizeMeta;
2368
2498
  comp.initiated().then(() => {
2369
2499
  if ((options == null ? void 0 : options.autoSize) === false) {
@@ -2418,6 +2548,42 @@ var HTMLComponentLoader = class extends BaseMyopLoader {
2418
2548
  isMyopWebComponent(html) {
2419
2549
  return html.trimStart().startsWith(MYOP_WEB_COMPONENT_MARKER);
2420
2550
  }
2551
+ /**
2552
+ * Resolve how this component should render, applying the host render policy.
2553
+ * Precedence: options.renderPolicy (per-call) fully replaces the global
2554
+ * hostSDK.setRenderPolicy — so an app can restrict globally and allow specifics.
2555
+ * With no policy set, behavior is unchanged from before (marker ⇒ web component).
2556
+ */
2557
+ async resolveRenderMode(componentDefinition, skin, loaderConfig, isWebComponent, options) {
2558
+ var _a, _b, _c, _d;
2559
+ const requestedMode = isWebComponent ? "webComponent" : loaderConfig.isolation || (options == null ? void 0 : options.isolation) ? "isolatedIframe" : "iframe";
2560
+ const policy = (_d = options == null ? void 0 : options.renderPolicy) != null ? _d : (_c = (_b = (_a = window == null ? void 0 : window.myop) == null ? void 0 : _a.hostSDK) == null ? void 0 : _b.getRenderPolicy) == null ? void 0 : _c.call(_b);
2561
+ const mode = policy ? await policy({ componentDefinition, skin, requestedMode, isWebComponent }) : requestedMode;
2562
+ return { mode, isolate: mode === "isolatedIframe" };
2563
+ }
2564
+ /**
2565
+ * The in-frame bridge for isolated components. Runs inside the sandboxed
2566
+ * (opaque-origin) iframe, translating the same author-facing contract to/from
2567
+ * postMessage since the host has no same-origin access:
2568
+ * • data-in : parent posts {type:'myop:init'} → calls window.myop_init_interface
2569
+ * (plus a baked initial value for the first render)
2570
+ * • data-out: window.myop_cta_handler → parent.postMessage({type:'myop:cta'})
2571
+ * • resize : ResizeObserver → parent.postMessage({type:'myop:size'})
2572
+ *
2573
+ * TODO(dev-extension): the isolated path deliberately skips the same-origin
2574
+ * dataScript, so it never posts the `MYOP_PREINJECTED_INIT` message the Myop dev
2575
+ * extension listens for to log the INITIAL render (`init*`). Later init updates and
2576
+ * all CTAs are still tracked (the extension wraps `comp.props`, which our isolated
2577
+ * connectProps branch routes through), so only the first-render payload is missing
2578
+ * from the extension's activity log for isolated components. Closing this would be a
2579
+ * ~1-line `parent.postMessage({type:'MYOP_PREINJECTED_INIT', payload:{data}})` inside
2580
+ * flushInitial() below — intentionally NOT done for now to avoid adding extension-only
2581
+ * traffic to the component runtime. Web components have the same initial-init gap
2582
+ * (initWithData is called on the element, not via comp.props) and it predates this.
2583
+ */
2584
+ buildIsolationBridge(initialDataLiteral) {
2585
+ return "<script>\n (function () {\n var __initial = ".concat(initialDataLiteral, ";\n var __pending;\n // data-out (cta)\n window.myop_cta_handler = function (action, payload) {\n try { parent.postMessage({ __myop: true, type: 'myop:cta', action: action, payload: payload }, '*'); } catch (e) {}\n };\n function callInit(data) {\n if (typeof window.myop_init_interface === 'function') { window.myop_init_interface(data); return true; }\n return false;\n }\n // data-in (init updates)\n window.addEventListener('message', function (e) {\n var d = e.data;\n if (!d || d.__myop !== true) return;\n if (d.type === 'myop:init') { if (!callInit(d.data)) __pending = d.data; }\n });\n // first render: use a pending update if one arrived, else the baked initial data\n (function flushInitial() {\n var data = (__pending !== undefined) ? __pending : __initial;\n if (data === undefined) return;\n if (callInit(data)) { __pending = undefined; __initial = undefined; }\n else requestAnimationFrame(flushInitial);\n })();\n // resize (report content size)\n function contentHeight() {\n // Measure the BODY (content box). documentElement.scrollHeight includes\n // the iframe viewport \u2014 which we're driving \u2014 so it would report the\n // current frame height, not the content, and never shrink.\n var b = document.body;\n if (b) return Math.max(b.scrollHeight, b.offsetHeight);\n return document.documentElement.scrollHeight;\n }\n function postSize() {\n try {\n parent.postMessage({\n __myop: true, type: 'myop:size',\n height: contentHeight(),\n width: document.documentElement.scrollWidth\n }, '*');\n } catch (e) {}\n }\n // Observe the BODY (reflows with content) \u2014 not documentElement, whose box is\n // the iframe viewport and would feed back into a resize loop. A MutationObserver\n // catches content swaps (e.g. innerHTML re-render) that don't change body's box.\n if (window.ResizeObserver) {\n try { var __ro = new ResizeObserver(postSize); if (document.body) __ro.observe(document.body); } catch (e) {}\n }\n if (window.MutationObserver && document.body) {\n try { new MutationObserver(postSize).observe(document.body, { childList: true, subtree: true, attributes: true, characterData: true }); } catch (e) {}\n }\n window.addEventListener('load', postSize);\n postSize();\n })();\n <\/script>");
2586
+ }
2421
2587
  /**
2422
2588
  * Extract the web component script content from HTML
2423
2589
  */
@@ -2635,24 +2801,33 @@ var _CloudRepository = class _CloudRepository {
2635
2801
  getPreloadedParams(componentId) {
2636
2802
  return this.preloadedComponents[componentId];
2637
2803
  }
2804
+ /**
2805
+ * Resolve a component config: fetch it once, then serve it from this
2806
+ * repository's cache.
2807
+ *
2808
+ * This is the name to use. `fetchComponentV2` is the same method under its
2809
+ * versioned name and stays for backward compatibility — note that the
2810
+ * unversioned `fetchComponent` is a *deprecated v1* API and is NOT this.
2811
+ *
2812
+ * Completes the trio with {@link getResolvedConfig} (synchronous read of an
2813
+ * already-resolved config) and {@link hydrateComponent} (seed one you
2814
+ * already hold).
2815
+ *
2816
+ * Prefer the module-level `preloadComponents([id])` in app code; reach for
2817
+ * this when you need an isolated repository instance whose cache lifetime
2818
+ * you control — a server with its own TTL, for example.
2819
+ */
2820
+ async resolveComponent(componentId, env, preview) {
2821
+ return this.fetchComponentV2(componentId, env, preview);
2822
+ }
2638
2823
  /**
2639
2824
  * Fetch a v2 component config
2640
2825
  * If env/preview not specified and component was preloaded, uses preloaded params
2826
+ *
2827
+ * @see resolveComponent — the unversioned name for this method
2641
2828
  */
2642
2829
  async fetchComponentV2(componentId, environmentIdentifier, preview) {
2643
- const preloaded = this.preloadedComponents[componentId];
2644
- const hasExplicitParams = environmentIdentifier !== void 0 || preview !== void 0;
2645
- let env;
2646
- let usePreview;
2647
- if (!hasExplicitParams && preloaded) {
2648
- env = preloaded.env;
2649
- usePreview = preloaded.preview;
2650
- } else {
2651
- env = environmentIdentifier || this._defaultEnv;
2652
- const hasEffectiveEnv = environmentIdentifier || this._envExplicitlySet;
2653
- usePreview = preview === true ? true : preview === false ? false : !hasEffectiveEnv;
2654
- }
2655
- const cacheKey = "".concat(componentId, ":").concat(env, ":").concat(usePreview ? "preview" : "live");
2830
+ const { env, usePreview, cacheKey } = this.resolveParams(componentId, environmentIdentifier, preview);
2656
2831
  console.log("[CloudRepository] fetchComponentV2", {
2657
2832
  componentId: componentId.slice(0, 8) + "...",
2658
2833
  env,
@@ -2721,20 +2896,52 @@ var _CloudRepository = class _CloudRepository {
2721
2896
  */
2722
2897
  getResolvedConfig(componentId, env, preview) {
2723
2898
  var _a;
2899
+ const { cacheKey } = this.resolveParams(componentId, env, preview);
2900
+ return ((_a = this.variants[cacheKey]) == null ? void 0 : _a.resolved) || null;
2901
+ }
2902
+ /**
2903
+ * Resolve which (env, preview) pair — and therefore which cache key — a call
2904
+ * for `componentId` refers to.
2905
+ *
2906
+ * Single source of truth for fetchComponentV2, getResolvedConfig and
2907
+ * hydrateComponent, so a hydrated config always lands on the key a later
2908
+ * fetch will look under.
2909
+ */
2910
+ resolveParams(componentId, environmentIdentifier, preview) {
2724
2911
  const preloaded = this.preloadedComponents[componentId];
2725
- const hasExplicitParams = env !== void 0 || preview !== void 0;
2726
- let resolvedEnv;
2912
+ const hasExplicitParams = environmentIdentifier !== void 0 || preview !== void 0;
2913
+ let env;
2727
2914
  let usePreview;
2728
2915
  if (!hasExplicitParams && preloaded) {
2729
- resolvedEnv = preloaded.env;
2916
+ env = preloaded.env;
2730
2917
  usePreview = preloaded.preview;
2731
2918
  } else {
2732
- resolvedEnv = env || this._defaultEnv;
2733
- const hasEffectiveEnv = env || this._envExplicitlySet;
2919
+ env = environmentIdentifier || this._defaultEnv;
2920
+ const hasEffectiveEnv = environmentIdentifier || this._envExplicitlySet;
2734
2921
  usePreview = preview === true ? true : preview === false ? false : !hasEffectiveEnv;
2735
2922
  }
2736
- const cacheKey = "".concat(componentId, ":").concat(resolvedEnv, ":").concat(usePreview ? "preview" : "live");
2737
- return ((_a = this.variants[cacheKey]) == null ? void 0 : _a.resolved) || null;
2923
+ return { env, usePreview, cacheKey: "".concat(componentId, ":").concat(env, ":").concat(usePreview ? "preview" : "live") };
2924
+ }
2925
+ /**
2926
+ * Seed an already-resolved component config into the cache, without any
2927
+ * network request.
2928
+ *
2929
+ * The counterpart to {@link fetchComponentV2}: use it when the config was
2930
+ * resolved somewhere else — most often on a server, then embedded in the
2931
+ * page — so the browser can render the component with no round trip.
2932
+ *
2933
+ * After hydrating, `fetchComponentV2`, `getResolvedConfig` and `isPreloaded`
2934
+ * all answer for this component from memory.
2935
+ *
2936
+ * Pass the same `env` / `preview` the config was resolved with; the defaults
2937
+ * match what a plain `fetchComponentV2(componentId)` would have used.
2938
+ */
2939
+ hydrateComponent(componentId, config, env, preview) {
2940
+ const { env: resolvedEnv, usePreview, cacheKey } = this.resolveParams(componentId, env, preview);
2941
+ const promise = Promise.resolve(config);
2942
+ promise.resolved = config;
2943
+ this.variants[cacheKey] = promise;
2944
+ this.preloadedComponents[componentId] = { env: resolvedEnv, preview: usePreview };
2738
2945
  }
2739
2946
  // ============ V1 Methods (Legacy) ============
2740
2947
  /**
@@ -2867,6 +3074,13 @@ var HostSDK = class {
2867
3074
  __publicField(this, "components2init", []);
2868
3075
  __publicField(this, "components", []);
2869
3076
  __publicField(this, "componentsLoaders", []);
3077
+ // Global render policy (allow/deny/mode gate). A per-call options.renderPolicy
3078
+ // takes precedence over this — see HTMLComponentLoader.resolveRenderMode.
3079
+ __publicField(this, "_renderPolicy");
3080
+ __publicField(this, "setRenderPolicy", (policy) => {
3081
+ this._renderPolicy = policy;
3082
+ });
3083
+ __publicField(this, "getRenderPolicy", () => this._renderPolicy);
2870
3084
  __publicField(this, "initiated", false);
2871
3085
  __publicField(this, "version", myop_sdk_version_default);
2872
3086
  __publicField(this, "type2InstanceCount", {});