@myop/sdk 0.3.36 → 0.4.0-beta.0

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 (46) hide show
  1. package/dist/bundled-declarations.d.ts +406 -166
  2. package/dist/cjs/{_IframeSDK.3283252f.js → _IframeSDK.096d8320.js} +1325 -915
  3. package/dist/cjs/_IframeSDK.096d8320.js.map +7 -0
  4. package/dist/cjs/_IframeSDK.8e791f92.min.js +1 -0
  5. package/dist/cjs/_MyopHelpers.91004b19.min.js +1 -0
  6. package/dist/cjs/{_MyopHelpers.08d1cf5d.js → _MyopHelpers.efed13e4.js} +362 -2
  7. package/dist/cjs/_MyopHelpers.efed13e4.js.map +7 -0
  8. package/dist/cjs/_WebComponentSDK.4a87f826.min.js +1 -0
  9. package/dist/cjs/{_WebComponentSDK.e84be6ea.js → _WebComponentSDK.e9e877db.js} +893 -486
  10. package/dist/cjs/_WebComponentSDK.e9e877db.js.map +7 -0
  11. package/dist/cjs/{_hostSDK.fa5b3ccf.js → _hostSDK.0c271647.js} +1348 -941
  12. package/dist/cjs/_hostSDK.0c271647.js.map +7 -0
  13. package/dist/cjs/_hostSDK.7d759290.min.js +1 -0
  14. package/dist/cjs/myop_sdk.js +35 -24
  15. package/dist/cjs/myop_sdk.js.map +2 -2
  16. package/dist/cjs/myop_sdk.min.js +1 -1
  17. package/dist/cjs-bundled/myop_sdk.bundled.js +1820 -1379
  18. package/dist/cjs-bundled/myop_sdk.bundled.js.map +4 -4
  19. package/dist/cjs-bundled/myop_sdk.bundled.min.js +1 -1
  20. package/dist/module/Iframe/index.js +1501 -1079
  21. package/dist/module/Iframe/index.js.map +4 -4
  22. package/dist/module/SDK.d.ts +5 -1
  23. package/dist/module/SDK.js +1974 -1523
  24. package/dist/module/SDK.js.map +4 -4
  25. package/dist/module/embeddedSDK.js +1 -1
  26. package/dist/module/helpers/CloudRepository.d.ts +96 -0
  27. package/dist/module/helpers/cloudRepositoryHelpers.d.ts +99 -0
  28. package/dist/module/helpers/deliveryStore.d.ts +51 -0
  29. package/dist/module/helpers/index.js +370 -3
  30. package/dist/module/helpers/index.js.map +4 -4
  31. package/dist/module/host/components/myopIframeComponent.d.ts +6 -0
  32. package/dist/module/host/embeddedSDK.js +1 -1
  33. package/dist/module/host/hostSDK.d.ts +2 -0
  34. package/dist/module/host/index.js +1516 -1097
  35. package/dist/module/host/index.js.map +4 -4
  36. package/dist/module/webcomponent/index.js +1202 -783
  37. package/dist/module/webcomponent/index.js.map +4 -4
  38. package/package.json +1 -1
  39. package/dist/cjs/_IframeSDK.3283252f.js.map +0 -7
  40. package/dist/cjs/_IframeSDK.652f4774.min.js +0 -1
  41. package/dist/cjs/_MyopHelpers.08d1cf5d.js.map +0 -7
  42. package/dist/cjs/_MyopHelpers.59521d8f.min.js +0 -1
  43. package/dist/cjs/_WebComponentSDK.8fe7c9bf.min.js +0 -1
  44. package/dist/cjs/_WebComponentSDK.e84be6ea.js.map +0 -7
  45. package/dist/cjs/_hostSDK.de2d767e.min.js +0 -1
  46. package/dist/cjs/_hostSDK.fa5b3ccf.js.map +0 -7
