@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
@@ -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.34";
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
  */
@@ -2430,24 +2596,33 @@ var _CloudRepository = class _CloudRepository {
2430
2596
  getPreloadedParams(componentId) {
2431
2597
  return this.preloadedComponents[componentId];
2432
2598
  }
2599
+ /**
2600
+ * Resolve a component config: fetch it once, then serve it from this
2601
+ * repository's cache.
2602
+ *
2603
+ * This is the name to use. `fetchComponentV2` is the same method under its
2604
+ * versioned name and stays for backward compatibility — note that the
2605
+ * unversioned `fetchComponent` is a *deprecated v1* API and is NOT this.
2606
+ *
2607
+ * Completes the trio with {@link getResolvedConfig} (synchronous read of an
2608
+ * already-resolved config) and {@link hydrateComponent} (seed one you
2609
+ * already hold).
2610
+ *
2611
+ * Prefer the module-level `preloadComponents([id])` in app code; reach for
2612
+ * this when you need an isolated repository instance whose cache lifetime
2613
+ * you control — a server with its own TTL, for example.
2614
+ */
2615
+ async resolveComponent(componentId, env, preview) {
2616
+ return this.fetchComponentV2(componentId, env, preview);
2617
+ }
2433
2618
  /**
2434
2619
  * Fetch a v2 component config
2435
2620
  * If env/preview not specified and component was preloaded, uses preloaded params
2621
+ *
2622
+ * @see resolveComponent — the unversioned name for this method
2436
2623
  */
2437
2624
  async fetchComponentV2(componentId, environmentIdentifier, preview) {
2438
- const preloaded = this.preloadedComponents[componentId];
2439
- const hasExplicitParams = environmentIdentifier !== void 0 || preview !== void 0;
2440
- let env;
2441
- let usePreview;
2442
- if (!hasExplicitParams && preloaded) {
2443
- env = preloaded.env;
2444
- usePreview = preloaded.preview;
2445
- } else {
2446
- env = environmentIdentifier || this._defaultEnv;
2447
- const hasEffectiveEnv = environmentIdentifier || this._envExplicitlySet;
2448
- usePreview = preview === true ? true : preview === false ? false : !hasEffectiveEnv;
2449
- }
2450
- const cacheKey = "".concat(componentId, ":").concat(env, ":").concat(usePreview ? "preview" : "live");
2625
+ const { env, usePreview, cacheKey } = this.resolveParams(componentId, environmentIdentifier, preview);
2451
2626
  console.log("[CloudRepository] fetchComponentV2", {
2452
2627
  componentId: componentId.slice(0, 8) + "...",
2453
2628
  env,
@@ -2516,20 +2691,52 @@ var _CloudRepository = class _CloudRepository {
2516
2691
  */
2517
2692
  getResolvedConfig(componentId, env, preview) {
2518
2693
  var _a;
2694
+ const { cacheKey } = this.resolveParams(componentId, env, preview);
2695
+ return ((_a = this.variants[cacheKey]) == null ? void 0 : _a.resolved) || null;
2696
+ }
2697
+ /**
2698
+ * Resolve which (env, preview) pair — and therefore which cache key — a call
2699
+ * for `componentId` refers to.
2700
+ *
2701
+ * Single source of truth for fetchComponentV2, getResolvedConfig and
2702
+ * hydrateComponent, so a hydrated config always lands on the key a later
2703
+ * fetch will look under.
2704
+ */
2705
+ resolveParams(componentId, environmentIdentifier, preview) {
2519
2706
  const preloaded = this.preloadedComponents[componentId];
2520
- const hasExplicitParams = env !== void 0 || preview !== void 0;
2521
- let resolvedEnv;
2707
+ const hasExplicitParams = environmentIdentifier !== void 0 || preview !== void 0;
2708
+ let env;
2522
2709
  let usePreview;
2523
2710
  if (!hasExplicitParams && preloaded) {
2524
- resolvedEnv = preloaded.env;
2711
+ env = preloaded.env;
2525
2712
  usePreview = preloaded.preview;
2526
2713
  } else {
2527
- resolvedEnv = env || this._defaultEnv;
2528
- const hasEffectiveEnv = env || this._envExplicitlySet;
2714
+ env = environmentIdentifier || this._defaultEnv;
2715
+ const hasEffectiveEnv = environmentIdentifier || this._envExplicitlySet;
2529
2716
  usePreview = preview === true ? true : preview === false ? false : !hasEffectiveEnv;
2530
2717
  }
2531
- const cacheKey = "".concat(componentId, ":").concat(resolvedEnv, ":").concat(usePreview ? "preview" : "live");
2532
- return ((_a = this.variants[cacheKey]) == null ? void 0 : _a.resolved) || null;
2718
+ return { env, usePreview, cacheKey: "".concat(componentId, ":").concat(env, ":").concat(usePreview ? "preview" : "live") };
2719
+ }
2720
+ /**
2721
+ * Seed an already-resolved component config into the cache, without any
2722
+ * network request.
2723
+ *
2724
+ * The counterpart to {@link fetchComponentV2}: use it when the config was
2725
+ * resolved somewhere else — most often on a server, then embedded in the
2726
+ * page — so the browser can render the component with no round trip.
2727
+ *
2728
+ * After hydrating, `fetchComponentV2`, `getResolvedConfig` and `isPreloaded`
2729
+ * all answer for this component from memory.
2730
+ *
2731
+ * Pass the same `env` / `preview` the config was resolved with; the defaults
2732
+ * match what a plain `fetchComponentV2(componentId)` would have used.
2733
+ */
2734
+ hydrateComponent(componentId, config, env, preview) {
2735
+ const { env: resolvedEnv, usePreview, cacheKey } = this.resolveParams(componentId, env, preview);
2736
+ const promise = Promise.resolve(config);
2737
+ promise.resolved = config;
2738
+ this.variants[cacheKey] = promise;
2739
+ this.preloadedComponents[componentId] = { env: resolvedEnv, preview: usePreview };
2533
2740
  }
2534
2741
  // ============ V1 Methods (Legacy) ============
2535
2742
  /**
@@ -2662,6 +2869,13 @@ var HostSDK = class {
2662
2869
  __publicField(this, "components2init", []);
2663
2870
  __publicField(this, "components", []);
2664
2871
  __publicField(this, "componentsLoaders", []);
2872
+ // Global render policy (allow/deny/mode gate). A per-call options.renderPolicy
2873
+ // takes precedence over this — see HTMLComponentLoader.resolveRenderMode.
2874
+ __publicField(this, "_renderPolicy");
2875
+ __publicField(this, "setRenderPolicy", (policy) => {
2876
+ this._renderPolicy = policy;
2877
+ });
2878
+ __publicField(this, "getRenderPolicy", () => this._renderPolicy);
2665
2879
  __publicField(this, "initiated", false);
2666
2880
  __publicField(this, "version", myop_sdk_version_default);
2667
2881
  __publicField(this, "type2InstanceCount", {});