@myop/sdk 0.3.32 → 0.3.33

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 (45) hide show
  1. package/dist/bundled-declarations.d.ts +135 -48
  2. package/dist/cjs/_IframeSDK.c7a53057.min.js +1 -0
  3. package/dist/cjs/{_IframeSDK.8ce25264.js → _IframeSDK.e5b2bc49.js} +201 -28
  4. package/dist/cjs/_IframeSDK.e5b2bc49.js.map +7 -0
  5. package/dist/cjs/_MyopHelpers.95610381.js.map +2 -2
  6. package/dist/cjs/{_MyopHelpers.172384f4.min.js → _MyopHelpers.ca1b3a3c.min.js} +1 -1
  7. package/dist/cjs/_WebComponentSDK.3a72ed95.min.js +1 -0
  8. package/dist/cjs/{_WebComponentSDK.1aa213d9.js → _WebComponentSDK.a7e660ab.js} +201 -28
  9. package/dist/cjs/_WebComponentSDK.a7e660ab.js.map +7 -0
  10. package/dist/cjs/_hostSDK.0529d5ed.min.js +1 -0
  11. package/dist/cjs/{_hostSDK.c7ca0fae.js → _hostSDK.1905850e.js} +201 -28
  12. package/dist/cjs/_hostSDK.1905850e.js.map +7 -0
  13. package/dist/cjs/myop_sdk.js +11 -11
  14. package/dist/cjs/myop_sdk.js.map +1 -1
  15. package/dist/cjs/myop_sdk.min.js +1 -1
  16. package/dist/cjs-bundled/myop_sdk.bundled.js +203 -29
  17. package/dist/cjs-bundled/myop_sdk.bundled.js.map +3 -3
  18. package/dist/cjs-bundled/myop_sdk.bundled.min.js +1 -1
  19. package/dist/module/Iframe/index.js +259 -29
  20. package/dist/module/Iframe/index.js.map +2 -2
  21. package/dist/module/SDK.js +260 -29
  22. package/dist/module/SDK.js.map +3 -3
  23. package/dist/module/common/index.d.ts +26 -0
  24. package/dist/module/common/index.js +1 -1
  25. package/dist/module/common/index.js.map +2 -2
  26. package/dist/module/embeddedSDK.js +1 -1
  27. package/dist/module/helpers/index.js +1 -1
  28. package/dist/module/helpers/index.js.map +2 -2
  29. package/dist/module/host/components/myopExtractedWebComponent.d.ts +1 -0
  30. package/dist/module/host/components/myopIframeComponent.d.ts +17 -0
  31. package/dist/module/host/embeddedSDK.js +1 -1
  32. package/dist/module/host/hostSDK.d.ts +15 -0
  33. package/dist/module/host/index.d.ts +1 -1
  34. package/dist/module/host/index.js +259 -29
  35. package/dist/module/host/index.js.map +2 -2
  36. package/dist/module/host/loaders/HTMLComponentLoader.d.ts +29 -1
  37. package/dist/module/webcomponent/index.js +259 -29
  38. package/dist/module/webcomponent/index.js.map +2 -2
  39. package/package.json +1 -1
  40. package/dist/cjs/_IframeSDK.07df88d3.min.js +0 -1
  41. package/dist/cjs/_IframeSDK.8ce25264.js.map +0 -7
  42. package/dist/cjs/_WebComponentSDK.1aa213d9.js.map +0 -7
  43. package/dist/cjs/_WebComponentSDK.92468fac.min.js +0 -1
  44. package/dist/cjs/_hostSDK.c7ca0fae.js.map +0 -7
  45. package/dist/cjs/_hostSDK.dc198afa.min.js +0 -1