@@ -1529,9 +1529,7 @@ var MyopIframeComponent = class extends BaseMyopComponent {
1529
1529
  const iframe = this.IframeElement;
1530
1530
  const doc = iframe.contentDocument;
1531
1531
  if (!doc) {
1532
- console.warn("[MyopIframeComponent] Cannot observe auto size: contentDocument not accessible");
1533
- return () => {
1534
- };
1532
+ return this.observeHeightViaBridge();
1535
1533
  }
1536
1534
  const clamp = (value, min, max) => {
1537
1535
  if (min !== void 0 && value < min) return min;
@@ -1675,6 +1673,32 @@ var MyopIframeComponent = class extends BaseMyopComponent {
1675
1673
  this._autoSizeCleanup = cleanup;
1676
1674
  return cleanup;
1677
1675
  });
1676
+ __publicField(this, "_bridgeSizeCleanup");
1677
+ /**
1678
+ * Auto-height for a frame the host can't read (cross-origin). Runs after the IframeSDK
1679
+ * handshake: the frame reports body resizes and the host re-reads the scroll height.
1680
+ */
1681
+ __publicField(this, "observeHeightViaBridge", () => {
1682
+ if (this._bridgeSizeCleanup) return this._bridgeSizeCleanup;
1683
+ let observerCleanup;
1684
+ let stopped = false;
1685
+ const cleanup = () => {
1686
+ stopped = true;
1687
+ observerCleanup == null ? void 0 : observerCleanup();
1688
+ this._bridgeSizeCleanup = void 0;
1689
+ };
1690
+ this._bridgeSizeCleanup = cleanup;
1691
+ this.initiated().then(() => {
1692
+ if (stopped || this.markedForDisposed) return;
1693
+ this.IframeElement.style.position = "relative";
1694
+ this.IframeElement.style.inset = "auto";
1695
+ this.IframeElement.style.width = "100%";
1696
+ this.setHeightBasedOnScrollHeight();
1697
+ observerCleanup = this.send(new SetResizeObserverMessage());
1698
+ }).catch(() => {
1699
+ });
1700
+ return cleanup;
1701
+ });
1678
1702
  __publicField(this, "setSizeBasedOnDocumentElement", () => {
1679
1703
  const cleanupHandler = this.send(new ExecuteScriptMessage(() => {
1680
1704
  const { height, width } = document.documentElement.getBoundingClientRect();
@@ -1720,6 +1744,8 @@ var MyopIframeComponent = class extends BaseMyopComponent {
1720
1744
  return cleanupHandler;
1721
1745
  });
1722
1746
  __publicField(this, "dispose", () => {
1747
+ var _a;
1748
+ (_a = this._bridgeSizeCleanup) == null ? void 0 : _a.call(this);
1723
1749
  if (this._autoSizeCleanup) {
1724
1750
  this._autoSizeCleanup();
1725
1751
  this._autoSizeCleanup = void 0;
@@ -1885,7 +1911,11 @@ var MyopIframeLoader = class extends BaseMyopLoader {
1885
1911
  container.innerHTML = "";
1886
1912
  IframeElement = this.appendChild(container, IframeElement, options);
1887
1913
  }
1888
- return new MyopIframeComponent(componentDefinition, skin, container, IframeElement, options);
1914
+ const component = new MyopIframeComponent(componentDefinition, skin, container, IframeElement, options);
1915
+ if (typedLoaderConfig.autoHeight && (options == null ? void 0 : options.autoSize) !== false) {
1916
+ component.observeHeightViaBridge();
1917
+ }
1918
+ return component;
1889
1919
  });
1890
1920
  }
1891
1921
  };
@@ -1999,1016 +2029,1366 @@ var WebcomponentLoader = class extends BaseMyopLoader {
1999
2029
  };
2000
2030
 
2001
2031
  // version:myop-sdk-version
2002
- var myop_sdk_version_default = "0.3.36";
2032
+ var myop_sdk_version_default = "0.4.0-beta.0";
2003
2033
 
2004
- // src/webcomponent/messageHandlers/BaseWebComponentMessageHandler.ts
2005
- var BaseWebComponentMessageHandler = class extends BaseContextMessageHandler {
2006
- constructor(messageToHost, context) {
2007
- super(messageToHost);
2008
- this.context = context;
2009
- __publicField(this, "executor", (event) => {
2010
- if (event.destination) {
2011
- const destination = event.destination;
2012
- if (this.context[destination].context) {
2013
- const _messageToHost = (message, replayTo) => {
2014
- this.messageToHost(__spreadProps(__spreadValues({}, message), {
2015
- source: event.destination ? event.destination : event.source,
2016
- destination: event.source ? event.source : event.destination
2017
- }), replayTo);
2018
- };
2019
- return this.innerExecutor(event, this.context[destination].context, _messageToHost);
2020
- } else {
2021
- debugger;
2022
- }
2023
- } else {
2024
- debugger;
2025
- }
2026
- });
2034
+ // src/helpers/deliveryStore.ts
2035
+ var DB_NAME = "myop-delivery";
2036
+ var STORE = "components";
2037
+ var DB_VERSION = 1;
2038
+ var dbPromise = null;
2039
+ function openDb() {
2040
+ if (dbPromise) return dbPromise;
2041
+ dbPromise = new Promise((resolve) => {
2042
+ try {
2043
+ if (typeof indexedDB === "undefined") return resolve(null);
2044
+ const req = indexedDB.open(DB_NAME, DB_VERSION);
2045
+ req.onupgradeneeded = () => {
2046
+ const db = req.result;
2047
+ if (!db.objectStoreNames.contains(STORE)) db.createObjectStore(STORE, { keyPath: "key" });
2048
+ };
2049
+ req.onsuccess = () => resolve(req.result);
2050
+ req.onerror = () => resolve(null);
2051
+ req.onblocked = () => resolve(null);
2052
+ } catch (e) {
2053
+ resolve(null);
2054
+ }
2055
+ });
2056
+ return dbPromise;
2057
+ }
2058
+ function tx(mode, fn) {
2059
+ return openDb().then((db) => new Promise((resolve) => {
2060
+ if (!db) return resolve(null);
2061
+ try {
2062
+ const t = db.transaction(STORE, mode);
2063
+ const req = fn(t.objectStore(STORE));
2064
+ req.onsuccess = () => resolve(req.result);
2065
+ req.onerror = () => resolve(null);
2066
+ t.onabort = () => resolve(null);
2067
+ } catch (e) {
2068
+ resolve(null);
2069
+ }
2070
+ }));
2071
+ }
2072
+ var HINT_PREFIX = "myop.d.";
2073
+ function writeHint(key, tag, expiresAt) {
2074
+ try {
2075
+ localStorage.setItem(HINT_PREFIX + key, JSON.stringify({ t: tag, e: expiresAt }));
2076
+ } catch (e) {
2077
+ }
2078
+ }
2079
+ function clearHint(key) {
2080
+ try {
2081
+ localStorage.removeItem(HINT_PREFIX + key);
2082
+ } catch (e) {
2083
+ }
2084
+ }
2085
+ var memory = /* @__PURE__ */ new Map();
2086
+ var deliveryStore = {
2087
+ key(host, componentId, env, preview, opt) {
2088
+ return "".concat(host, "|").concat(componentId, "|").concat(env, "|").concat(preview ? "preview" : "live", "|").concat(opt || "raw");
2089
+ },
2090
+ async get(key) {
2091
+ const m = memory.get(key);
2092
+ if (m) return m;
2093
+ const e = await tx("readonly", (s) => s.get(key));
2094
+ if (e) {
2095
+ memory.set(key, e);
2096
+ writeHint(key, e.tag, e.storedAt + e.windowMs);
2097
+ }
2098
+ return e;
2099
+ },
2100
+ async put(entry) {
2101
+ memory.set(entry.key, entry);
2102
+ writeHint(entry.key, entry.tag, entry.storedAt + entry.windowMs);
2103
+ await tx("readwrite", (s) => s.put(entry));
2104
+ },
2105
+ async drop(key) {
2106
+ memory.delete(key);
2107
+ clearHint(key);
2108
+ await tx("readwrite", (s) => s.delete(key));
2109
+ },
2110
+ /** Still usable without asking the server? */
2111
+ fresh(e) {
2112
+ return !!e && Date.now() - e.storedAt < e.windowMs;
2113
+ },
2114
+ /**
2115
+ * The window this response licenses: the server's freshness minus what a CDN already
2116
+ * spent. Returns 0 when the server said nothing about caching, which means "do not
2117
+ * hold this" — the safe reading, and what production sends today.
2118
+ */
2119
+ windowFrom(headers) {
2120
+ const cc = headers.get("cache-control") || "";
2121
+ if (/no-store|no-cache/i.test(cc)) return 0;
2122
+ const m = /s-maxage\s*=\s*(\d+)/i.exec(cc) || /max-age\s*=\s*(\d+)/i.exec(cc);
2123
+ if (!m) return 0;
2124
+ const total = Number(m[1]);
2125
+ const age = Number(headers.get("age") || 0);
2126
+ return Math.max(0, total - (isNaN(age) ? 0 : age)) * 1e3;
2127
+ },
2128
+ /** For tests and for `refresh()`: forget everything this browser holds. */
2129
+ async clear() {
2130
+ memory.clear();
2131
+ try {
2132
+ for (let i = localStorage.length - 1; i >= 0; i--) {
2133
+ const k = localStorage.key(i);
2134
+ if (k && k.startsWith(HINT_PREFIX)) localStorage.removeItem(k);
2135
+ }
2136
+ } catch (e) {
2137
+ }
2138
+ await tx("readwrite", (s) => s.clear());
2027
2139
  }
2028
2140
  };
2029
2141
 
2030
- // src/consts.ts
2031
- var myopAttributes = {
2032
- id: "myop-id"
2142
+ // src/helpers/CloudRepository.ts
2143
+ var convertV2VariantToComponentConfig = (config) => {
2144
+ return {
2145
+ instance: {
2146
+ id: "auto",
2147
+ componentId: config.componentId,
2148
+ componentName: config.name,
2149
+ skinSelector: {
2150
+ type: "Dedicated",
2151
+ skin: {
2152
+ id: "skin_auto_v2_converted"
2153
+ }
2154
+ }
2155
+ },
2156
+ type: {
2157
+ id: config.id,
2158
+ name: config.name,
2159
+ description: config.description,
2160
+ props: [
2161
+ {
2162
+ id: "in_auto_v2_converted",
2163
+ name: "myop_init_interface",
2164
+ type: "any",
2165
+ behavior: {
2166
+ type: PropConfigBehaviorTypes.code
2167
+ }
2168
+ },
2169
+ {
2170
+ id: "out_auto_v2_converted",
2171
+ name: "myop_cta_handler",
2172
+ type: "any",
2173
+ behavior: {
2174
+ type: PropConfigBehaviorTypes.code
2175
+ }
2176
+ }
2177
+ ],
2178
+ refs: [],
2179
+ skins: [
2180
+ {
2181
+ id: "skin_auto_v2_converted",
2182
+ name: "auto_v2_converted",
2183
+ description: "",
2184
+ //TODO : handle empty :
2185
+ // @ts-ignore
2186
+ loader: config.consume_variant[0].loader
2187
+ }
2188
+ ],
2189
+ defaultSkin: 0
2190
+ },
2191
+ name: config.name
2192
+ };
2033
2193
  };
2034
-
2035
- // src/common/messageHandlers/helpers.ts
2036
- var getElementsByRef = (ref, el) => {
2037
- return el.querySelectorAll("[".concat(myopAttributes.id, "='").concat(ref.refConfig.selector, "']"));
2194
+ var GLOBAL_KEY = "__MYOP_CLOUD_REPOSITORY_MAIN__";
2195
+ var getGlobalMain = () => {
2196
+ if (typeof window !== "undefined") {
2197
+ return window[GLOBAL_KEY];
2198
+ }
2199
+ if (typeof globalThis !== "undefined") {
2200
+ return globalThis[GLOBAL_KEY];
2201
+ }
2202
+ return void 0;
2038
2203
  };
2039
-
2040
- // src/webcomponent/messageHandlers/bindOnClickHandler.ts
2041
- var BindOnClickHandler = class extends BaseWebComponentMessageHandler {
2042
- constructor() {
2043
- super(...arguments);
2044
- __publicField(this, "messageType", MyopMessages.BindClickMessage);
2045
- __publicField(this, "innerExecutor", (event, shadowRootRef, messageToHost) => {
2046
- const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
2047
- const cleanupTasks = [];
2048
- items.forEach((item) => {
2049
- const handler = () => {
2050
- messageToHost(new ClickReplayMessage(event.handlerUniqueId));
2051
- };
2052
- item.addEventListener("click", handler);
2053
- cleanupTasks.push(() => {
2054
- item.removeEventListener("click", handler);
2055
- });
2056
- });
2057
- return () => {
2058
- cleanupTasks.forEach((task) => task());
2059
- };
2060
- });
2204
+ var setGlobalMain = (instance) => {
2205
+ if (typeof window !== "undefined") {
2206
+ window[GLOBAL_KEY] = instance;
2207
+ }
2208
+ if (typeof globalThis !== "undefined") {
2209
+ globalThis[GLOBAL_KEY] = instance;
2061
2210
  }
2062
2211
  };
2063
-
2064
- // src/webcomponent/messageHandlers/changeTextHandler.ts
2065
- var ChangeTextHandler = class extends BaseWebComponentMessageHandler {
2066
- constructor() {
2067
- super(...arguments);
2068
- __publicField(this, "messageType", MyopMessages.ChangeTextMessage);
2069
- __publicField(this, "innerExecutor", (event, shadowRootRef) => {
2070
- const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
2071
- items.forEach((item) => {
2072
- item.textContent = event.content;
2073
- });
2212
+ var _CloudRepository = class _CloudRepository {
2213
+ constructor(_baseUrl = "https://cloud.myop.dev") {
2214
+ this._baseUrl = _baseUrl;
2215
+ // v2 cache - keyed by componentId:env:preview|live
2216
+ // Each Promise is tagged with a `resolved` property after settling (see fetchComponentV2).
2217
+ __publicField(this, "variants", {});
2218
+ // Track which components were preloaded and with what params
2219
+ // Key: componentId, Value: { env, preview }
2220
+ __publicField(this, "preloadedComponents", {});
2221
+ // v1 cache
2222
+ __publicField(this, "userFlows", {});
2223
+ __publicField(this, "_defaultEnv", "production");
2224
+ __publicField(this, "_envExplicitlySet", false);
2225
+ __publicField(this, "_staticMode", false);
2226
+ __publicField(this, "_queryParams", {});
2227
+ /**
2228
+ * Opt-in delivery settings, set by myop.delivery(). Off means: this file behaves
2229
+ * EXACTLY as it did before — same host, same URL, same everything.
2230
+ */
2231
+ __publicField(this, "_delivery", { minify: false, host: null, cache: false });
2232
+ /**
2233
+ * What actually happened, for myop.delivery.stats(). `fellBack` is the number that
2234
+ * matters: it is how you find out the lane is unhealthy without waiting for a
2235
+ * bug report, because a fallback is INVISIBLE to the page (it still renders).
2236
+ */
2237
+ __publicField(this, "_deliveryStats", {
2238
+ requests: 0,
2239
+ viaDelivery: 0,
2240
+ fellBack: 0,
2241
+ lastError: null,
2242
+ /** where the last loads were answered from — the number the client window exists to move */
2243
+ fromMemory: 0,
2244
+ fromStorage: 0,
2245
+ fromNetwork: 0,
2246
+ /** re-checks after the window ended, and how many were answered "nothing changed" */
2247
+ revalidations: 0,
2248
+ unchanged: 0,
2249
+ bytesSaved: 0
2074
2250
  });
2251
+ /**
2252
+ * Local serves waiting to be reported: componentId -> {env, count}.
2253
+ *
2254
+ * THE MEASUREMENT PROBLEM THIS SOLVES. The better this cache works, the more usage
2255
+ * vanishes: a visitor inside their freshness window renders the page with no request,
2256
+ * so neither the server nor the CDN can see them. Left alone, a successful rollout
2257
+ * looks in the ledger exactly like customers leaving.
2258
+ *
2259
+ * So local serves are counted here and reported afterwards, batched, on a path that
2260
+ * never blocks rendering: flushed when the page is hidden (keepalive, so it survives
2261
+ * the tab closing) and opportunistically whenever the SDK is talking to the server
2262
+ * anyway. Nothing is sent while the page is loading, which is the point of the window.
2263
+ */
2264
+ __publicField(this, "_localServes", /* @__PURE__ */ new Map());
2265
+ __publicField(this, "_flushBound", false);
2075
2266
  }
2076
- };
2077
-
2078
- // src/webcomponent/shadowRootRef.ts
2079
- var ShadowRootRef = class extends RootRef {
2080
- constructor(container, shadowRoot) {
2081
- super(container, shadowRoot);
2082
- this.container = container;
2083
- this.shadowRoot = shadowRoot;
2267
+ static get Main() {
2268
+ const globalMain = getGlobalMain();
2269
+ if (globalMain) {
2270
+ return globalMain;
2271
+ }
2272
+ if (!_CloudRepository._main) {
2273
+ _CloudRepository._main = new _CloudRepository();
2274
+ setGlobalMain(_CloudRepository._main);
2275
+ }
2276
+ return _CloudRepository._main;
2084
2277
  }
2085
- };
2086
-
2087
- // src/webcomponent/messageHandlers/DetectMyopRefsMessageHandler.ts
2088
- var DetectMyopRefsMessageHandler = class extends BaseWebComponentMessageHandler {
2089
- constructor() {
2090
- super(...arguments);
2091
- __publicField(this, "innerExecutor", (event, shadowRootRef) => {
2092
- const allMyopItems = shadowRootRef.shadowRoot.querySelectorAll("[".concat(myopAttributes.id, "]"));
2093
- let myopRefs = [];
2094
- allMyopItems.forEach((item) => {
2095
- const myopId = item.getAttribute(myopAttributes.id);
2096
- if (myopId) {
2097
- myopRefs.push(new MyopElementRef(myopId, item.tagName, item.getBoundingClientRect(), item.offsetTop, item.offsetLeft));
2098
- }
2099
- });
2100
- this.messageToHost(new DetectedMyopRefsMessage(event.handlerUniqueId, myopRefs));
2278
+ /**
2279
+ * How big the component we are NOT re-downloading is. Deliberately measured from what
2280
+ * we hold rather than from Content-Length: once a response is compressed the header is
2281
+ * not readable cross-origin, so reading it there reported 0 every single time.
2282
+ */
2283
+ static sizeOfHeld(e) {
2284
+ var _a, _b, _c, _d, _e;
2285
+ try {
2286
+ return (((_e = (_d = (_c = (_b = (_a = e == null ? void 0 : e.config) == null ? void 0 : _a.type) == null ? void 0 : _b.skins) == null ? void 0 : _c[0]) == null ? void 0 : _d.loader) == null ? void 0 : _e.HTML) || "").length;
2287
+ } catch (e2) {
2288
+ return 0;
2289
+ }
2290
+ }
2291
+ /**
2292
+ * Turn on the opt-in delivery path.
2293
+ *
2294
+ * Opting in IS choosing the delivery stack: this points /consume at `host` (a second,
2295
+ * complete stack reading the same data) and asks for the minified artifact. Leave this
2296
+ * uncalled and nothing about the SDK changes.
2297
+ *
2298
+ * Deliberately mutates THIS instance rather than constructing a new repository:
2299
+ * CloudRepository.Main is a global singleton shared across bundles (see getGlobalMain),
2300
+ * so a second instance would be ignored by every component already using the first.
2301
+ */
2302
+ setDelivery(opts = {}) {
2303
+ if (opts.minify !== void 0) this._delivery.minify = !!opts.minify;
2304
+ if (opts.host !== void 0) this._delivery.host = opts.host;
2305
+ if (opts.cache !== void 0) this._delivery.cache = !!opts.cache;
2306
+ }
2307
+ deliveryStats() {
2308
+ var _a;
2309
+ return __spreadProps(__spreadValues({}, this._deliveryStats), {
2310
+ host: (_a = this._delivery.host) != null ? _a : _CloudRepository.DEFAULT_HOST,
2311
+ minify: this._delivery.minify,
2312
+ cache: this._delivery.cache
2101
2313
  });
2102
- __publicField(this, "messageType", MyopMessages.DetectMyopRefsMessage);
2103
2314
  }
2104
- };
2105
-
2106
- // src/webcomponent/messageHandlers/setAttributeHandler.ts
2107
- var setAttributeHandler = class extends BaseWebComponentMessageHandler {
2108
- constructor() {
2109
- super(...arguments);
2110
- __publicField(this, "messageType", MyopMessages.SetAttributeMessage);
2111
- __publicField(this, "innerExecutor", (event, shadowRootRef) => {
2112
- const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
2113
- items.forEach((item) => {
2114
- item.setAttribute(event.name, event.value);
2315
+ /**
2316
+ * Forget what this browser holds, so the next load asks the server.
2317
+ * `refresh()` with no ids drops everything; the counterpart to the window for the case
2318
+ * where a change has to be visible on THIS load — right after someone publishes.
2319
+ */
2320
+ async refreshDelivery() {
2321
+ await deliveryStore.clear();
2322
+ }
2323
+ noteLocalServe(componentId, env) {
2324
+ const cur = this._localServes.get(componentId);
2325
+ if (cur) cur.count++;
2326
+ else this._localServes.set(componentId, { env, count: 1 });
2327
+ this.bindFlush();
2328
+ }
2329
+ /** Report on page-hide, which is the only event that reliably fires on mobile. */
2330
+ bindFlush() {
2331
+ if (this._flushBound || typeof document === "undefined") return;
2332
+ this._flushBound = true;
2333
+ const onHide = () => {
2334
+ if (document.visibilityState === "hidden") this.flushLocalServes();
2335
+ };
2336
+ document.addEventListener("visibilitychange", onHide);
2337
+ window.addEventListener("pagehide", () => this.flushLocalServes());
2338
+ }
2339
+ /**
2340
+ * Send what we have. `keepalive` is what makes this work at page-hide: the request
2341
+ * outlives the document. Failure is ignored — a lost usage report must never be
2342
+ * visible to a visitor, and the next page load will report its own.
2343
+ */
2344
+ flushLocalServes() {
2345
+ if (!this._localServes.size) return;
2346
+ const batch = [...this._localServes.entries()].map(([id, v]) => "".concat(id, ":").concat(v.env, ":").concat(v.count)).join(",");
2347
+ this._localServes.clear();
2348
+ try {
2349
+ const url = "".concat(this.deliveryHost(), "/clientUsage?b=").concat(encodeURIComponent(batch));
2350
+ fetch(url, { keepalive: true, mode: "cors", credentials: "omit" }).catch(() => {
2115
2351
  });
2116
- });
2352
+ } catch (e) {
2353
+ }
2117
2354
  }
2118
- };
2119
-
2120
- // src/webcomponent/messageHandlers/addEventListenerHandler.ts
2121
- var AddEventListenerHandler = class extends BaseWebComponentMessageHandler {
2122
- constructor() {
2123
- super(...arguments);
2124
- __publicField(this, "messageType", MyopMessages.AddEventListenerMessage);
2125
- __publicField(this, "innerExecutor", (event, shadowRootRef, messageToHost) => {
2126
- const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
2127
- const cleanupTasks = [];
2128
- items.forEach((item) => {
2129
- const handler = (e) => {
2130
- messageToHost(new EventListenerCallbackMessage(event.handlerUniqueId, makeSerializable(e, event.serializableSkeleton)));
2131
- };
2132
- item.addEventListener(event.type, handler);
2133
- cleanupTasks.push(() => {
2134
- item.removeEventListener(event.type, handler);
2135
- });
2136
- });
2137
- return () => {
2138
- cleanupTasks.forEach((task) => task());
2139
- };
2140
- });
2355
+ /** Where /consume should be fetched from right now. */
2356
+ deliveryHost() {
2357
+ return this._delivery.host || this._baseUrl;
2141
2358
  }
2142
- };
2143
-
2144
- // src/webcomponent/messageHandlers/CreateRefComponentMessageHandler.ts
2145
- var CreateRefComponentMessageHandler = class extends BaseWebComponentMessageHandler {
2146
- constructor() {
2147
- super(...arguments);
2148
- __publicField(this, "messageType", MyopMessages.CreateRefComponentMessage);
2149
- __publicField(this, "innerExecutor", (event, shadowRootRef, messageToHost) => {
2150
- const createRef = async () => {
2151
- const allItems = shadowRootRef.shadowRoot.querySelectorAll("[".concat(myopAttributes.id, "='").concat(event.refConfig.selector, "']"));
2152
- if (allItems.length === 1) {
2153
- const hostSDK2 = HostSDK.Instance();
2154
- const refComponent = hostSDK2.components.find((c) => c.id === event.options.id);
2155
- if (refComponent) {
2156
- refComponent.dispose();
2157
- } else {
2158
- }
2159
- const index = hostSDK2.components.indexOf(refComponent);
2160
- if (index !== -1) {
2161
- hostSDK2.components.splice(index, 1);
2162
- } else {
2163
- }
2164
- const implementationComponent = await hostSDK2.loadComponent(
2165
- event.nestedComponentConfig,
2166
- allItems.item(0),
2167
- event.options
2168
- );
2169
- const nestedRefConfig = [];
2170
- Object.keys(implementationComponent.refs).forEach((refName) => {
2171
- let ref = implementationComponent.refs[refName];
2172
- ref = ref.__nonProxied || ref;
2173
- if (ref.componentDefinition) {
2174
- nestedRefConfig.push({
2175
- refName,
2176
- componentDefinitionId: ref.componentDefinition.id
2177
- });
2178
- }
2179
- });
2180
- messageToHost(new RefComponentCreatedMessage(event.handlerUniqueId, nestedRefConfig));
2181
- } else {
2182
- console.error("CreateRefComponentMessageHandler - DOM element not found");
2183
- this.messageToHost(new RefComponentCreatedMessage(event.handlerUniqueId, [], true));
2184
- debugger;
2185
- }
2186
- };
2187
- createRef().then();
2188
- });
2359
+ /**
2360
+ * Fetch a delivery URL with ONE fallback to the default host.
2361
+ *
2362
+ * The fallback is the kill switch: break or disable the lane and every client drifts
2363
+ * back to cloud.myop.dev on its own, with no customer deploy. It must therefore be
2364
+ * genuinely silent to the page and genuinely LOUD in stats() — a fallback that nobody
2365
+ * counts is an outage nobody notices.
2366
+ *
2367
+ * Only transport failures and 5xx fall back. A 404 is an answer: the component really
2368
+ * is missing, and retrying elsewhere would only hide it.
2369
+ */
2370
+ async deliveryFetch(path) {
2371
+ var _a;
2372
+ if (this._localServes.size) this.flushLocalServes();
2373
+ const host = this.deliveryHost();
2374
+ const primary = "".concat(host).concat(path);
2375
+ this._deliveryStats.requests++;
2376
+ const usingLane = host !== this._baseUrl;
2377
+ try {
2378
+ const res = await fetch(primary);
2379
+ if (res.ok || res.status < 500 || !usingLane) {
2380
+ if (usingLane && res.ok) this._deliveryStats.viaDelivery++;
2381
+ return res;
2382
+ }
2383
+ this._deliveryStats.lastError = "HTTP ".concat(res.status, " from ").concat(host);
2384
+ } catch (e) {
2385
+ if (!usingLane) throw e;
2386
+ this._deliveryStats.lastError = String((_a = e == null ? void 0 : e.message) != null ? _a : e);
2387
+ }
2388
+ this._deliveryStats.fellBack++;
2389
+ console.warn("[myop] delivery host failed (".concat(this._deliveryStats.lastError, ") \u2014 falling back to ").concat(this._baseUrl));
2390
+ return await fetch("".concat(this._baseUrl).concat(path));
2189
2391
  }
2190
- };
2191
-
2192
- // src/common/messageHandlers/executeScriptHandler.ts
2193
- var ExecuteScriptHandlerExecutor = (event, replier, rootRef) => {
2194
- const __scriptInputs = event.scriptInputs ? event.scriptInputs : {};
2195
- __scriptInputs.makeSerializable = makeSerializable;
2196
- __scriptInputs.send = replier;
2197
- __scriptInputs.rootRef = rootRef;
2198
- __scriptInputs.__scriptInputs = __scriptInputs;
2199
- const dynamicFunction = new Function("return (".concat(event.script, ")(...arguments)"));
2200
- const ret = dynamicFunction(__scriptInputs);
2201
- replier(ret);
2202
- };
2203
-
2204
- // src/webcomponent/messageHandlers/executeScriptHandler.ts
2205
- var ExecuteScriptHandler = class extends BaseWebComponentMessageHandler {
2206
- constructor() {
2207
- super(...arguments);
2208
- __publicField(this, "messageType", MyopMessages.ExecuteScriptMessage);
2209
- __publicField(this, "innerExecutor", (event, shadowRootRef, messageToHost) => {
2210
- const replier = (data) => {
2211
- messageToHost(new ExecuteScriptReplyMessage(event.handlerUniqueId, data));
2212
- };
2213
- ExecuteScriptHandlerExecutor(event, replier, shadowRootRef);
2214
- });
2392
+ /**
2393
+ * Enable static mode for self-hosted component registries.
2394
+ * In static mode, URLs are constructed as file paths instead of query params:
2395
+ * ${baseUrl}/components/${componentId}/${env}.json
2396
+ */
2397
+ enableStaticMode() {
2398
+ this._staticMode = true;
2215
2399
  }
2216
- };
2217
-
2218
- // src/webcomponent/messageHandlers/GetElementValueHandler.ts
2219
- var getInputValue = (element) => {
2220
- if (!element) return null;
2221
- if (element.tagName === "FORM") {
2222
- const formData = new FormData(element);
2223
- const dataObject = {
2224
- formData: {},
2225
- unmappedData: []
2226
- };
2227
- const elements = element.querySelectorAll("input, select, textarea");
2228
- let autoNameIndexer = -1;
2229
- elements.forEach((element2) => {
2230
- if (typeof element2.value === "string") {
2231
- const myopId = element2.getAttribute(myopAttributes.id);
2232
- let key = element2.getAttribute("name");
2233
- const nodeData = {
2234
- id: element2.id,
2235
- name: key,
2236
- value: getInputValue(element2),
2237
- required: element2.required,
2238
- validity: makeSerializable(element2.validity, true),
2239
- myopId
2240
- };
2241
- if (!key) {
2242
- dataObject.unmappedData.push(nodeData);
2243
- } else {
2244
- if (dataObject.formData[key]) {
2245
- if (dataObject.formData[key].value) {
2246
- dataObject.unmappedData.push(nodeData);
2247
- } else {
2248
- dataObject.unmappedData.push(dataObject.formData[key]);
2249
- dataObject.formData[key] = nodeData;
2250
- }
2251
- } else {
2252
- dataObject.formData[key] = nodeData;
2253
- }
2254
- }
2255
- }
2256
- });
2257
- return dataObject;
2400
+ /**
2401
+ * Set query parameters to append to all fetch URLs (e.g. for CDN cache busting).
2402
+ * Example: `setQueryParams({ lastupdate: '11112026' })`
2403
+ */
2404
+ setQueryParams(params) {
2405
+ this._queryParams = params;
2258
2406
  }
2259
- if (element.type === "checkbox" || element.type === "radio") {
2260
- return element.checked ? element.value : null;
2407
+ /**
2408
+ * Set the default environment for this CloudRepository instance
2409
+ */
2410
+ setEnvironment(env) {
2411
+ this._defaultEnv = env;
2412
+ this._envExplicitlySet = true;
2261
2413
  }
2262
- if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
2263
- return element.value;
2414
+ /**
2415
+ * Get the current default environment
2416
+ */
2417
+ getDefaultEnvironment() {
2418
+ return this._defaultEnv;
2264
2419
  }
2265
- if (element.tagName === "SELECT") {
2266
- return element.value;
2420
+ // ============ V2 Methods (Default) ============
2421
+ /**
2422
+ * Check if a component is already cached/preloaded (v2)
2423
+ * If env and preview are not provided, checks if ANY version is preloaded
2424
+ */
2425
+ isPreloaded(componentId, env, preview) {
2426
+ if (env !== void 0 || preview !== void 0) {
2427
+ const cacheKey = "".concat(componentId, ":").concat(env || this._defaultEnv, ":").concat(preview ? "preview" : "live");
2428
+ return cacheKey in this.variants;
2429
+ }
2430
+ return componentId in this.preloadedComponents;
2267
2431
  }
2268
- if (element.isContentEditable) {
2269
- return element.innerText || element.textContent;
2432
+ /**
2433
+ * Get the preloaded params for a component (if preloaded)
2434
+ * Returns undefined if not preloaded
2435
+ */
2436
+ getPreloadedParams(componentId) {
2437
+ return this.preloadedComponents[componentId];
2270
2438
  }
2271
- return null;
2272
- };
2273
- var GetElementValueHandler = class extends BaseWebComponentMessageHandler {
2274
- constructor() {
2275
- super(...arguments);
2276
- __publicField(this, "messageType", MyopMessages.GetElementValueMessage);
2277
- __publicField(this, "innerExecutor", (event, shadowRootRef, messageToHost) => {
2278
- const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
2279
- items.forEach((item) => {
2280
- messageToHost(new ElementValueReplayMessage(getInputValue(item)), event);
2281
- });
2282
- });
2439
+ /**
2440
+ * Resolve a component config: fetch it once, then serve it from this
2441
+ * repository's cache.
2442
+ *
2443
+ * This is the name to use. `fetchComponentV2` is the same method under its
2444
+ * versioned name and stays for backward compatibility — note that the
2445
+ * unversioned `fetchComponent` is a *deprecated v1* API and is NOT this.
2446
+ *
2447
+ * Completes the trio with {@link getResolvedConfig} (synchronous read of an
2448
+ * already-resolved config) and {@link hydrateComponent} (seed one you
2449
+ * already hold).
2450
+ *
2451
+ * Prefer the module-level `preloadComponents([id])` in app code; reach for
2452
+ * this when you need an isolated repository instance whose cache lifetime
2453
+ * you control — a server with its own TTL, for example.
2454
+ */
2455
+ async resolveComponent(componentId, env, preview) {
2456
+ return this.fetchComponentV2(componentId, env, preview);
2283
2457
  }
2284
- };
2285
-
2286
- // src/webcomponent/messageHandlers/setInnerHtmlHandler.ts
2287
- var SetInnerHtmlHandler = class extends BaseWebComponentMessageHandler {
2288
- constructor() {
2289
- super(...arguments);
2290
- __publicField(this, "messageType", MyopMessages.SetInnerHtml);
2291
- __publicField(this, "innerExecutor", (event, shadowRootRef) => {
2292
- const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
2293
- items.forEach((item) => {
2294
- item.innerHTML = event.content;
2295
- });
2458
+ /**
2459
+ * Fetch a v2 component config
2460
+ * If env/preview not specified and component was preloaded, uses preloaded params
2461
+ *
2462
+ * @see resolveComponent — the unversioned name for this method
2463
+ */
2464
+ async fetchComponentV2(componentId, environmentIdentifier, preview) {
2465
+ const { env, usePreview, cacheKey } = this.resolveParams(componentId, environmentIdentifier, preview);
2466
+ console.log("[CloudRepository] fetchComponentV2", {
2467
+ componentId: componentId.slice(0, 8) + "...",
2468
+ env,
2469
+ usePreview,
2470
+ cacheKey,
2471
+ cached: cacheKey in this.variants
2296
2472
  });
2297
- }
2298
- };
2299
-
2300
- // src/webcomponent/WebComponentSDK.ts
2301
- var WebComponentSDK = class extends BaseMyopSDK {
2302
- constructor() {
2303
- super(...arguments);
2304
- __publicField(this, "alwaysPassEnvelopesToHost", true);
2305
- //when new web component created.
2306
- __publicField(this, "connectedCallback", (container, shadow) => {
2307
- container.addEventListener(myopWebcomponentConsts.webcomponent_message_key, (e) => {
2308
- const eventContent = e.data ? e.data : e.detail;
2309
- if (!eventContent || !eventContent.myop) {
2310
- debugger;
2311
- throw new Error("recvied webcomponent_message with wrong type");
2312
- } else {
2313
- const message = eventContent;
2314
- this.handleIncomeMessages(e);
2315
- if (message.messageType === MyopMessages.InitMessage) {
2316
- const newComponentId = message.content.id;
2317
- this.components[newComponentId].context = new ShadowRootRef(container, shadow);
2473
+ if (!this.variants[cacheKey]) {
2474
+ if (!this.preloadedComponents[componentId]) {
2475
+ this.preloadedComponents[componentId] = { env, preview: usePreview };
2476
+ }
2477
+ this.variants[cacheKey] = new Promise(
2478
+ async (resolve, reject) => {
2479
+ try {
2480
+ let url;
2481
+ if (this._staticMode) {
2482
+ const file = usePreview ? "preview" : env;
2483
+ url = "".concat(this._baseUrl, "/components/").concat(componentId, "/").concat(file, ".json");
2484
+ const qs = new URLSearchParams(this._queryParams).toString();
2485
+ if (qs) url += "?".concat(qs);
2486
+ } else {
2487
+ url = "/consume?id=".concat(componentId, "&env=").concat(env);
2488
+ if (usePreview) {
2489
+ url += "&preview=true";
2490
+ }
2491
+ if (this._delivery.minify && !usePreview) {
2492
+ url += "&opt=min";
2493
+ }
2494
+ }
2495
+ const cacheable = this._delivery.cache && !this._staticMode && !usePreview;
2496
+ const storeKey = cacheable ? deliveryStore.key(
2497
+ this.deliveryHost(),
2498
+ componentId,
2499
+ env,
2500
+ usePreview,
2501
+ this._delivery.minify ? "min" : "raw"
2502
+ ) : "";
2503
+ let held = cacheable ? await deliveryStore.get(storeKey) : null;
2504
+ if (held && deliveryStore.fresh(held)) {
2505
+ this._deliveryStats.fromStorage++;
2506
+ this.noteLocalServe(componentId, env);
2507
+ this.variants[cacheKey].resolved = held.config;
2508
+ resolve(held.config);
2509
+ return;
2510
+ }
2511
+ if (held && held.tag) {
2512
+ const checkUrl = "/consume?ids=".concat(componentId, "&env=").concat(env) + (this._delivery.minify ? "&opt=min" : "") + "&have=".concat(encodeURIComponent(held.tag));
2513
+ this._deliveryStats.revalidations++;
2514
+ try {
2515
+ const check = await this.deliveryFetch(checkUrl);
2516
+ if (check.ok) {
2517
+ const body = await check.json();
2518
+ if ((body.unchanged || []).includes(componentId)) {
2519
+ this._deliveryStats.unchanged++;
2520
+ this._deliveryStats.bytesSaved += _CloudRepository.sizeOfHeld(held);
2521
+ held.storedAt = Date.now();
2522
+ held.windowMs = deliveryStore.windowFrom(check.headers) || held.windowMs;
2523
+ await deliveryStore.put(held);
2524
+ this.variants[cacheKey].resolved = held.config;
2525
+ resolve(held.config);
2526
+ return;
2527
+ }
2528
+ const item = (body.items || [])[0];
2529
+ if (item) {
2530
+ const cfg = convertV2VariantToComponentConfig(item);
2531
+ this._deliveryStats.fromNetwork++;
2532
+ await deliveryStore.put({
2533
+ key: storeKey,
2534
+ config: cfg,
2535
+ tag: item.tag || null,
2536
+ storedAt: Date.now(),
2537
+ windowMs: deliveryStore.windowFrom(check.headers),
2538
+ host: this.deliveryHost()
2539
+ });
2540
+ this.variants[cacheKey].resolved = cfg;
2541
+ resolve(cfg);
2542
+ return;
2543
+ }
2544
+ }
2545
+ } catch (e) {
2546
+ }
2547
+ }
2548
+ const res = this._staticMode ? await fetch(url) : await this.deliveryFetch(url);
2549
+ if (!res.ok) {
2550
+ reject(new Error('Failed to load component "'.concat(componentId, '" (').concat(res.status).concat(this._staticMode ? " from ".concat(url) : "", ")")));
2551
+ return;
2552
+ }
2553
+ const json = await res.json();
2554
+ const variant = json.item;
2555
+ if (!variant) {
2556
+ reject(new Error('Component "'.concat(componentId, '" not found')));
2557
+ return;
2558
+ }
2559
+ if (!variant.consume_variant || !variant.consume_variant.length) {
2560
+ reject(new Error('Component "'.concat(componentId, '" has no implementation for environment "').concat(env, '"')));
2561
+ return;
2562
+ }
2563
+ const componentConfig = convertV2VariantToComponentConfig(variant);
2564
+ this._deliveryStats.fromNetwork++;
2565
+ if (cacheable) {
2566
+ await deliveryStore.put({
2567
+ key: storeKey,
2568
+ config: componentConfig,
2569
+ tag: variant.tag || null,
2570
+ storedAt: Date.now(),
2571
+ windowMs: deliveryStore.windowFrom(res.headers),
2572
+ host: this.deliveryHost()
2573
+ });
2574
+ }
2575
+ this.variants[cacheKey].resolved = componentConfig;
2576
+ resolve(componentConfig);
2577
+ } catch (e) {
2578
+ delete this.variants[cacheKey];
2579
+ reject(e);
2318
2580
  }
2319
2581
  }
2320
- });
2321
- setTimeout(() => {
2322
- this.messageToHost(new InitRequest());
2323
- }, 1);
2324
- });
2325
- __publicField(this, "messageToHost", (message, replayTo) => {
2326
- message.direction = MessageDirection.up;
2327
- if (!message.replayToHandler && (replayTo == null ? void 0 : replayTo.handlerUniqueId))
2328
- message.replayToHandler = replayTo.handlerUniqueId;
2329
- window.myop.hostSDK.send(message);
2330
- });
2331
- __publicField(this, "supportedHandlers", [
2332
- new ChangeTextHandler(this.messageToHost, this.components),
2333
- new SetInnerHtmlHandler(this.messageToHost, this.components),
2334
- new BindOnClickHandler(this.messageToHost, this.components),
2335
- new DetectMyopRefsMessageHandler(this.messageToHost, this.components),
2336
- new setAttributeHandler(this.messageToHost, this.components),
2337
- new AddEventListenerHandler(this.messageToHost, this.components),
2338
- new ExecuteScriptHandler(this.messageToHost, this.components),
2339
- new GetElementValueHandler(this.messageToHost, this.components),
2340
- //
2341
- new CreateRefComponentMessageHandler(this.messageToHost, this.components)
2342
- ]);
2343
- __publicField(this, "init", () => {
2344
- });
2582
+ );
2583
+ }
2584
+ return await this.variants[cacheKey];
2345
2585
  }
2346
- };
2347
- defineDynamicImport("WebComponentSDK", WebComponentSDK);
2348
-
2349
- // src/host/embeddedSDK.ts
2350
- var EMBEDDED_SDK_CONTENT = "";
2351
- var HAS_EMBEDDED_SDK = false;
2352
-
2353
- // src/host/loaders/HTMLComponentLoader.ts
2354
- var MYOP_WEB_COMPONENT_MARKER = "<!-- myop-web-component -->";
2355
- var MYOP_WEB_COMPONENT_SCRIPT_ID = "myop-web-component";
2356
- var extractedWebComponentScripts = /* @__PURE__ */ new Map();
2357
- var seen2 = [];
2358
- var sdk;
2359
- var getInitiatedSdk = async () => {
2360
- if (!sdk) {
2361
- sdk = new WebComponentSDK();
2362
- sdk.init();
2586
+ /**
2587
+ * Synchronous version of fetchComponentV2 — returns the config only if
2588
+ * the fetch already completed, null otherwise.
2589
+ *
2590
+ * Uses the same `this.variants` cache that fetchComponentV2/preloadComponents
2591
+ * populate. Each cached Promise is tagged with a `.resolved` property when
2592
+ * it settles — this method just reads that property. No separate cache.
2593
+ *
2594
+ * Why this exists: React Native needs the config at render time to embed it
2595
+ * in the WebView HTML (can't await in useState). If preloadComponents ran
2596
+ * earlier and the fetch completed, this returns the result synchronously,
2597
+ * skipping the WEBVIEW_READY → fetch → inject round trip entirely.
2598
+ */
2599
+ getResolvedConfig(componentId, env, preview) {
2600
+ var _a;
2601
+ const { cacheKey } = this.resolveParams(componentId, env, preview);
2602
+ return ((_a = this.variants[cacheKey]) == null ? void 0 : _a.resolved) || null;
2363
2603
  }
2364
- return sdk;
2365
- };
2366
- function createHTMLElementConstructor(htmlString, ShadowRootMode) {
2367
- return class extends HTMLElement {
2368
- connectedCallback() {
2369
- const mode = ShadowRootMode === ShadowRootModeType.open ? "open" : "closed";
2370
- const shadow = this.attachShadow({ mode });
2371
- getInitiatedSdk().then((sdk2) => {
2372
- sdk2.connectedCallback(this, shadow);
2373
- shadow.innerHTML = htmlString;
2374
- });
2604
+ /**
2605
+ * Resolve which (env, preview) pair — and therefore which cache key — a call
2606
+ * for `componentId` refers to.
2607
+ *
2608
+ * Single source of truth for fetchComponentV2, getResolvedConfig and
2609
+ * hydrateComponent, so a hydrated config always lands on the key a later
2610
+ * fetch will look under.
2611
+ */
2612
+ resolveParams(componentId, environmentIdentifier, preview) {
2613
+ const preloaded = this.preloadedComponents[componentId];
2614
+ const hasExplicitParams = environmentIdentifier !== void 0 || preview !== void 0;
2615
+ let env;
2616
+ let usePreview;
2617
+ if (!hasExplicitParams && preloaded) {
2618
+ env = preloaded.env;
2619
+ usePreview = preloaded.preview;
2620
+ } else {
2621
+ env = environmentIdentifier || this._defaultEnv;
2622
+ const hasEffectiveEnv = environmentIdentifier || this._envExplicitlySet;
2623
+ usePreview = preview === true ? true : preview === false ? false : !hasEffectiveEnv;
2375
2624
  }
2376
- };
2377
- }
2378
- var createCustomWebComponent = (componentName, html, ShadowRootMode) => {
2379
- customElements.define(componentName, createHTMLElementConstructor(html, ShadowRootMode));
2380
- console.log("define('".concat(componentName, "') was called, web component ready to use"));
2625
+ return { env, usePreview, cacheKey: "".concat(componentId, ":").concat(env, ":").concat(usePreview ? "preview" : "live") };
2626
+ }
2627
+ /**
2628
+ * Seed an already-resolved component config into the cache, without any
2629
+ * network request.
2630
+ *
2631
+ * The counterpart to {@link fetchComponentV2}: use it when the config was
2632
+ * resolved somewhere else — most often on a server, then embedded in the
2633
+ * page — so the browser can render the component with no round trip.
2634
+ *
2635
+ * After hydrating, `fetchComponentV2`, `getResolvedConfig` and `isPreloaded`
2636
+ * all answer for this component from memory.
2637
+ *
2638
+ * Pass the same `env` / `preview` the config was resolved with; the defaults
2639
+ * match what a plain `fetchComponentV2(componentId)` would have used.
2640
+ */
2641
+ hydrateComponent(componentId, config, env, preview) {
2642
+ const { env: resolvedEnv, usePreview, cacheKey } = this.resolveParams(componentId, env, preview);
2643
+ const promise = Promise.resolve(config);
2644
+ promise.resolved = config;
2645
+ this.variants[cacheKey] = promise;
2646
+ this.preloadedComponents[componentId] = { env: resolvedEnv, preview: usePreview };
2647
+ }
2648
+ // ============ V1 Methods (Legacy) ============
2649
+ /**
2650
+ * Fetch a v1 component from a flow
2651
+ */
2652
+ async fetchComponentV1(componentId, flowId) {
2653
+ if (flowId) {
2654
+ const flow = await this.fetchFlow(flowId);
2655
+ return flow.components.find((c) => c.type.id === componentId);
2656
+ } else {
2657
+ const flow = await this.fetchAutoFlow(componentId);
2658
+ return flow.components[0];
2659
+ }
2660
+ }
2661
+ async fetchAutoFlow(componentId) {
2662
+ if (!this.userFlows[componentId]) {
2663
+ this.userFlows[componentId] = new Promise(
2664
+ async (resolve, reject) => {
2665
+ try {
2666
+ const res = await fetch(
2667
+ "".concat(this._baseUrl, "/flow?id=").concat(componentId, "&auto=true")
2668
+ );
2669
+ const json = await res.json();
2670
+ resolve(json.item);
2671
+ } catch (e) {
2672
+ delete this.userFlows[componentId];
2673
+ reject(e);
2674
+ }
2675
+ }
2676
+ );
2677
+ }
2678
+ return await this.userFlows[componentId];
2679
+ }
2680
+ async fetchFlow(flowId) {
2681
+ if (!this.userFlows[flowId]) {
2682
+ this.userFlows[flowId] = new Promise(
2683
+ async (resolve, reject) => {
2684
+ try {
2685
+ const res = await fetch(
2686
+ "".concat(this._baseUrl, "/flow?id=").concat(flowId, "&resolve=components")
2687
+ );
2688
+ const json = await res.json();
2689
+ resolve(json.item);
2690
+ } catch (e) {
2691
+ delete this.userFlows[flowId];
2692
+ reject(e);
2693
+ }
2694
+ }
2695
+ );
2696
+ }
2697
+ return await this.userFlows[flowId];
2698
+ }
2699
+ // ============ Backward Compatibility ============
2700
+ /**
2701
+ * @deprecated Use fetchComponentV2 or fetchComponentV1 explicitly
2702
+ * Defaults to v1 behavior for backward compatibility with existing code
2703
+ */
2704
+ async fetchComponent(componentId, flowId) {
2705
+ return this.fetchComponentV1(componentId, flowId);
2706
+ }
2381
2707
  };
2382
- var toWebComponentName = (str) => {
2383
- return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/(\d+)/g, "-$1").toLowerCase();
2708
+ __publicField(_CloudRepository, "_main", null);
2709
+ /** The host every request goes to unless delivery() moved it. Never changes. */
2710
+ __publicField(_CloudRepository, "DEFAULT_HOST", "https://cloud.myop.dev");
2711
+ var CloudRepository = _CloudRepository;
2712
+
2713
+ // src/helpers/cloudRepositoryHelpers.ts
2714
+ var _cloudRepository = CloudRepository.Main;
2715
+ var DELIVERY_HOST = "https://delivery.myop.dev";
2716
+ var delivery = (opts = {}) => {
2717
+ var _a, _b;
2718
+ const wantsLane = opts.minify !== false || opts.cache === true;
2719
+ _cloudRepository.setDelivery({
2720
+ minify: (_a = opts.minify) != null ? _a : false,
2721
+ cache: (_b = opts.cache) != null ? _b : false,
2722
+ host: opts.host !== void 0 ? opts.host : wantsLane ? DELIVERY_HOST : null
2723
+ });
2724
+ return deliveryStats();
2384
2725
  };
2385
- var toCustomElementName = (name) => {
2386
- name = toWebComponentName(name);
2387
- return name.replace(/_/g, "-");
2726
+ var deliveryRefresh = async () => {
2727
+ await _cloudRepository.refreshDelivery();
2728
+ return deliveryStats();
2388
2729
  };
2389
- var HTMLComponentLoader = class extends BaseMyopLoader {
2390
- constructor() {
2391
- super(...arguments);
2392
- __publicField(this, "type", SkinLoaders.HTMLLoader);
2393
- __publicField(this, "load", async (componentDefinition, skin, container, options) => {
2394
- const loaderConfig = skin.loader;
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
- }
2404
- return this.loadExtractedWebComponent(componentDefinition, skin, container, loaderConfig.HTML, options);
2405
- }
2406
- let domId = "myop-comp-".concat(uuidv4());
2407
- let element;
2408
- if (loaderConfig.shadowRootMode === ShadowRootModeType.localFrame) {
2409
- const uniqId = uuidv4();
2410
- const domId2 = "myop-comp-".concat(uniqId);
2411
- let IframeElement = document.createElement("iframe");
2412
- IframeElement.id = domId2;
2413
- if (isolate) {
2414
- IframeElement.setAttribute("sandbox", "allow-scripts allow-forms allow-popups");
2415
- }
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 ");
2417
- if (!container.querySelector('[id^="myop-comp-"]'))
2418
- container.innerHTML = "";
2419
- IframeElement = this.appendChild(container, IframeElement, options);
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
- })();
2435
- let parsedSizeMeta = null;
2436
- {
2437
- const _preParser = new DOMParser();
2438
- const _preDoc = _preParser.parseFromString(loaderConfig.HTML, "text/html");
2439
- const sizeMeta = _preDoc.querySelector('meta[name="myop:size"]');
2440
- if (sizeMeta) {
2441
- try {
2442
- parsedSizeMeta = JSON.parse(sizeMeta.getAttribute("content") || "{}");
2443
- } catch (e) {
2444
- }
2445
- }
2446
- }
2447
- let HTML2Render = loaderConfig.HTML;
2448
- if (options == null ? void 0 : options._inspection) {
2449
- const parser = new DOMParser();
2450
- const _doc = parser.parseFromString(loaderConfig.HTML, "text/html");
2451
- const myop_preview_script = _doc.getElementById("myop_preview");
2452
- myop_preview_script == null ? void 0 : myop_preview_script.removeAttribute("type");
2453
- const temp = _doc.implementation.createHTMLDocument();
2454
- temp.body.innerHTML = "<script>\n const beforeKeysWindow = new Set(Object.keys(window));\n window.myopState = {\n beforeKeysWindow,\n };\n <\/script>";
2455
- const node = temp.body.firstChild;
2456
- if (node && _doc.head) {
2457
- _doc.head.insertBefore(_doc.importNode(node, true), _doc.head.firstChild);
2458
- }
2459
- HTML2Render = "<!DOCTYPE html>" + _doc.documentElement.outerHTML;
2460
- } else if ((options == null ? void 0 : options.data) !== void 0) {
2461
- const parser = new DOMParser();
2462
- const _doc = parser.parseFromString(loaderConfig.HTML, "text/html");
2463
- const myop_preview_script = _doc.getElementById("myop_preview");
2464
- if (myop_preview_script) {
2465
- myop_preview_script.remove();
2466
- HTML2Render = "<!DOCTYPE html>" + _doc.documentElement.outerHTML;
2467
- }
2468
- }
2469
- if (options == null ? void 0 : options.injectCss) {
2470
- const parser = new DOMParser();
2471
- const _doc = parser.parseFromString(HTML2Render, "text/html");
2472
- const styleTag = _doc.createElement("style");
2473
- styleTag.setAttribute("data-myop-injected", "true");
2474
- styleTag.textContent = options.injectCss.replace(/<\s*\/\s*style/gi, "<\\/style");
2475
- (_doc.head || _doc.documentElement).appendChild(styleTag);
2476
- HTML2Render = "<!DOCTYPE html>" + _doc.documentElement.outerHTML;
2477
- }
2478
- doc.writeln(HTML2Render);
2479
- const sdkScript = HAS_EMBEDDED_SDK ? "<script>".concat(EMBEDDED_SDK_CONTENT, "<\/script>") : '<script src="'.concat(window.myop.__ROOT_SDK_PUBLIC_URL__, '"><\/script>');
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>";
2481
- if (!isolate) {
2482
- doc.writeln("".concat(sdkScript).concat(initScript));
2483
- }
2484
- if (!isolate && (options == null ? void 0 : options.data) !== void 0) {
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>";
2486
- const escapedData = JSON.stringify(options.data).replace(/<\/script/gi, "\\u003c/script");
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>");
2488
- doc.writeln(ctaQueueScript + dataScript);
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));
2730
+ var deliveryStats = () => _cloudRepository.deliveryStats();
2731
+ var deliveryOff = () => {
2732
+ _cloudRepository.setDelivery({ minify: false, cache: false, host: null });
2733
+ return deliveryStats();
2734
+ };
2735
+
2736
+ // src/webcomponent/messageHandlers/BaseWebComponentMessageHandler.ts
2737
+ var BaseWebComponentMessageHandler = class extends BaseContextMessageHandler {
2738
+ constructor(messageToHost, context) {
2739
+ super(messageToHost);
2740
+ this.context = context;
2741
+ __publicField(this, "executor", (event) => {
2742
+ if (event.destination) {
2743
+ const destination = event.destination;
2744
+ if (this.context[destination].context) {
2745
+ const _messageToHost = (message, replayTo) => {
2746
+ this.messageToHost(__spreadProps(__spreadValues({}, message), {
2747
+ source: event.destination ? event.destination : event.source,
2748
+ destination: event.source ? event.source : event.destination
2749
+ }), replayTo);
2750
+ };
2751
+ return this.innerExecutor(event, this.context[destination].context, _messageToHost);
2752
+ } else {
2753
+ debugger;
2493
2754
  }
2494
- doc.close();
2495
- const comp = new MyopIframeComponent(componentDefinition, skin, container, IframeElement, options);
2496
- if (isolate) comp.enableIsolation();
2497
- comp.sizeMeta = parsedSizeMeta;
2498
- comp.initiated().then(() => {
2499
- if ((options == null ? void 0 : options.autoSize) === false) {
2500
- return;
2501
- }
2502
- let shown = false;
2503
- comp.observeAutoSize({
2504
- forceAutoSize: true,
2505
- onSizeChange: () => {
2506
- if (!shown && !(options == null ? void 0 : options.hidden)) {
2507
- shown = true;
2508
- comp.show();
2509
- }
2510
- }
2511
- });
2512
- });
2513
- return comp;
2514
- }
2515
- if (loaderConfig.shadowRootMode === ShadowRootModeType.none) {
2516
- const template = document.createElement("template");
2517
- template.innerHTML = loaderConfig.HTML;
2518
- element = template.content.firstElementChild;
2519
- getInitiatedSdk().then((sdk2) => {
2520
- sdk2.connectedCallback(element, element);
2521
- });
2522
2755
  } else {
2523
- const customElementName = toCustomElementName(componentDefinition.name + skin.id);
2524
- if (!seen2.includes(customElementName)) {
2525
- createCustomWebComponent(customElementName, loaderConfig.HTML, loaderConfig.shadowRootMode);
2526
- seen2.push(customElementName);
2527
- }
2528
- element = document.createElement(customElementName);
2529
- }
2530
- if (!container.querySelector('[id^="myop-comp-"]'))
2531
- container.innerHTML = "";
2532
- element.id = domId;
2533
- if (options == null ? void 0 : options.hidden) {
2534
- element.style.opacity = "0";
2535
- element.style.position = "absolute";
2536
- element.style.height = "0";
2537
- element.style.width = "0";
2538
- element.style.pointerEvents = "none";
2539
- element.style.visibility = "hidden";
2756
+ debugger;
2540
2757
  }
2541
- this.appendChild(container, element, options);
2542
- return new MyopWebComponent(componentDefinition, skin, container, element, options);
2543
2758
  });
2544
2759
  }
2545
- /**
2546
- * Detect if HTML is a Myop Web Component (starts with marker comment)
2547
- */
2548
- isMyopWebComponent(html) {
2549
- return html.trimStart().startsWith(MYOP_WEB_COMPONENT_MARKER);
2760
+ };
2761
+
2762
+ // src/consts.ts
2763
+ var myopAttributes = {
2764
+ id: "myop-id"
2765
+ };
2766
+
2767
+ // src/common/messageHandlers/helpers.ts
2768
+ var getElementsByRef = (ref, el) => {
2769
+ return el.querySelectorAll("[".concat(myopAttributes.id, "='").concat(ref.refConfig.selector, "']"));
2770
+ };
2771
+
2772
+ // src/webcomponent/messageHandlers/bindOnClickHandler.ts
2773
+ var BindOnClickHandler = class extends BaseWebComponentMessageHandler {
2774
+ constructor() {
2775
+ super(...arguments);
2776
+ __publicField(this, "messageType", MyopMessages.BindClickMessage);
2777
+ __publicField(this, "innerExecutor", (event, shadowRootRef, messageToHost) => {
2778
+ const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
2779
+ const cleanupTasks = [];
2780
+ items.forEach((item) => {
2781
+ const handler = () => {
2782
+ messageToHost(new ClickReplayMessage(event.handlerUniqueId));
2783
+ };
2784
+ item.addEventListener("click", handler);
2785
+ cleanupTasks.push(() => {
2786
+ item.removeEventListener("click", handler);
2787
+ });
2788
+ });
2789
+ return () => {
2790
+ cleanupTasks.forEach((task) => task());
2791
+ };
2792
+ });
2550
2793
  }
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" };
2794
+ };
2795
+
2796
+ // src/webcomponent/messageHandlers/changeTextHandler.ts
2797
+ var ChangeTextHandler = class extends BaseWebComponentMessageHandler {
2798
+ constructor() {
2799
+ super(...arguments);
2800
+ __publicField(this, "messageType", MyopMessages.ChangeTextMessage);
2801
+ __publicField(this, "innerExecutor", (event, shadowRootRef) => {
2802
+ const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
2803
+ items.forEach((item) => {
2804
+ item.textContent = event.content;
2805
+ });
2806
+ });
2563
2807
  }
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>");
2808
+ };
2809
+
2810
+ // src/webcomponent/shadowRootRef.ts
2811
+ var ShadowRootRef = class extends RootRef {
2812
+ constructor(container, shadowRoot) {
2813
+ super(container, shadowRoot);
2814
+ this.container = container;
2815
+ this.shadowRoot = shadowRoot;
2586
2816
  }
2587
- /**
2588
- * Extract the web component script content from HTML
2589
- */
2590
- extractWebComponentScript(html) {
2591
- const parser = new DOMParser();
2592
- const doc = parser.parseFromString(html, "text/html");
2593
- const script = doc.getElementById(MYOP_WEB_COMPONENT_SCRIPT_ID);
2594
- return (script == null ? void 0 : script.textContent) || null;
2817
+ };
2818
+
2819
+ // src/webcomponent/messageHandlers/DetectMyopRefsMessageHandler.ts
2820
+ var DetectMyopRefsMessageHandler = class extends BaseWebComponentMessageHandler {
2821
+ constructor() {
2822
+ super(...arguments);
2823
+ __publicField(this, "innerExecutor", (event, shadowRootRef) => {
2824
+ const allMyopItems = shadowRootRef.shadowRoot.querySelectorAll("[".concat(myopAttributes.id, "]"));
2825
+ let myopRefs = [];
2826
+ allMyopItems.forEach((item) => {
2827
+ const myopId = item.getAttribute(myopAttributes.id);
2828
+ if (myopId) {
2829
+ myopRefs.push(new MyopElementRef(myopId, item.tagName, item.getBoundingClientRect(), item.offsetTop, item.offsetLeft));
2830
+ }
2831
+ });
2832
+ this.messageToHost(new DetectedMyopRefsMessage(event.handlerUniqueId, myopRefs));
2833
+ });
2834
+ __publicField(this, "messageType", MyopMessages.DetectMyopRefsMessage);
2595
2835
  }
2596
- /**
2597
- * Execute the web component script on the host document.
2598
- * Returns the custom element tag name this script registered.
2599
- */
2600
- executeWebComponentScript(scriptContent, scriptId) {
2601
- const cachedTagName = extractedWebComponentScripts.get(scriptId);
2602
- if (cachedTagName) {
2603
- console.log("[MyopWebComponent] Script already executed for ".concat(scriptId, ", reusing <").concat(cachedTagName, ">"));
2604
- return cachedTagName;
2605
- }
2606
- const script = document.createElement("script");
2607
- script.textContent = scriptContent;
2608
- script.id = "myop-extracted-".concat(scriptId);
2609
- document.head.appendChild(script);
2610
- const tagName = window.__MYOP_TAG_NAME__;
2611
- if (tagName) {
2612
- extractedWebComponentScripts.set(scriptId, tagName);
2613
- }
2614
- console.log("[MyopWebComponent] Executed web component script: ".concat(scriptId, " -> <").concat(tagName, ">"));
2615
- return tagName;
2836
+ };
2837
+
2838
+ // src/webcomponent/messageHandlers/setAttributeHandler.ts
2839
+ var setAttributeHandler = class extends BaseWebComponentMessageHandler {
2840
+ constructor() {
2841
+ super(...arguments);
2842
+ __publicField(this, "messageType", MyopMessages.SetAttributeMessage);
2843
+ __publicField(this, "innerExecutor", (event, shadowRootRef) => {
2844
+ const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
2845
+ items.forEach((item) => {
2846
+ item.setAttribute(event.name, event.value);
2847
+ });
2848
+ });
2616
2849
  }
2617
- /**
2618
- * Load a Myop Web Component (extracted and run on host document)
2619
- */
2620
- async loadExtractedWebComponent(componentDefinition, skin, container, html, options) {
2621
- const scriptContent = this.extractWebComponentScript(html);
2622
- if (!scriptContent) {
2623
- throw new Error('[MyopWebComponent] No <script id="myop-web-component"> found in HTML');
2624
- }
2625
- const scriptId = "".concat(componentDefinition.id, "-").concat(skin.id);
2626
- const tagName = this.executeWebComponentScript(scriptContent, scriptId);
2627
- if (!tagName) {
2628
- throw new Error("[MyopWebComponent] Script did not set window.__MYOP_TAG_NAME__");
2629
- }
2630
- const domId = "myop-comp-".concat(uuidv4());
2631
- const element = document.createElement(tagName);
2632
- element.id = domId;
2633
- if (options == null ? void 0 : options.hidden) {
2634
- element.style.opacity = "0";
2635
- element.style.position = "absolute";
2636
- element.style.height = "0";
2637
- element.style.width = "0";
2638
- element.style.pointerEvents = "none";
2639
- element.style.visibility = "hidden";
2640
- }
2641
- if (!container.querySelector('[id^="myop-comp-"]')) {
2642
- container.innerHTML = "";
2643
- }
2644
- this.appendChild(container, element, options);
2645
- const component = new MyopExtractedWebComponent(
2646
- componentDefinition,
2647
- skin,
2648
- container,
2649
- element,
2650
- tagName,
2651
- options
2652
- );
2653
- if ((options == null ? void 0 : options.data) !== void 0) {
2654
- component.initWithData(options.data);
2655
- }
2656
- console.log("[MyopWebComponent] Loaded <".concat(tagName, "> into container"));
2657
- return component;
2850
+ };
2851
+
2852
+ // src/webcomponent/messageHandlers/addEventListenerHandler.ts
2853
+ var AddEventListenerHandler = class extends BaseWebComponentMessageHandler {
2854
+ constructor() {
2855
+ super(...arguments);
2856
+ __publicField(this, "messageType", MyopMessages.AddEventListenerMessage);
2857
+ __publicField(this, "innerExecutor", (event, shadowRootRef, messageToHost) => {
2858
+ const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
2859
+ const cleanupTasks = [];
2860
+ items.forEach((item) => {
2861
+ const handler = (e) => {
2862
+ messageToHost(new EventListenerCallbackMessage(event.handlerUniqueId, makeSerializable(e, event.serializableSkeleton)));
2863
+ };
2864
+ item.addEventListener(event.type, handler);
2865
+ cleanupTasks.push(() => {
2866
+ item.removeEventListener(event.type, handler);
2867
+ });
2868
+ });
2869
+ return () => {
2870
+ cleanupTasks.forEach((task) => task());
2871
+ };
2872
+ });
2658
2873
  }
2659
2874
  };
2660
2875
 
2661
- // src/helpers/CloudRepository.ts
2662
- var convertV2VariantToComponentConfig = (config) => {
2663
- return {
2664
- instance: {
2665
- id: "auto",
2666
- componentId: config.componentId,
2667
- componentName: config.name,
2668
- skinSelector: {
2669
- type: "Dedicated",
2670
- skin: {
2671
- id: "skin_auto_v2_converted"
2672
- }
2673
- }
2674
- },
2675
- type: {
2676
- id: config.id,
2677
- name: config.name,
2678
- description: config.description,
2679
- props: [
2680
- {
2681
- id: "in_auto_v2_converted",
2682
- name: "myop_init_interface",
2683
- type: "any",
2684
- behavior: {
2685
- type: PropConfigBehaviorTypes.code
2876
+ // src/webcomponent/messageHandlers/CreateRefComponentMessageHandler.ts
2877
+ var CreateRefComponentMessageHandler = class extends BaseWebComponentMessageHandler {
2878
+ constructor() {
2879
+ super(...arguments);
2880
+ __publicField(this, "messageType", MyopMessages.CreateRefComponentMessage);
2881
+ __publicField(this, "innerExecutor", (event, shadowRootRef, messageToHost) => {
2882
+ const createRef = async () => {
2883
+ const allItems = shadowRootRef.shadowRoot.querySelectorAll("[".concat(myopAttributes.id, "='").concat(event.refConfig.selector, "']"));
2884
+ if (allItems.length === 1) {
2885
+ const hostSDK2 = HostSDK.Instance();
2886
+ const refComponent = hostSDK2.components.find((c) => c.id === event.options.id);
2887
+ if (refComponent) {
2888
+ refComponent.dispose();
2889
+ } else {
2686
2890
  }
2687
- },
2688
- {
2689
- id: "out_auto_v2_converted",
2690
- name: "myop_cta_handler",
2691
- type: "any",
2692
- behavior: {
2693
- type: PropConfigBehaviorTypes.code
2891
+ const index = hostSDK2.components.indexOf(refComponent);
2892
+ if (index !== -1) {
2893
+ hostSDK2.components.splice(index, 1);
2894
+ } else {
2694
2895
  }
2896
+ const implementationComponent = await hostSDK2.loadComponent(
2897
+ event.nestedComponentConfig,
2898
+ allItems.item(0),
2899
+ event.options
2900
+ );
2901
+ const nestedRefConfig = [];
2902
+ Object.keys(implementationComponent.refs).forEach((refName) => {
2903
+ let ref = implementationComponent.refs[refName];
2904
+ ref = ref.__nonProxied || ref;
2905
+ if (ref.componentDefinition) {
2906
+ nestedRefConfig.push({
2907
+ refName,
2908
+ componentDefinitionId: ref.componentDefinition.id
2909
+ });
2910
+ }
2911
+ });
2912
+ messageToHost(new RefComponentCreatedMessage(event.handlerUniqueId, nestedRefConfig));
2913
+ } else {
2914
+ console.error("CreateRefComponentMessageHandler - DOM element not found");
2915
+ this.messageToHost(new RefComponentCreatedMessage(event.handlerUniqueId, [], true));
2916
+ debugger;
2695
2917
  }
2696
- ],
2697
- refs: [],
2698
- skins: [
2699
- {
2700
- id: "skin_auto_v2_converted",
2701
- name: "auto_v2_converted",
2702
- description: "",
2703
- //TODO : handle empty :
2704
- // @ts-ignore
2705
- loader: config.consume_variant[0].loader
2706
- }
2707
- ],
2708
- defaultSkin: 0
2709
- },
2710
- name: config.name
2711
- };
2712
- };
2713
- var GLOBAL_KEY = "__MYOP_CLOUD_REPOSITORY_MAIN__";
2714
- var getGlobalMain = () => {
2715
- if (typeof window !== "undefined") {
2716
- return window[GLOBAL_KEY];
2717
- }
2718
- if (typeof globalThis !== "undefined") {
2719
- return globalThis[GLOBAL_KEY];
2918
+ };
2919
+ createRef().then();
2920
+ });
2720
2921
  }
2721
- return void 0;
2722
2922
  };
2723
- var setGlobalMain = (instance) => {
2724
- if (typeof window !== "undefined") {
2725
- window[GLOBAL_KEY] = instance;
2726
- }
2727
- if (typeof globalThis !== "undefined") {
2728
- globalThis[GLOBAL_KEY] = instance;
2923
+
2924
+ // src/common/messageHandlers/executeScriptHandler.ts
2925
+ var ExecuteScriptHandlerExecutor = (event, replier, rootRef) => {
2926
+ const __scriptInputs = event.scriptInputs ? event.scriptInputs : {};
2927
+ __scriptInputs.makeSerializable = makeSerializable;
2928
+ __scriptInputs.send = replier;
2929
+ __scriptInputs.rootRef = rootRef;
2930
+ __scriptInputs.__scriptInputs = __scriptInputs;
2931
+ const dynamicFunction = new Function("return (".concat(event.script, ")(...arguments)"));
2932
+ const ret = dynamicFunction(__scriptInputs);
2933
+ replier(ret);
2934
+ };
2935
+
2936
+ // src/webcomponent/messageHandlers/executeScriptHandler.ts
2937
+ var ExecuteScriptHandler = class extends BaseWebComponentMessageHandler {
2938
+ constructor() {
2939
+ super(...arguments);
2940
+ __publicField(this, "messageType", MyopMessages.ExecuteScriptMessage);
2941
+ __publicField(this, "innerExecutor", (event, shadowRootRef, messageToHost) => {
2942
+ const replier = (data) => {
2943
+ messageToHost(new ExecuteScriptReplyMessage(event.handlerUniqueId, data));
2944
+ };
2945
+ ExecuteScriptHandlerExecutor(event, replier, shadowRootRef);
2946
+ });
2729
2947
  }
2730
2948
  };
2731
- var _CloudRepository = class _CloudRepository {
2732
- constructor(_baseUrl = "https://cloud.myop.dev") {
2733
- this._baseUrl = _baseUrl;
2734
- // v2 cache - keyed by componentId:env:preview|live
2735
- // Each Promise is tagged with a `resolved` property after settling (see fetchComponentV2).
2736
- __publicField(this, "variants", {});
2737
- // Track which components were preloaded and with what params
2738
- // Key: componentId, Value: { env, preview }
2739
- __publicField(this, "preloadedComponents", {});
2740
- // v1 cache
2741
- __publicField(this, "userFlows", {});
2742
- __publicField(this, "_defaultEnv", "production");
2743
- __publicField(this, "_envExplicitlySet", false);
2744
- __publicField(this, "_staticMode", false);
2745
- __publicField(this, "_queryParams", {});
2949
+
2950
+ // src/webcomponent/messageHandlers/GetElementValueHandler.ts
2951
+ var getInputValue = (element) => {
2952
+ if (!element) return null;
2953
+ if (element.tagName === "FORM") {
2954
+ const formData = new FormData(element);
2955
+ const dataObject = {
2956
+ formData: {},
2957
+ unmappedData: []
2958
+ };
2959
+ const elements = element.querySelectorAll("input, select, textarea");
2960
+ let autoNameIndexer = -1;
2961
+ elements.forEach((element2) => {
2962
+ if (typeof element2.value === "string") {
2963
+ const myopId = element2.getAttribute(myopAttributes.id);
2964
+ let key = element2.getAttribute("name");
2965
+ const nodeData = {
2966
+ id: element2.id,
2967
+ name: key,
2968
+ value: getInputValue(element2),
2969
+ required: element2.required,
2970
+ validity: makeSerializable(element2.validity, true),
2971
+ myopId
2972
+ };
2973
+ if (!key) {
2974
+ dataObject.unmappedData.push(nodeData);
2975
+ } else {
2976
+ if (dataObject.formData[key]) {
2977
+ if (dataObject.formData[key].value) {
2978
+ dataObject.unmappedData.push(nodeData);
2979
+ } else {
2980
+ dataObject.unmappedData.push(dataObject.formData[key]);
2981
+ dataObject.formData[key] = nodeData;
2982
+ }
2983
+ } else {
2984
+ dataObject.formData[key] = nodeData;
2985
+ }
2986
+ }
2987
+ }
2988
+ });
2989
+ return dataObject;
2746
2990
  }
2747
- static get Main() {
2748
- const globalMain = getGlobalMain();
2749
- if (globalMain) {
2750
- return globalMain;
2751
- }
2752
- if (!_CloudRepository._main) {
2753
- _CloudRepository._main = new _CloudRepository();
2754
- setGlobalMain(_CloudRepository._main);
2755
- }
2756
- return _CloudRepository._main;
2991
+ if (element.type === "checkbox" || element.type === "radio") {
2992
+ return element.checked ? element.value : null;
2757
2993
  }
2758
- /**
2759
- * Enable static mode for self-hosted component registries.
2760
- * In static mode, URLs are constructed as file paths instead of query params:
2761
- * ${baseUrl}/components/${componentId}/${env}.json
2762
- */
2763
- enableStaticMode() {
2764
- this._staticMode = true;
2994
+ if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
2995
+ return element.value;
2765
2996
  }
2766
- /**
2767
- * Set query parameters to append to all fetch URLs (e.g. for CDN cache busting).
2768
- * Example: `setQueryParams({ lastupdate: '11112026' })`
2769
- */
2770
- setQueryParams(params) {
2771
- this._queryParams = params;
2997
+ if (element.tagName === "SELECT") {
2998
+ return element.value;
2772
2999
  }
2773
- /**
2774
- * Set the default environment for this CloudRepository instance
2775
- */
2776
- setEnvironment(env) {
2777
- this._defaultEnv = env;
2778
- this._envExplicitlySet = true;
3000
+ if (element.isContentEditable) {
3001
+ return element.innerText || element.textContent;
2779
3002
  }
2780
- /**
2781
- * Get the current default environment
2782
- */
2783
- getDefaultEnvironment() {
2784
- return this._defaultEnv;
3003
+ return null;
3004
+ };
3005
+ var GetElementValueHandler = class extends BaseWebComponentMessageHandler {
3006
+ constructor() {
3007
+ super(...arguments);
3008
+ __publicField(this, "messageType", MyopMessages.GetElementValueMessage);
3009
+ __publicField(this, "innerExecutor", (event, shadowRootRef, messageToHost) => {
3010
+ const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
3011
+ items.forEach((item) => {
3012
+ messageToHost(new ElementValueReplayMessage(getInputValue(item)), event);
3013
+ });
3014
+ });
2785
3015
  }
2786
- // ============ V2 Methods (Default) ============
2787
- /**
2788
- * Check if a component is already cached/preloaded (v2)
2789
- * If env and preview are not provided, checks if ANY version is preloaded
2790
- */
2791
- isPreloaded(componentId, env, preview) {
2792
- if (env !== void 0 || preview !== void 0) {
2793
- const cacheKey = "".concat(componentId, ":").concat(env || this._defaultEnv, ":").concat(preview ? "preview" : "live");
2794
- return cacheKey in this.variants;
2795
- }
2796
- return componentId in this.preloadedComponents;
3016
+ };
3017
+
3018
+ // src/webcomponent/messageHandlers/setInnerHtmlHandler.ts
3019
+ var SetInnerHtmlHandler = class extends BaseWebComponentMessageHandler {
3020
+ constructor() {
3021
+ super(...arguments);
3022
+ __publicField(this, "messageType", MyopMessages.SetInnerHtml);
3023
+ __publicField(this, "innerExecutor", (event, shadowRootRef) => {
3024
+ const items = getElementsByRef(event.ref, shadowRootRef.shadowRoot);
3025
+ items.forEach((item) => {
3026
+ item.innerHTML = event.content;
3027
+ });
3028
+ });
2797
3029
  }
2798
- /**
2799
- * Get the preloaded params for a component (if preloaded)
2800
- * Returns undefined if not preloaded
2801
- */
2802
- getPreloadedParams(componentId) {
2803
- return this.preloadedComponents[componentId];
3030
+ };
3031
+
3032
+ // src/webcomponent/WebComponentSDK.ts
3033
+ var WebComponentSDK = class extends BaseMyopSDK {
3034
+ constructor() {
3035
+ super(...arguments);
3036
+ __publicField(this, "alwaysPassEnvelopesToHost", true);
3037
+ //when new web component created.
3038
+ __publicField(this, "connectedCallback", (container, shadow) => {
3039
+ container.addEventListener(myopWebcomponentConsts.webcomponent_message_key, (e) => {
3040
+ const eventContent = e.data ? e.data : e.detail;
3041
+ if (!eventContent || !eventContent.myop) {
3042
+ debugger;
3043
+ throw new Error("recvied webcomponent_message with wrong type");
3044
+ } else {
3045
+ const message = eventContent;
3046
+ this.handleIncomeMessages(e);
3047
+ if (message.messageType === MyopMessages.InitMessage) {
3048
+ const newComponentId = message.content.id;
3049
+ this.components[newComponentId].context = new ShadowRootRef(container, shadow);
3050
+ }
3051
+ }
3052
+ });
3053
+ setTimeout(() => {
3054
+ this.messageToHost(new InitRequest());
3055
+ }, 1);
3056
+ });
3057
+ __publicField(this, "messageToHost", (message, replayTo) => {
3058
+ message.direction = MessageDirection.up;
3059
+ if (!message.replayToHandler && (replayTo == null ? void 0 : replayTo.handlerUniqueId))
3060
+ message.replayToHandler = replayTo.handlerUniqueId;
3061
+ window.myop.hostSDK.send(message);
3062
+ });
3063
+ __publicField(this, "supportedHandlers", [
3064
+ new ChangeTextHandler(this.messageToHost, this.components),
3065
+ new SetInnerHtmlHandler(this.messageToHost, this.components),
3066
+ new BindOnClickHandler(this.messageToHost, this.components),
3067
+ new DetectMyopRefsMessageHandler(this.messageToHost, this.components),
3068
+ new setAttributeHandler(this.messageToHost, this.components),
3069
+ new AddEventListenerHandler(this.messageToHost, this.components),
3070
+ new ExecuteScriptHandler(this.messageToHost, this.components),
3071
+ new GetElementValueHandler(this.messageToHost, this.components),
3072
+ //
3073
+ new CreateRefComponentMessageHandler(this.messageToHost, this.components)
3074
+ ]);
3075
+ __publicField(this, "init", () => {
3076
+ });
2804
3077
  }
2805
- /**
2806
- * Resolve a component config: fetch it once, then serve it from this
2807
- * repository's cache.
2808
- *
2809
- * This is the name to use. `fetchComponentV2` is the same method under its
2810
- * versioned name and stays for backward compatibility — note that the
2811
- * unversioned `fetchComponent` is a *deprecated v1* API and is NOT this.
2812
- *
2813
- * Completes the trio with {@link getResolvedConfig} (synchronous read of an
2814
- * already-resolved config) and {@link hydrateComponent} (seed one you
2815
- * already hold).
2816
- *
2817
- * Prefer the module-level `preloadComponents([id])` in app code; reach for
2818
- * this when you need an isolated repository instance whose cache lifetime
2819
- * you control — a server with its own TTL, for example.
2820
- */
2821
- async resolveComponent(componentId, env, preview) {
2822
- return this.fetchComponentV2(componentId, env, preview);
3078
+ };
3079
+ defineDynamicImport("WebComponentSDK", WebComponentSDK);
3080
+
3081
+ // src/host/embeddedSDK.ts
3082
+ var EMBEDDED_SDK_CONTENT = "";
3083
+ var HAS_EMBEDDED_SDK = false;
3084
+
3085
+ // src/host/loaders/HTMLComponentLoader.ts
3086
+ var MYOP_WEB_COMPONENT_MARKER = "<!-- myop-web-component -->";
3087
+ var MYOP_WEB_COMPONENT_SCRIPT_ID = "myop-web-component";
3088
+ var extractedWebComponentScripts = /* @__PURE__ */ new Map();
3089
+ var seen2 = [];
3090
+ var sdk;
3091
+ var getInitiatedSdk = async () => {
3092
+ if (!sdk) {
3093
+ sdk = new WebComponentSDK();
3094
+ sdk.init();
2823
3095
  }
2824
- /**
2825
- * Fetch a v2 component config
2826
- * If env/preview not specified and component was preloaded, uses preloaded params
2827
- *
2828
- * @see resolveComponent — the unversioned name for this method
2829
- */
2830
- async fetchComponentV2(componentId, environmentIdentifier, preview) {
2831
- const { env, usePreview, cacheKey } = this.resolveParams(componentId, environmentIdentifier, preview);
2832
- console.log("[CloudRepository] fetchComponentV2", {
2833
- componentId: componentId.slice(0, 8) + "...",
2834
- env,
2835
- usePreview,
2836
- cacheKey,
2837
- cached: cacheKey in this.variants
2838
- });
2839
- if (!this.variants[cacheKey]) {
2840
- if (!this.preloadedComponents[componentId]) {
2841
- this.preloadedComponents[componentId] = { env, preview: usePreview };
3096
+ return sdk;
3097
+ };
3098
+ function createHTMLElementConstructor(htmlString, ShadowRootMode) {
3099
+ return class extends HTMLElement {
3100
+ connectedCallback() {
3101
+ const mode = ShadowRootMode === ShadowRootModeType.open ? "open" : "closed";
3102
+ const shadow = this.attachShadow({ mode });
3103
+ getInitiatedSdk().then((sdk2) => {
3104
+ sdk2.connectedCallback(this, shadow);
3105
+ shadow.innerHTML = htmlString;
3106
+ });
3107
+ }
3108
+ };
3109
+ }
3110
+ var createCustomWebComponent = (componentName, html, ShadowRootMode) => {
3111
+ customElements.define(componentName, createHTMLElementConstructor(html, ShadowRootMode));
3112
+ console.log("define('".concat(componentName, "') was called, web component ready to use"));
3113
+ };
3114
+ var toWebComponentName = (str) => {
3115
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/(\d+)/g, "-$1").toLowerCase();
3116
+ };
3117
+ var toCustomElementName = (name) => {
3118
+ name = toWebComponentName(name);
3119
+ return name.replace(/_/g, "-");
3120
+ };
3121
+ var HTMLComponentLoader = class extends BaseMyopLoader {
3122
+ constructor() {
3123
+ super(...arguments);
3124
+ __publicField(this, "type", SkinLoaders.HTMLLoader);
3125
+ __publicField(this, "load", async (componentDefinition, skin, container, options) => {
3126
+ const loaderConfig = skin.loader;
3127
+ const isWC = this.isMyopWebComponent(loaderConfig.HTML);
3128
+ const { mode, isolate } = await this.resolveRenderMode(componentDefinition, skin, loaderConfig, isWC, options);
3129
+ if (mode === false) {
3130
+ throw new Error('[Myop] Rendering blocked by render policy for component "'.concat(componentDefinition.id, '"'));
2842
3131
  }
2843
- this.variants[cacheKey] = new Promise(
2844
- async (resolve, reject) => {
2845
- try {
2846
- let url;
2847
- if (this._staticMode) {
2848
- const file = usePreview ? "preview" : env;
2849
- url = "".concat(this._baseUrl, "/components/").concat(componentId, "/").concat(file, ".json");
2850
- const qs = new URLSearchParams(this._queryParams).toString();
2851
- if (qs) url += "?".concat(qs);
2852
- } else {
2853
- url = "".concat(this._baseUrl, "/consume?id=").concat(componentId, "&env=").concat(env);
2854
- if (usePreview) {
2855
- url += "&preview=true";
2856
- }
2857
- }
2858
- const res = await fetch(url);
2859
- if (!res.ok) {
2860
- reject(new Error('Failed to load component "'.concat(componentId, '" (').concat(res.status).concat(this._staticMode ? " from ".concat(url) : "", ")")));
2861
- return;
2862
- }
2863
- const json = await res.json();
2864
- const variant = json.item;
2865
- if (!variant) {
2866
- reject(new Error('Component "'.concat(componentId, '" not found')));
2867
- return;
3132
+ if (isWC) {
3133
+ if (mode !== "webComponent") {
3134
+ throw new Error('[Myop] Web-component rendering denied by render policy for component "'.concat(componentDefinition.id, '"'));
3135
+ }
3136
+ return this.loadExtractedWebComponent(componentDefinition, skin, container, loaderConfig.HTML, options);
3137
+ }
3138
+ let domId = "myop-comp-".concat(uuidv4());
3139
+ let element;
3140
+ if (loaderConfig.shadowRootMode === ShadowRootModeType.localFrame) {
3141
+ const uniqId = uuidv4();
3142
+ const domId2 = "myop-comp-".concat(uniqId);
3143
+ let IframeElement = document.createElement("iframe");
3144
+ IframeElement.id = domId2;
3145
+ if (isolate) {
3146
+ IframeElement.setAttribute("sandbox", "allow-scripts allow-forms allow-popups");
3147
+ }
3148
+ 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 ");
3149
+ if (!container.querySelector('[id^="myop-comp-"]'))
3150
+ container.innerHTML = "";
3151
+ IframeElement = this.appendChild(container, IframeElement, options);
3152
+ const __srcParts = [];
3153
+ const doc = isolate ? {
3154
+ open() {
3155
+ },
3156
+ writeln(s) {
3157
+ __srcParts.push(s);
3158
+ },
3159
+ close() {
3160
+ IframeElement.srcdoc = __srcParts.join("\n");
3161
+ }
3162
+ } : (() => {
3163
+ const d = IframeElement.contentDocument || IframeElement.contentWindow.document;
3164
+ d.open();
3165
+ return d;
3166
+ })();
3167
+ let parsedSizeMeta = null;
3168
+ {
3169
+ const _preParser = new DOMParser();
3170
+ const _preDoc = _preParser.parseFromString(loaderConfig.HTML, "text/html");
3171
+ const sizeMeta = _preDoc.querySelector('meta[name="myop:size"]');
3172
+ if (sizeMeta) {
3173
+ try {
3174
+ parsedSizeMeta = JSON.parse(sizeMeta.getAttribute("content") || "{}");
3175
+ } catch (e) {
2868
3176
  }
2869
- if (!variant.consume_variant || !variant.consume_variant.length) {
2870
- reject(new Error('Component "'.concat(componentId, '" has no implementation for environment "').concat(env, '"')));
2871
- return;
3177
+ }
3178
+ }
3179
+ let HTML2Render = loaderConfig.HTML;
3180
+ if (options == null ? void 0 : options._inspection) {
3181
+ const parser = new DOMParser();
3182
+ const _doc = parser.parseFromString(loaderConfig.HTML, "text/html");
3183
+ const myop_preview_script = _doc.getElementById("myop_preview");
3184
+ myop_preview_script == null ? void 0 : myop_preview_script.removeAttribute("type");
3185
+ const temp = _doc.implementation.createHTMLDocument();
3186
+ temp.body.innerHTML = "<script>\n const beforeKeysWindow = new Set(Object.keys(window));\n window.myopState = {\n beforeKeysWindow,\n };\n <\/script>";
3187
+ const node = temp.body.firstChild;
3188
+ if (node && _doc.head) {
3189
+ _doc.head.insertBefore(_doc.importNode(node, true), _doc.head.firstChild);
3190
+ }
3191
+ HTML2Render = "<!DOCTYPE html>" + _doc.documentElement.outerHTML;
3192
+ } else if ((options == null ? void 0 : options.data) !== void 0) {
3193
+ const parser = new DOMParser();
3194
+ const _doc = parser.parseFromString(loaderConfig.HTML, "text/html");
3195
+ const myop_preview_script = _doc.getElementById("myop_preview");
3196
+ if (myop_preview_script) {
3197
+ myop_preview_script.remove();
3198
+ HTML2Render = "<!DOCTYPE html>" + _doc.documentElement.outerHTML;
3199
+ }
3200
+ }
3201
+ if (options == null ? void 0 : options.injectCss) {
3202
+ const parser = new DOMParser();
3203
+ const _doc = parser.parseFromString(HTML2Render, "text/html");
3204
+ const styleTag = _doc.createElement("style");
3205
+ styleTag.setAttribute("data-myop-injected", "true");
3206
+ styleTag.textContent = options.injectCss.replace(/<\s*\/\s*style/gi, "<\\/style");
3207
+ (_doc.head || _doc.documentElement).appendChild(styleTag);
3208
+ HTML2Render = "<!DOCTYPE html>" + _doc.documentElement.outerHTML;
3209
+ }
3210
+ doc.writeln(HTML2Render);
3211
+ const sdkScript = HAS_EMBEDDED_SDK ? "<script>".concat(EMBEDDED_SDK_CONTENT, "<\/script>") : '<script src="'.concat(window.myop.__ROOT_SDK_PUBLIC_URL__, '"><\/script>');
3212
+ 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>";
3213
+ if (!isolate) {
3214
+ doc.writeln("".concat(sdkScript).concat(initScript));
3215
+ }
3216
+ if (!isolate && (options == null ? void 0 : options.data) !== void 0) {
3217
+ 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>";
3218
+ const escapedData = JSON.stringify(options.data).replace(/<\/script/gi, "\\u003c/script");
3219
+ 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>");
3220
+ doc.writeln(ctaQueueScript + dataScript);
3221
+ }
3222
+ if (isolate) {
3223
+ const escapedData = (options == null ? void 0 : options.data) !== void 0 ? JSON.stringify(options.data).replace(/<\/script/gi, "\\u003c/script") : "undefined";
3224
+ doc.writeln(this.buildIsolationBridge(escapedData));
3225
+ }
3226
+ doc.close();
3227
+ const comp = new MyopIframeComponent(componentDefinition, skin, container, IframeElement, options);
3228
+ if (isolate) comp.enableIsolation();
3229
+ comp.sizeMeta = parsedSizeMeta;
3230
+ comp.initiated().then(() => {
3231
+ if ((options == null ? void 0 : options.autoSize) === false) {
3232
+ return;
3233
+ }
3234
+ let shown = false;
3235
+ comp.observeAutoSize({
3236
+ forceAutoSize: true,
3237
+ onSizeChange: () => {
3238
+ if (!shown && !(options == null ? void 0 : options.hidden)) {
3239
+ shown = true;
3240
+ comp.show();
3241
+ }
2872
3242
  }
2873
- const componentConfig = convertV2VariantToComponentConfig(variant);
2874
- this.variants[cacheKey].resolved = componentConfig;
2875
- resolve(componentConfig);
2876
- } catch (e) {
2877
- delete this.variants[cacheKey];
2878
- reject(e);
2879
- }
3243
+ });
3244
+ });
3245
+ return comp;
3246
+ }
3247
+ if (loaderConfig.shadowRootMode === ShadowRootModeType.none) {
3248
+ const template = document.createElement("template");
3249
+ template.innerHTML = loaderConfig.HTML;
3250
+ element = template.content.firstElementChild;
3251
+ getInitiatedSdk().then((sdk2) => {
3252
+ sdk2.connectedCallback(element, element);
3253
+ });
3254
+ } else {
3255
+ const customElementName = toCustomElementName(componentDefinition.name + skin.id);
3256
+ if (!seen2.includes(customElementName)) {
3257
+ createCustomWebComponent(customElementName, loaderConfig.HTML, loaderConfig.shadowRootMode);
3258
+ seen2.push(customElementName);
2880
3259
  }
2881
- );
2882
- }
2883
- return await this.variants[cacheKey];
3260
+ element = document.createElement(customElementName);
3261
+ }
3262
+ if (!container.querySelector('[id^="myop-comp-"]'))
3263
+ container.innerHTML = "";
3264
+ element.id = domId;
3265
+ if (options == null ? void 0 : options.hidden) {
3266
+ element.style.opacity = "0";
3267
+ element.style.position = "absolute";
3268
+ element.style.height = "0";
3269
+ element.style.width = "0";
3270
+ element.style.pointerEvents = "none";
3271
+ element.style.visibility = "hidden";
3272
+ }
3273
+ this.appendChild(container, element, options);
3274
+ return new MyopWebComponent(componentDefinition, skin, container, element, options);
3275
+ });
2884
3276
  }
2885
3277
  /**
2886
- * Synchronous version of fetchComponentV2 — returns the config only if
2887
- * the fetch already completed, null otherwise.
2888
- *
2889
- * Uses the same `this.variants` cache that fetchComponentV2/preloadComponents
2890
- * populate. Each cached Promise is tagged with a `.resolved` property when
2891
- * it settles — this method just reads that property. No separate cache.
2892
- *
2893
- * Why this exists: React Native needs the config at render time to embed it
2894
- * in the WebView HTML (can't await in useState). If preloadComponents ran
2895
- * earlier and the fetch completed, this returns the result synchronously,
2896
- * skipping the WEBVIEW_READY → fetch → inject round trip entirely.
3278
+ * Detect if HTML is a Myop Web Component (starts with marker comment)
2897
3279
  */
2898
- getResolvedConfig(componentId, env, preview) {
2899
- var _a;
2900
- const { cacheKey } = this.resolveParams(componentId, env, preview);
2901
- return ((_a = this.variants[cacheKey]) == null ? void 0 : _a.resolved) || null;
3280
+ isMyopWebComponent(html) {
3281
+ return html.trimStart().startsWith(MYOP_WEB_COMPONENT_MARKER);
2902
3282
  }
2903
3283
  /**
2904
- * Resolve which (env, preview) pair — and therefore which cache key — a call
2905
- * for `componentId` refers to.
2906
- *
2907
- * Single source of truth for fetchComponentV2, getResolvedConfig and
2908
- * hydrateComponent, so a hydrated config always lands on the key a later
2909
- * fetch will look under.
3284
+ * Resolve how this component should render, applying the host render policy.
3285
+ * Precedence: options.renderPolicy (per-call) fully replaces the global
3286
+ * hostSDK.setRenderPolicy — so an app can restrict globally and allow specifics.
3287
+ * With no policy set, behavior is unchanged from before (marker ⇒ web component).
2910
3288
  */
2911
- resolveParams(componentId, environmentIdentifier, preview) {
2912
- const preloaded = this.preloadedComponents[componentId];
2913
- const hasExplicitParams = environmentIdentifier !== void 0 || preview !== void 0;
2914
- let env;
2915
- let usePreview;
2916
- if (!hasExplicitParams && preloaded) {
2917
- env = preloaded.env;
2918
- usePreview = preloaded.preview;
2919
- } else {
2920
- env = environmentIdentifier || this._defaultEnv;
2921
- const hasEffectiveEnv = environmentIdentifier || this._envExplicitlySet;
2922
- usePreview = preview === true ? true : preview === false ? false : !hasEffectiveEnv;
2923
- }
2924
- return { env, usePreview, cacheKey: "".concat(componentId, ":").concat(env, ":").concat(usePreview ? "preview" : "live") };
3289
+ async resolveRenderMode(componentDefinition, skin, loaderConfig, isWebComponent, options) {
3290
+ var _a, _b, _c, _d;
3291
+ const requestedMode = isWebComponent ? "webComponent" : loaderConfig.isolation || (options == null ? void 0 : options.isolation) ? "isolatedIframe" : "iframe";
3292
+ 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);
3293
+ const mode = policy ? await policy({ componentDefinition, skin, requestedMode, isWebComponent }) : requestedMode;
3294
+ return { mode, isolate: mode === "isolatedIframe" };
2925
3295
  }
2926
3296
  /**
2927
- * Seed an already-resolved component config into the cache, without any
2928
- * network request.
2929
- *
2930
- * The counterpart to {@link fetchComponentV2}: use it when the config was
2931
- * resolved somewhere else — most often on a server, then embedded in the
2932
- * page — so the browser can render the component with no round trip.
2933
- *
2934
- * After hydrating, `fetchComponentV2`, `getResolvedConfig` and `isPreloaded`
2935
- * all answer for this component from memory.
3297
+ * The in-frame bridge for isolated components. Runs inside the sandboxed
3298
+ * (opaque-origin) iframe, translating the same author-facing contract to/from
3299
+ * postMessage since the host has no same-origin access:
3300
+ * • data-in : parent posts {type:'myop:init'} → calls window.myop_init_interface
3301
+ * (plus a baked initial value for the first render)
3302
+ * • data-out: window.myop_cta_handler → parent.postMessage({type:'myop:cta'})
3303
+ * • resize : ResizeObserver → parent.postMessage({type:'myop:size'})
2936
3304
  *
2937
- * Pass the same `env` / `preview` the config was resolved with; the defaults
2938
- * match what a plain `fetchComponentV2(componentId)` would have used.
3305
+ * TODO(dev-extension): the isolated path deliberately skips the same-origin
3306
+ * dataScript, so it never posts the `MYOP_PREINJECTED_INIT` message the Myop dev
3307
+ * extension listens for to log the INITIAL render (`init*`). Later init updates and
3308
+ * all CTAs are still tracked (the extension wraps `comp.props`, which our isolated
3309
+ * connectProps branch routes through), so only the first-render payload is missing
3310
+ * from the extension's activity log for isolated components. Closing this would be a
3311
+ * ~1-line `parent.postMessage({type:'MYOP_PREINJECTED_INIT', payload:{data}})` inside
3312
+ * flushInitial() below — intentionally NOT done for now to avoid adding extension-only
3313
+ * traffic to the component runtime. Web components have the same initial-init gap
3314
+ * (initWithData is called on the element, not via comp.props) and it predates this.
2939
3315
  */
2940
- hydrateComponent(componentId, config, env, preview) {
2941
- const { env: resolvedEnv, usePreview, cacheKey } = this.resolveParams(componentId, env, preview);
2942
- const promise = Promise.resolve(config);
2943
- promise.resolved = config;
2944
- this.variants[cacheKey] = promise;
2945
- this.preloadedComponents[componentId] = { env: resolvedEnv, preview: usePreview };
3316
+ buildIsolationBridge(initialDataLiteral) {
3317
+ 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>");
2946
3318
  }
2947
- // ============ V1 Methods (Legacy) ============
2948
3319
  /**
2949
- * Fetch a v1 component from a flow
3320
+ * Extract the web component script content from HTML
2950
3321
  */
2951
- async fetchComponentV1(componentId, flowId) {
2952
- if (flowId) {
2953
- const flow = await this.fetchFlow(flowId);
2954
- return flow.components.find((c) => c.type.id === componentId);
2955
- } else {
2956
- const flow = await this.fetchAutoFlow(componentId);
2957
- return flow.components[0];
2958
- }
3322
+ extractWebComponentScript(html) {
3323
+ const parser = new DOMParser();
3324
+ const doc = parser.parseFromString(html, "text/html");
3325
+ const script = doc.getElementById(MYOP_WEB_COMPONENT_SCRIPT_ID);
3326
+ return (script == null ? void 0 : script.textContent) || null;
2959
3327
  }
2960
- async fetchAutoFlow(componentId) {
2961
- if (!this.userFlows[componentId]) {
2962
- this.userFlows[componentId] = new Promise(
2963
- async (resolve, reject) => {
2964
- try {
2965
- const res = await fetch(
2966
- "".concat(this._baseUrl, "/flow?id=").concat(componentId, "&auto=true")
2967
- );
2968
- const json = await res.json();
2969
- resolve(json.item);
2970
- } catch (e) {
2971
- delete this.userFlows[componentId];
2972
- reject(e);
2973
- }
2974
- }
2975
- );
3328
+ /**
3329
+ * Execute the web component script on the host document.
3330
+ * Returns the custom element tag name this script registered.
3331
+ */
3332
+ executeWebComponentScript(scriptContent, scriptId) {
3333
+ const cachedTagName = extractedWebComponentScripts.get(scriptId);
3334
+ if (cachedTagName) {
3335
+ console.log("[MyopWebComponent] Script already executed for ".concat(scriptId, ", reusing <").concat(cachedTagName, ">"));
3336
+ return cachedTagName;
2976
3337
  }
2977
- return await this.userFlows[componentId];
2978
- }
2979
- async fetchFlow(flowId) {
2980
- if (!this.userFlows[flowId]) {
2981
- this.userFlows[flowId] = new Promise(
2982
- async (resolve, reject) => {
2983
- try {
2984
- const res = await fetch(
2985
- "".concat(this._baseUrl, "/flow?id=").concat(flowId, "&resolve=components")
2986
- );
2987
- const json = await res.json();
2988
- resolve(json.item);
2989
- } catch (e) {
2990
- delete this.userFlows[flowId];
2991
- reject(e);
2992
- }
2993
- }
2994
- );
3338
+ const script = document.createElement("script");
3339
+ script.textContent = scriptContent;
3340
+ script.id = "myop-extracted-".concat(scriptId);
3341
+ document.head.appendChild(script);
3342
+ const tagName = window.__MYOP_TAG_NAME__;
3343
+ if (tagName) {
3344
+ extractedWebComponentScripts.set(scriptId, tagName);
2995
3345
  }
2996
- return await this.userFlows[flowId];
3346
+ console.log("[MyopWebComponent] Executed web component script: ".concat(scriptId, " -> <").concat(tagName, ">"));
3347
+ return tagName;
2997
3348
  }
2998
- // ============ Backward Compatibility ============
2999
3349
  /**
3000
- * @deprecated Use fetchComponentV2 or fetchComponentV1 explicitly
3001
- * Defaults to v1 behavior for backward compatibility with existing code
3350
+ * Load a Myop Web Component (extracted and run on host document)
3002
3351
  */
3003
- async fetchComponent(componentId, flowId) {
3004
- return this.fetchComponentV1(componentId, flowId);
3352
+ async loadExtractedWebComponent(componentDefinition, skin, container, html, options) {
3353
+ const scriptContent = this.extractWebComponentScript(html);
3354
+ if (!scriptContent) {
3355
+ throw new Error('[MyopWebComponent] No <script id="myop-web-component"> found in HTML');
3356
+ }
3357
+ const scriptId = "".concat(componentDefinition.id, "-").concat(skin.id);
3358
+ const tagName = this.executeWebComponentScript(scriptContent, scriptId);
3359
+ if (!tagName) {
3360
+ throw new Error("[MyopWebComponent] Script did not set window.__MYOP_TAG_NAME__");
3361
+ }
3362
+ const domId = "myop-comp-".concat(uuidv4());
3363
+ const element = document.createElement(tagName);
3364
+ element.id = domId;
3365
+ if (options == null ? void 0 : options.hidden) {
3366
+ element.style.opacity = "0";
3367
+ element.style.position = "absolute";
3368
+ element.style.height = "0";
3369
+ element.style.width = "0";
3370
+ element.style.pointerEvents = "none";
3371
+ element.style.visibility = "hidden";
3372
+ }
3373
+ if (!container.querySelector('[id^="myop-comp-"]')) {
3374
+ container.innerHTML = "";
3375
+ }
3376
+ this.appendChild(container, element, options);
3377
+ const component = new MyopExtractedWebComponent(
3378
+ componentDefinition,
3379
+ skin,
3380
+ container,
3381
+ element,
3382
+ tagName,
3383
+ options
3384
+ );
3385
+ if ((options == null ? void 0 : options.data) !== void 0) {
3386
+ component.initWithData(options.data);
3387
+ }
3388
+ console.log("[MyopWebComponent] Loaded <".concat(tagName, "> into container"));
3389
+ return component;
3005
3390
  }
3006
3391
  };
3007
- __publicField(_CloudRepository, "_main", null);
3008
- var CloudRepository = _CloudRepository;
3009
-
3010
- // src/helpers/cloudRepositoryHelpers.ts
3011
- var _cloudRepository = CloudRepository.Main;
3012
3392
 
3013
3393
  // src/host/myopOverride.ts
3014
3394
  var checkMyopOverride = async (componentConfig) => {
@@ -3104,8 +3484,22 @@ var HostSDK = class {
3104
3484
  }
3105
3485
  });
3106
3486
  });
3487
+ // A component's origin is whatever its iframe URL is, so an origin allowlist can't work here.
3488
+ // Instead only frames this SDK created (or adopted) may talk to it. `send()` dispatches
3489
+ // synthetic events, which have no source.
3490
+ __publicField(this, "isTrustedSource", (source) => {
3491
+ if (!source || source === window) return true;
3492
+ const isOwnFrame = (component) => {
3493
+ const element = component.element;
3494
+ return (element == null ? void 0 : element.nodeName) === "IFRAME" && element.contentWindow === source;
3495
+ };
3496
+ return this.components.some(isOwnFrame) || this.components2init.some(isOwnFrame);
3497
+ });
3107
3498
  __publicField(this, "incomingMessageHandler", (event) => {
3108
- if (event.origin === document.location.origin) {
3499
+ var _a;
3500
+ if (!((_a = event.data) == null ? void 0 : _a.myop)) return;
3501
+ if (!this.isTrustedSource(event.source)) {
3502
+ return;
3109
3503
  }
3110
3504
  if (event.data.myop) {
3111
3505
  if (event.data.direction !== MessageDirection.up && event.data.messageType !== MyopMessages.EnvelopedMessage) {
@@ -3121,8 +3515,8 @@ var HostSDK = class {
3121
3515
  if (myopMessage.messageType === MyopMessages.InitResponse) {
3122
3516
  this.components2init = this.components2init.filter((component2) => component2.id !== myopMessage.content.id);
3123
3517
  const initiatedComponent = this.components.find((component2) => {
3124
- var _a;
3125
- return component2.id === ((_a = myopMessage.content) == null ? void 0 : _a.id);
3518
+ var _a2;
3519
+ return component2.id === ((_a2 = myopMessage.content) == null ? void 0 : _a2.id);
3126
3520
  });
3127
3521
  initiatedComponent == null ? void 0 : initiatedComponent.setInitiated();
3128
3522
  return;
@@ -3175,7 +3569,10 @@ var HostSDK = class {
3175
3569
  });
3176
3570
  __publicField(this, "init", (customComponentLoaderCreators) => {
3177
3571
  if (this.initiated) {
3178
- throw new Error("hostSDK already initiated");
3572
+ if (customComponentLoaderCreators == null ? void 0 : customComponentLoaderCreators.length) {
3573
+ this._registerLoaders(customComponentLoaderCreators);
3574
+ }
3575
+ return;
3179
3576
  }
3180
3577
  const basicLoaders = [
3181
3578
  new MyopIframeLoader(),
@@ -3186,16 +3583,7 @@ var HostSDK = class {
3186
3583
  ...basicLoaders
3187
3584
  ];
3188
3585
  if (customComponentLoaderCreators) {
3189
- const loaderByType = {};
3190
- customComponentLoaderCreators.forEach((customComponentLoaderCreator) => {
3191
- const customLoader = new customComponentLoaderCreator(this.componentsLoaders);
3192
- loaderByType[customLoader.type] = customLoader;
3193
- });
3194
- this.componentsLoaders.forEach((loader) => {
3195
- if (!loaderByType[loader.type])
3196
- loaderByType[loader.type] = loader;
3197
- });
3198
- this.componentsLoaders = Object.values(loaderByType);
3586
+ this._registerLoaders(customComponentLoaderCreators);
3199
3587
  }
3200
3588
  window.addEventListener(
3201
3589
  "message",
@@ -3205,6 +3593,18 @@ var HostSDK = class {
3205
3593
  console.log("myop hostSDK initiated", document.location.href);
3206
3594
  this.initiated = true;
3207
3595
  });
3596
+ __publicField(this, "_registerLoaders", (customComponentLoaderCreators) => {
3597
+ const loaderByType = {};
3598
+ customComponentLoaderCreators.forEach((customComponentLoaderCreator) => {
3599
+ const customLoader = new customComponentLoaderCreator(this.componentsLoaders);
3600
+ loaderByType[customLoader.type] = customLoader;
3601
+ });
3602
+ this.componentsLoaders.forEach((loader) => {
3603
+ if (!loaderByType[loader.type])
3604
+ loaderByType[loader.type] = loader;
3605
+ });
3606
+ this.componentsLoaders = Object.values(loaderByType);
3607
+ });
3208
3608
  __publicField(this, "_getSkinIdBySkinSelector", async (skinSelector, experiences = [], hooks) => {
3209
3609
  var _a;
3210
3610
  async function asyncFind(array, predicate) {
@@ -3385,6 +3785,13 @@ if (!window.myop.hostSDK) {
3385
3785
  }
3386
3786
  window.myop.hostSDK = _hostSDK;
3387
3787
  }
3788
+ if (window.myop && !window.myop.delivery) {
3789
+ const api = (opts) => delivery(opts);
3790
+ api.stats = deliveryStats;
3791
+ api.off = deliveryOff;
3792
+ api.refresh = deliveryRefresh;
3793
+ window.myop.delivery = api;
3794
+ }
3388
3795
  var hostSDK = window.myop.hostSDK;
3389
3796
  defineDynamicImport("hostSDK", hostSDK);
3390
3797
  export {