@@ -1168,6 +1168,19 @@ var MyopExtractedWebComponent = class extends BaseMyopComponent {
1168
1168
  __publicField(this, "ctaCleanup");
1169
1169
  __publicField(this, "_ctaHandler");
1170
1170
  __publicField(this, "_ctaQueue", []);
1171
+ // A single 'myop-cta' listener, attached at construction so CTAs a component
1172
+ // dispatches during its first initWithData() render — before the host attaches
1173
+ // a handler — are buffered (and flushed on setCtaHandler), matching the iframe
1174
+ // path's pre-handler CTA queue.
1175
+ __publicField(this, "_ctaListener", (e) => {
1176
+ const detail = e.detail;
1177
+ if (!(detail == null ? void 0 : detail.action)) return;
1178
+ if (this._ctaHandler && !this.markedForDisposed) {
1179
+ this._ctaHandler(detail.action, detail.payload);
1180
+ } else if (!this._ctaHandler) {
1181
+ this._ctaQueue.push({ action: detail.action, payload: detail.payload });
1182
+ }
1183
+ });
1171
1184
  __publicField(this, "cleanupInspect", () => {
1172
1185
  });
1173
1186
  /**
@@ -1188,6 +1201,8 @@ var MyopExtractedWebComponent = class extends BaseMyopComponent {
1188
1201
  (_a = this.customElement.parentNode) == null ? void 0 : _a.removeChild(this.customElement);
1189
1202
  });
1190
1203
  this.element = customElement;
1204
+ this.customElement.addEventListener("myop-cta", this._ctaListener);
1205
+ this.ctaCleanup = () => this.customElement.removeEventListener("myop-cta", this._ctaListener);
1191
1206
  this.setInitiated();
1192
1207
  }
1193
1208
  inspect() {
@@ -1232,9 +1247,6 @@ var MyopExtractedWebComponent = class extends BaseMyopComponent {
1232
1247
  * Called via props.myop_cta_handler = handler
1233
1248
  */
1234
1249
  setCtaHandler(handler) {
1235
- if (this.ctaCleanup) {
1236
- this.ctaCleanup();
1237
- }
1238
1250
  this._ctaHandler = handler;
1239
1251
  if (this._ctaQueue.length > 0) {
1240
1252
  const queue = [...this._ctaQueue];
@@ -1245,24 +1257,6 @@ var MyopExtractedWebComponent = class extends BaseMyopComponent {
1245
1257
  }
1246
1258
  });
1247
1259
  }
1248
- const listener = (e) => {
1249
- var _a;
1250
- const customEvent = e;
1251
- if ((_a = customEvent.detail) == null ? void 0 : _a.action) {
1252
- if (this._ctaHandler && !this.markedForDisposed) {
1253
- this._ctaHandler(customEvent.detail.action, customEvent.detail.payload);
1254
- } else if (!this._ctaHandler) {
1255
- this._ctaQueue.push({
1256
- action: customEvent.detail.action,
1257
- payload: customEvent.detail.payload
1258
- });
1259
- }
1260
- }
1261
- };
1262
- this.customElement.addEventListener("myop-cta", listener);
1263
- this.ctaCleanup = () => {
1264
- this.customElement.removeEventListener("myop-cta", listener);
1265
- };
1266
1260
  }
1267
1261
  };
1268
1262
 
@@ -1331,6 +1325,17 @@ var connectProps = (component, propsConfig, selectedSkin) => {
1331
1325
  }
1332
1326
  return void 0;
1333
1327
  }
1328
+ if (component instanceof MyopIframeComponent && component.isolated) {
1329
+ const typedPropBehavior = propConfig.behavior;
1330
+ const propName = typedPropBehavior.remap || prop;
1331
+ if (propName === "myop_init_interface") {
1332
+ return (data) => {
1333
+ if (data === void 0) return component.getData();
1334
+ component.initWithData(data);
1335
+ };
1336
+ }
1337
+ return void 0;
1338
+ }
1334
1339
  if (selectedSkin.loader.type === SkinLoaders.HTMLLoader) {
1335
1340
  const typedLoader = selectedSkin.loader;
1336
1341
  if (typedLoader.shadowRootMode === ShadowRootModeType.localFrame) {
@@ -1377,6 +1382,18 @@ var connectProps = (component, propsConfig, selectedSkin) => {
1377
1382
  return true;
1378
1383
  }
1379
1384
  }
1385
+ if (component instanceof MyopIframeComponent && component.isolated) {
1386
+ const typedPropBehavior = propConfig.behavior;
1387
+ const propName = typedPropBehavior.remap || prop;
1388
+ if (propName === "myop_cta_handler") {
1389
+ component.setCtaHandler(value);
1390
+ return true;
1391
+ }
1392
+ if (propName === "myop_init_interface") {
1393
+ component.initWithData(value);
1394
+ return true;
1395
+ }
1396
+ }
1380
1397
  if (selectedSkin.loader.type === SkinLoaders.HTMLLoader) {
1381
1398
  const typedLoader = selectedSkin.loader;
1382
1399
  if (typedLoader.shadowRootMode === ShadowRootModeType.localFrame) {
@@ -1582,6 +1599,7 @@ var connectRefs = async (component, componentConfig, components, withoutRefCompo
1582
1599
 
1583
1600
  // src/host/components/myopIframeComponent.ts
1584
1601
  var MyopIframeComponent = class extends BaseMyopComponent {
1602
+ // last reported size (for the enable race)
1585
1603
  constructor(componentConfig, skin, container, IframeElement, options) {
1586
1604
  super(componentConfig, container, options);
1587
1605
  this.componentConfig = componentConfig;
@@ -1590,6 +1608,17 @@ var MyopIframeComponent = class extends BaseMyopComponent {
1590
1608
  __publicField(this, "_autoSizeCleanup");
1591
1609
  __publicField(this, "_autoSizeOptions");
1592
1610
  __publicField(this, "_autoSizeUpdate");
1611
+ // ── Isolation (sandboxed cross-origin frame) — postMessage bridge, host side ──
1612
+ __publicField(this, "isolated", false);
1613
+ __publicField(this, "_lastData");
1614
+ // cached last-sent data (sync getData)
1615
+ __publicField(this, "_ctaHandler");
1616
+ __publicField(this, "_ctaQueue", []);
1617
+ __publicField(this, "_isoMsgHandler");
1618
+ __publicField(this, "_isoSizeOpts");
1619
+ __publicField(this, "_isoAutoSize", false);
1620
+ // bridge sizing only when auto-size is on
1621
+ __publicField(this, "_isoLastSize");
1593
1622
  __publicField(this, "sizeMeta");
1594
1623
  __publicField(this, "cleanupInspect");
1595
1624
  __publicField(this, "setHeightBasedOnDocumentElement", () => {
@@ -1629,6 +1658,15 @@ var MyopIframeComponent = class extends BaseMyopComponent {
1629
1658
  */
1630
1659
  __publicField(this, "observeAutoSize", (options) => {
1631
1660
  this._autoSizeOptions = options;
1661
+ if (this.isolated) {
1662
+ this._isoSizeOpts = options;
1663
+ this._isoAutoSize = true;
1664
+ if (this._isoLastSize) this._applyIsoSize(this._isoLastSize.height, this._isoLastSize.width);
1665
+ return () => {
1666
+ this._isoAutoSize = false;
1667
+ this._isoSizeOpts = void 0;
1668
+ };
1669
+ }
1632
1670
  if (this._autoSizeCleanup && this._autoSizeUpdate) {
1633
1671
  this._autoSizeUpdate();
1634
1672
  return this._autoSizeCleanup;
@@ -1831,12 +1869,73 @@ var MyopIframeComponent = class extends BaseMyopComponent {
1831
1869
  this._autoSizeCleanup();
1832
1870
  this._autoSizeCleanup = void 0;
1833
1871
  }
1872
+ if (this._isoMsgHandler) {
1873
+ window.removeEventListener("message", this._isoMsgHandler);
1874
+ this._isoMsgHandler = void 0;
1875
+ }
1834
1876
  if (this.cleanupInspect)
1835
1877
  this.cleanupInspect();
1836
1878
  super.dispose();
1837
1879
  this.IframeElement.parentNode.removeChild(this.IframeElement);
1838
1880
  });
1839
1881
  this.element = this.IframeElement;
1882
+ this._lastData = options == null ? void 0 : options.data;
1883
+ }
1884
+ // ── Isolation bridge (host side) ─────────────────────────────────────────
1885
+ /** Attach the host-side postMessage listener for a sandboxed frame. */
1886
+ enableIsolation() {
1887
+ this.isolated = true;
1888
+ this.setInitiated();
1889
+ this._isoMsgHandler = (e) => {
1890
+ if (e.source !== this.IframeElement.contentWindow) return;
1891
+ const d = e.data;
1892
+ if (!d || d.__myop !== true) return;
1893
+ if (d.type === "myop:cta") {
1894
+ if (this._ctaHandler && !this.markedForDisposed) this._ctaHandler(d.action, d.payload);
1895
+ else if (!this._ctaHandler) this._ctaQueue.push({ action: d.action, payload: d.payload });
1896
+ } else if (d.type === "myop:size") {
1897
+ this._applyIsoSize(d.height, d.width);
1898
+ }
1899
+ };
1900
+ window.addEventListener("message", this._isoMsgHandler);
1901
+ }
1902
+ /** Data-in — unified with the extracted-WC API. Posts init over the bridge. */
1903
+ initWithData(data) {
1904
+ var _a, _b;
1905
+ this._lastData = data;
1906
+ (_b = (_a = this.IframeElement) == null ? void 0 : _a.contentWindow) == null ? void 0 : _b.postMessage({ __myop: true, type: "myop:init", data }, "*");
1907
+ }
1908
+ /** Data-in getter — returns the last data the host sent (cached, synchronous). */
1909
+ getData() {
1910
+ return this._lastData;
1911
+ }
1912
+ /** Data-out — unified with the extracted-WC API. Flushes CTAs queued pre-handler. */
1913
+ setCtaHandler(handler) {
1914
+ this._ctaHandler = handler;
1915
+ if (this._ctaQueue.length > 0) {
1916
+ const queue = [...this._ctaQueue];
1917
+ this._ctaQueue = [];
1918
+ queue.forEach((item) => {
1919
+ if (!this.markedForDisposed) handler(item.action, item.payload);
1920
+ });
1921
+ }
1922
+ }
1923
+ _applyIsoSize(height, width) {
1924
+ var _a;
1925
+ if (!height || Number.isNaN(height)) return;
1926
+ this._isoLastSize = { height, width };
1927
+ if (!this._isoAutoSize) return;
1928
+ const opts = this._isoSizeOpts;
1929
+ const toNum = (v) => v === void 0 ? void 0 : typeof v === "number" ? v : isNaN(parseFloat(v)) ? void 0 : parseFloat(v);
1930
+ const min = toNum(opts == null ? void 0 : opts.minHeight), max = toNum(opts == null ? void 0 : opts.maxHeight);
1931
+ let h = height;
1932
+ if (min !== void 0 && h < min) h = min;
1933
+ if (max !== void 0 && h > max) h = max;
1934
+ this.IframeElement.style.position = "relative";
1935
+ this.IframeElement.style.inset = "auto";
1936
+ this.IframeElement.style.height = h + "px";
1937
+ this.IframeElement.style.width = "100%";
1938
+ (_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 });
1840
1939
  }
1841
1940
  inspect() {
1842
1941
  if (this.cleanupInspect) {
@@ -2040,7 +2139,7 @@ var WebcomponentLoader = class extends BaseMyopLoader {
2040
2139
  };
2041
2140
 
2042
2141
  // version:myop-sdk-version
2043
- var myop_sdk_version_default = "0.3.32";
2142
+ var myop_sdk_version_default = "0.3.33";
2044
2143
 
2045
2144
  // src/host/embeddedSDK.ts
2046
2145
  var EMBEDDED_SDK_CONTENT = "";
@@ -2088,7 +2187,15 @@ var HTMLComponentLoader = class extends BaseMyopLoader {
2088
2187
  __publicField(this, "type", SkinLoaders.HTMLLoader);
2089
2188
  __publicField(this, "load", async (componentDefinition, skin, container, options) => {
2090
2189
  const loaderConfig = skin.loader;
2091
- if (this.isMyopWebComponent(loaderConfig.HTML)) {
2190
+ const isWC = this.isMyopWebComponent(loaderConfig.HTML);
2191
+ const { mode, isolate } = await this.resolveRenderMode(componentDefinition, skin, loaderConfig, isWC, options);
2192
+ if (mode === false) {
2193
+ throw new Error('[Myop] Rendering blocked by render policy for component "'.concat(componentDefinition.id, '"'));
2194
+ }
2195
+ if (isWC) {
2196
+ if (mode !== "webComponent") {
2197
+ throw new Error('[Myop] Web-component rendering denied by render policy for component "'.concat(componentDefinition.id, '"'));
2198
+ }
2092
2199
  return this.loadExtractedWebComponent(componentDefinition, skin, container, loaderConfig.HTML, options);
2093
2200
  }
2094
2201
  let domId = "myop-comp-".concat(uuidv4());
@@ -2098,12 +2205,28 @@ var HTMLComponentLoader = class extends BaseMyopLoader {
2098
2205
  const domId2 = "myop-comp-".concat(uniqId);
2099
2206
  let IframeElement = document.createElement("iframe");
2100
2207
  IframeElement.id = domId2;
2208
+ if (isolate) {
2209
+ IframeElement.setAttribute("sandbox", "allow-scripts allow-forms allow-popups");
2210
+ }
2101
2211
  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 ");
2102
2212
  if (!container.querySelector('[id^="myop-comp-"]'))
2103
2213
  container.innerHTML = "";
2104
2214
  IframeElement = this.appendChild(container, IframeElement, options);
2105
- const doc = IframeElement.contentDocument || IframeElement.contentWindow.document;
2106
- doc.open();
2215
+ const __srcParts = [];
2216
+ const doc = isolate ? {
2217
+ open() {
2218
+ },
2219
+ writeln(s) {
2220
+ __srcParts.push(s);
2221
+ },
2222
+ close() {
2223
+ IframeElement.srcdoc = __srcParts.join("\n");
2224
+ }
2225
+ } : (() => {
2226
+ const d = IframeElement.contentDocument || IframeElement.contentWindow.document;
2227
+ d.open();
2228
+ return d;
2229
+ })();
2107
2230
  let parsedSizeMeta = null;
2108
2231
  {
2109
2232
  const _preParser = new DOMParser();
@@ -2143,22 +2266,29 @@ var HTMLComponentLoader = class extends BaseMyopLoader {
2143
2266
  const _doc = parser.parseFromString(HTML2Render, "text/html");
2144
2267
  const styleTag = _doc.createElement("style");
2145
2268
  styleTag.setAttribute("data-myop-injected", "true");
2146
- styleTag.textContent = options.injectCss;
2269
+ styleTag.textContent = options.injectCss.replace(/<\s*\/\s*style/gi, "<\\/style");
2147
2270
  (_doc.head || _doc.documentElement).appendChild(styleTag);
2148
2271
  HTML2Render = "<!DOCTYPE html>" + _doc.documentElement.outerHTML;
2149
2272
  }
2150
2273
  doc.writeln(HTML2Render);
2151
2274
  const sdkScript = HAS_EMBEDDED_SDK ? "<script>".concat(EMBEDDED_SDK_CONTENT, "<\/script>") : '<script src="'.concat(window.myop.__ROOT_SDK_PUBLIC_URL__, '"><\/script>');
2152
2275
  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>";
2153
- doc.writeln("".concat(sdkScript).concat(initScript));
2154
- if ((options == null ? void 0 : options.data) !== void 0) {
2276
+ if (!isolate) {
2277
+ doc.writeln("".concat(sdkScript).concat(initScript));
2278
+ }
2279
+ if (!isolate && (options == null ? void 0 : options.data) !== void 0) {
2155
2280
  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>";
2156
2281
  const escapedData = JSON.stringify(options.data).replace(/<\/script/gi, "\\u003c/script");
2157
2282
  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>");
2158
2283
  doc.writeln(ctaQueueScript + dataScript);
2159
2284
  }
2285
+ if (isolate) {
2286
+ const escapedData = (options == null ? void 0 : options.data) !== void 0 ? JSON.stringify(options.data).replace(/<\/script/gi, "\\u003c/script") : "undefined";
2287
+ doc.writeln(this.buildIsolationBridge(escapedData));
2288
+ }
2160
2289
  doc.close();
2161
2290
  const comp = new MyopIframeComponent(componentDefinition, skin, container, IframeElement, options);
2291
+ if (isolate) comp.enableIsolation();
2162
2292
  comp.sizeMeta = parsedSizeMeta;
2163
2293
  comp.initiated().then(() => {
2164
2294
  if ((options == null ? void 0 : options.autoSize) === false) {
@@ -2213,6 +2343,42 @@ var HTMLComponentLoader = class extends BaseMyopLoader {
2213
2343
  isMyopWebComponent(html) {
2214
2344
  return html.trimStart().startsWith(MYOP_WEB_COMPONENT_MARKER);
2215
2345
  }
2346
+ /**
2347
+ * Resolve how this component should render, applying the host render policy.
2348
+ * Precedence: options.renderPolicy (per-call) fully replaces the global
2349
+ * hostSDK.setRenderPolicy — so an app can restrict globally and allow specifics.
2350
+ * With no policy set, behavior is unchanged from before (marker ⇒ web component).
2351
+ */
2352
+ async resolveRenderMode(componentDefinition, skin, loaderConfig, isWebComponent, options) {
2353
+ var _a, _b, _c, _d;
2354
+ const requestedMode = isWebComponent ? "webComponent" : loaderConfig.isolation || (options == null ? void 0 : options.isolation) ? "isolatedIframe" : "iframe";
2355
+ 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);
2356
+ const mode = policy ? await policy({ componentDefinition, skin, requestedMode, isWebComponent }) : requestedMode;
2357
+ return { mode, isolate: mode === "isolatedIframe" };
2358
+ }
2359
+ /**
2360
+ * The in-frame bridge for isolated components. Runs inside the sandboxed
2361
+ * (opaque-origin) iframe, translating the same author-facing contract to/from
2362
+ * postMessage since the host has no same-origin access:
2363
+ * • data-in : parent posts {type:'myop:init'} → calls window.myop_init_interface
2364
+ * (plus a baked initial value for the first render)
2365
+ * • data-out: window.myop_cta_handler → parent.postMessage({type:'myop:cta'})
2366
+ * • resize : ResizeObserver → parent.postMessage({type:'myop:size'})
2367
+ *
2368
+ * TODO(dev-extension): the isolated path deliberately skips the same-origin
2369
+ * dataScript, so it never posts the `MYOP_PREINJECTED_INIT` message the Myop dev
2370
+ * extension listens for to log the INITIAL render (`init*`). Later init updates and
2371
+ * all CTAs are still tracked (the extension wraps `comp.props`, which our isolated
2372
+ * connectProps branch routes through), so only the first-render payload is missing
2373
+ * from the extension's activity log for isolated components. Closing this would be a
2374
+ * ~1-line `parent.postMessage({type:'MYOP_PREINJECTED_INIT', payload:{data}})` inside
2375
+ * flushInitial() below — intentionally NOT done for now to avoid adding extension-only
2376
+ * traffic to the component runtime. Web components have the same initial-init gap
2377
+ * (initWithData is called on the element, not via comp.props) and it predates this.
2378
+ */
2379
+ buildIsolationBridge(initialDataLiteral) {
2380
+ 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>");
2381
+ }
2216
2382
  /**
2217
2383
  * Extract the web component script content from HTML
2218
2384
  */
@@ -2662,6 +2828,13 @@ var HostSDK = class {
2662
2828
  __publicField(this, "components2init", []);
2663
2829
  __publicField(this, "components", []);
2664
2830
  __publicField(this, "componentsLoaders", []);
2831
+ // Global render policy (allow/deny/mode gate). A per-call options.renderPolicy
2832
+ // takes precedence over this — see HTMLComponentLoader.resolveRenderMode.
2833
+ __publicField(this, "_renderPolicy");
2834
+ __publicField(this, "setRenderPolicy", (policy) => {
2835
+ this._renderPolicy = policy;
2836
+ });
2837
+ __publicField(this, "getRenderPolicy", () => this._renderPolicy);
2665
2838
  __publicField(this, "initiated", false);
2666
2839
  __publicField(this, "version", myop_sdk_version_default);
2667
2840
  __publicField(this, "type2InstanceCount", {});