@myop/sdk 0.4.0-beta.4 → 0.4.0-beta.6

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 (48) hide show
  1. package/README.md +13 -0
  2. package/dist/bundled-declarations.d.ts +87 -4
  3. package/dist/cjs/{_IframeSDK.3a412cd4.js → _IframeSDK.49662e01.js} +97 -18
  4. package/dist/cjs/_IframeSDK.49662e01.js.map +7 -0
  5. package/dist/cjs/_IframeSDK.d4a97876.min.js +1 -0
  6. package/dist/cjs/_MyopHelpers.12acc780.min.js +1 -0
  7. package/dist/cjs/{_MyopHelpers.efed13e4.js → _MyopHelpers.2c449e7a.js} +78 -15
  8. package/dist/cjs/_MyopHelpers.2c449e7a.js.map +7 -0
  9. package/dist/cjs/_WebComponentSDK.1addf28b.min.js +1 -0
  10. package/dist/cjs/{_WebComponentSDK.4b6ac803.js → _WebComponentSDK.d5f9105b.js} +97 -18
  11. package/dist/cjs/_WebComponentSDK.d5f9105b.js.map +7 -0
  12. package/dist/cjs/_hostSDK.6dab59cb.min.js +1 -0
  13. package/dist/cjs/{_hostSDK.e9b70e44.js → _hostSDK.8cf37510.js} +97 -18
  14. package/dist/cjs/_hostSDK.8cf37510.js.map +7 -0
  15. package/dist/cjs/myop_sdk.js +14 -14
  16. package/dist/cjs/myop_sdk.js.map +1 -1
  17. package/dist/cjs/myop_sdk.min.js +1 -1
  18. package/dist/cjs-bundled/myop_sdk.bundled.js +107 -21
  19. package/dist/cjs-bundled/myop_sdk.bundled.js.map +3 -3
  20. package/dist/cjs-bundled/myop_sdk.bundled.min.js +1 -1
  21. package/dist/module/Iframe/index.js +98 -19
  22. package/dist/module/Iframe/index.js.map +2 -2
  23. package/dist/module/SDK.js +107 -21
  24. package/dist/module/SDK.js.map +3 -3
  25. package/dist/module/common/index.d.ts +5 -0
  26. package/dist/module/common/index.js +1 -1
  27. package/dist/module/common/index.js.map +2 -2
  28. package/dist/module/embeddedSDK.js +1 -1
  29. package/dist/module/helpers/CloudRepository.d.ts +36 -1
  30. package/dist/module/helpers/cloudRepositoryHelpers.d.ts +42 -2
  31. package/dist/module/helpers/index.js +77 -16
  32. package/dist/module/helpers/index.js.map +2 -2
  33. package/dist/module/host/components/IMyopComponent.d.ts +3 -0
  34. package/dist/module/host/embeddedSDK.js +1 -1
  35. package/dist/module/host/hostSDK.d.ts +1 -1
  36. package/dist/module/host/index.js +98 -19
  37. package/dist/module/host/index.js.map +2 -2
  38. package/dist/module/webcomponent/index.js +98 -19
  39. package/dist/module/webcomponent/index.js.map +2 -2
  40. package/package.json +1 -1
  41. package/dist/cjs/_IframeSDK.3a412cd4.js.map +0 -7
  42. package/dist/cjs/_IframeSDK.9338575d.min.js +0 -1
  43. package/dist/cjs/_MyopHelpers.91004b19.min.js +0 -1
  44. package/dist/cjs/_MyopHelpers.efed13e4.js.map +0 -7
  45. package/dist/cjs/_WebComponentSDK.4b6ac803.js.map +0 -7
  46. package/dist/cjs/_WebComponentSDK.4e78d94a.min.js +0 -1
  47. package/dist/cjs/_hostSDK.34f770f6.min.js +0 -1
  48. package/dist/cjs/_hostSDK.e9b70e44.js.map +0 -7
package/README.md CHANGED
@@ -328,6 +328,19 @@ const flow = await CloudRepository.Main.fetchFlow('flow-id');
328
328
  const isLoaded = CloudRepository.Main.isPreloaded('component-id');
329
329
  ```
330
330
 
331
+ ### Runtime tags (`ui:*`)
332
+
333
+ Read a component's `ui:`-prefixed tags client-side, in the same response that loads it:
334
+
335
+ ```typescript
336
+ import { preloadComponents, getComponentTags } from '@myop/sdk/helpers';
337
+
338
+ await preloadComponents(['component-id']);
339
+ getComponentTags('component-id'); // ['ui:beta'] — also on a mounted component as component.uiTags
340
+ ```
341
+
342
+ Only tags starting with `ui:` reach the browser. See [Runtime Tags](https://docs.myop.dev/docs/learn/ui-tags/).
343
+
331
344
  ### Host SDK
332
345
 
333
346
  ```typescript
@@ -370,6 +370,11 @@ declare module "@myop/sdk/common" {
370
370
  id: string;
371
371
  name: string;
372
372
  description: string;
373
+ /**
374
+ * The component's runtime tags: only tags named `ui:...` (e.g. `ui:beta`), as set in the
375
+ * dashboard. Every other tag stays private on the server. Empty when there are none.
376
+ */
377
+ uiTags?: string[];
373
378
  props: IPropConfig[];
374
379
  refs: IRefConfig[];
375
380
  skins: ISkinConfig[];
@@ -1225,6 +1230,8 @@ declare module "@myop/sdk/host/components/IMyopComponent" {
1225
1230
  markedForDisposed: boolean;
1226
1231
  setInitiated: () => void;
1227
1232
  componentDefinition: IComponentDefinitionConfig;
1233
+ /** Runtime tags: only tags named `ui:...` (e.g. `ui:beta`). `[]` when there are none. */
1234
+ readonly uiTags: string[];
1228
1235
  container: HTMLElement;
1229
1236
  element?: HTMLElement;
1230
1237
  send: (msg: BaseMyopMessage) => CleanupHandler;
@@ -1268,6 +1275,7 @@ declare module "@myop/sdk/host/components/IMyopComponent" {
1268
1275
  messageHandlers: Record<string, messageHandler<any>[]>;
1269
1276
  element?: HTMLElement;
1270
1277
  protected constructor(componentDefinition: IComponentDefinitionConfig, container: HTMLElement, options?: loaderOptions);
1278
+ get uiTags(): string[];
1271
1279
  _markedForDisposed: boolean;
1272
1280
  get markedForDisposed(): boolean;
1273
1281
  set markedForDisposed(value: boolean);
@@ -1622,16 +1630,21 @@ declare module "@myop/sdk/helpers/CloudRepository" {
1622
1630
  * Deliberately mutates THIS instance rather than constructing a new repository:
1623
1631
  * CloudRepository.Main is a global singleton shared across bundles (see getGlobalMain),
1624
1632
  * so a second instance would be ignored by every component already using the first.
1633
+ *
1634
+ * @internal
1625
1635
  */
1626
1636
  setDelivery(opts?: {
1627
1637
  minify?: boolean;
1628
1638
  host?: string | null;
1629
1639
  cache?: boolean;
1640
+ flow?: boolean;
1630
1641
  }): void;
1642
+ /** @internal */
1631
1643
  deliveryStats(): {
1632
1644
  host: string;
1633
1645
  minify: boolean;
1634
1646
  cache: boolean;
1647
+ flow: boolean;
1635
1648
  requests: number;
1636
1649
  viaDelivery: number;
1637
1650
  fellBack: number;
@@ -1649,6 +1662,8 @@ declare module "@myop/sdk/helpers/CloudRepository" {
1649
1662
  * Forget what this browser holds, so the next load asks the server.
1650
1663
  * `refresh()` with no ids drops everything; the counterpart to the window for the case
1651
1664
  * where a change has to be visible on THIS load — right after someone publishes.
1665
+ *
1666
+ * @internal
1652
1667
  */
1653
1668
  refreshDelivery(): Promise<void>;
1654
1669
  /**
@@ -1666,6 +1681,12 @@ declare module "@myop/sdk/helpers/CloudRepository" {
1666
1681
  */
1667
1682
  private _localServes;
1668
1683
  private _flushBound;
1684
+ /**
1685
+ * `source: 'h'` = the view was served from a config the page's SERVER embedded
1686
+ * (hydrateV1Component), not from this browser's cache window. Reported as a 4th batch
1687
+ * field (`id:env:n:h`) so our usage data can tell server-rendered views apart; a server
1688
+ * that predates it reads the first three fields and counts the view all the same.
1689
+ */
1669
1690
  private noteLocalServe;
1670
1691
  /** Report on page-hide, which is the only event that reliably fires on mobile. */
1671
1692
  private bindFlush;
@@ -1692,7 +1713,7 @@ declare module "@myop/sdk/helpers/CloudRepository" {
1692
1713
  /**
1693
1714
  * Enable static mode for self-hosted component registries.
1694
1715
  * In static mode, URLs are constructed as file paths instead of query params:
1695
- * ${baseUrl}/components/${componentId}/${env}.json
1716
+ * `${baseUrl}/components/${componentId}/${env}.json`
1696
1717
  */
1697
1718
  enableStaticMode(): void;
1698
1719
  /**
@@ -1759,6 +1780,11 @@ declare module "@myop/sdk/helpers/CloudRepository" {
1759
1780
  * skipping the WEBVIEW_READY → fetch → inject round trip entirely.
1760
1781
  */
1761
1782
  getResolvedConfig(componentId: string, env?: string, preview?: boolean): IComponentConfig | null;
1783
+ /**
1784
+ * The `ui:` tags of an already-resolved component (`[]` if it has none or is not
1785
+ * resolved yet). Synchronous, no request: tags arrive with the component itself.
1786
+ */
1787
+ getComponentTags(componentId: string, env?: string, preview?: boolean): string[];
1762
1788
  /**
1763
1789
  * Resolve which (env, preview) pair — and therefore which cache key — a call
1764
1790
  * for `componentId` refers to.
@@ -1783,6 +1809,23 @@ declare module "@myop/sdk/helpers/CloudRepository" {
1783
1809
  * match what a plain `fetchComponentV2(componentId)` would have used.
1784
1810
  */
1785
1811
  hydrateComponent(componentId: string, config: IComponentConfig, env?: string, preview?: boolean): void;
1812
+ /** ids seeded by hydrateV1Component whose first use has not been counted yet */
1813
+ private _hydratedV1;
1814
+ /**
1815
+ * Seed a v1 component's config, so `fetchComponentV1(componentId)` answers from memory
1816
+ * with no request. The v1 counterpart of {@link hydrateComponent}.
1817
+ *
1818
+ * `flow` is what `GET /flow?id=<componentId>&auto=true` returns: either the whole body
1819
+ * (`{item: {...}}`) or its `item`. Typical use is a server that fetched it (with
1820
+ * `&prefetch=1`, so the fetch is not counted as a view) and embedded it in the page.
1821
+ *
1822
+ * The view IS counted: the first time the seeded config is used, it is reported through
1823
+ * /clientUsage (flagged `:h`, recorded as deliveryPath 'hydrated'), so hydrating never makes
1824
+ * usage disappear and server-rendered views stay distinguishable.
1825
+ */
1826
+ hydrateV1Component(componentId: string, flow: IUserFlow | {
1827
+ item: IUserFlow;
1828
+ }): void;
1786
1829
  /**
1787
1830
  * Fetch a v1 component from a flow
1788
1831
  */
@@ -1835,21 +1878,28 @@ declare module "@myop/sdk/helpers/cloudRepositoryHelpers" {
1835
1878
  * inside the freshness the server promised, is rendered with NO request. Once the
1836
1879
  * window ends the browser sends back the version it holds instead of re-downloading.
1837
1880
  * - A preview is never minified and never cached.
1838
- * - Only /consume moves. Everything else keeps the host it has today.
1881
+ * - Only /consume moves. Everything else keeps the host it has today -- unless
1882
+ * `flow: true`, which also moves v1 component configs (`/flow?auto=true`), with the
1883
+ * same fallback.
1839
1884
  * - Asking for `minify` does not force it: the server decides per component, and a
1840
1885
  * component that is not enabled is served raw, which is not an error.
1841
1886
  *
1842
1887
  * `host` is for us (a staging lane, a local server); leave it out.
1888
+ *
1889
+ * @internal Delivery lane: kept out of the public API reference until it is released.
1843
1890
  */
1844
1891
  export const DELIVERY_HOST = "https://delivery.myop.dev";
1892
+ /** @internal */
1845
1893
  export const delivery: (opts?: {
1846
1894
  minify?: boolean;
1847
1895
  cache?: boolean;
1896
+ flow?: boolean;
1848
1897
  host?: string | null;
1849
1898
  }) => {
1850
1899
  host: string;
1851
1900
  minify: boolean;
1852
1901
  cache: boolean;
1902
+ flow: boolean;
1853
1903
  requests: number;
1854
1904
  viaDelivery: number;
1855
1905
  fellBack: number;
@@ -1865,11 +1915,14 @@ declare module "@myop/sdk/helpers/cloudRepositoryHelpers" {
1865
1915
  * Forget what this browser holds, so the next load asks the server. Use it when a change
1866
1916
  * has to be visible on THIS load — right after someone publishes — rather than within the
1867
1917
  * freshness window.
1918
+ *
1919
+ * @internal
1868
1920
  */
1869
1921
  export const deliveryRefresh: () => Promise<{
1870
1922
  host: string;
1871
1923
  minify: boolean;
1872
1924
  cache: boolean;
1925
+ flow: boolean;
1873
1926
  requests: number;
1874
1927
  viaDelivery: number;
1875
1928
  fellBack: number;
@@ -1884,11 +1937,14 @@ declare module "@myop/sdk/helpers/cloudRepositoryHelpers" {
1884
1937
  /**
1885
1938
  * What answered the last requests, and — the number worth watching — how many times the
1886
1939
  * SDK had to fall back to the default host because the lane did not answer.
1940
+ *
1941
+ * @internal
1887
1942
  */
1888
1943
  export const deliveryStats: () => {
1889
1944
  host: string;
1890
1945
  minify: boolean;
1891
1946
  cache: boolean;
1947
+ flow: boolean;
1892
1948
  requests: number;
1893
1949
  viaDelivery: number;
1894
1950
  fellBack: number;
@@ -1900,11 +1956,12 @@ declare module "@myop/sdk/helpers/cloudRepositoryHelpers" {
1900
1956
  unchanged: number;
1901
1957
  bytesSaved: number;
1902
1958
  };
1903
- /** Undo delivery(): back to the default host and raw bytes, with no reload. */
1959
+ /** Undo delivery(): back to the default host and raw bytes, with no reload. @internal */
1904
1960
  export const deliveryOff: () => {
1905
1961
  host: string;
1906
1962
  minify: boolean;
1907
1963
  cache: boolean;
1964
+ flow: boolean;
1908
1965
  requests: number;
1909
1966
  viaDelivery: number;
1910
1967
  fellBack: number;
@@ -1919,6 +1976,16 @@ declare module "@myop/sdk/helpers/cloudRepositoryHelpers" {
1919
1976
  export const setCloudRepository: (repository: CloudRepository) => void;
1920
1977
  export const setEnvironment: (env: string) => void;
1921
1978
  export const getResolvedConfig: (componentId: string, env?: string, preview?: boolean) => IComponentConfig;
1979
+ /**
1980
+ * The runtime tags of a loaded/preloaded component: only tags named `ui:...` (e.g.
1981
+ * `ui:beta`). Returns `[]` when it has none or has not been fetched yet.
1982
+ *
1983
+ * ```ts
1984
+ * await preloadComponents([id]);
1985
+ * getComponentTags(id); // ['ui:beta']
1986
+ * ```
1987
+ */
1988
+ export const getComponentTags: (componentId: string, env?: string, preview?: boolean) => string[];
1922
1989
  export const preloadComponents: (ids: string[], env?: string, preview?: boolean) => Promise<PromiseSettledResult<IComponentConfig>[]>;
1923
1990
  /**
1924
1991
  * Seed already-resolved component configs into the SDK cache, with no network
@@ -1938,6 +2005,22 @@ declare module "@myop/sdk/helpers/cloudRepositoryHelpers" {
1938
2005
  * match what a plain `preloadComponents([id])` would have used.
1939
2006
  */
1940
2007
  export const hydrateComponents: (configs: Record<string, IComponentConfig>, env?: string, preview?: boolean) => void;
2008
+ /**
2009
+ * The v1 (iframe component) counterpart of {@link hydrateComponents}: seed configs that a
2010
+ * server already fetched, so `loadComponent` needs no `/flow` request at all.
2011
+ *
2012
+ * ```ts
2013
+ * // server (cache it ~60 s; `prefetch=1` keeps this fetch out of the view count, `for` says which
2014
+ * // page it is for, so the prefetch is attributed to your site — its query string is not stored):
2015
+ * const flow = await (await fetch(`https://cloud.myop.dev/flow?id=${id}&auto=true&prefetch=1&for=${encodeURIComponent(pageUrl)}`)).json();
2016
+ * // embed JSON.stringify(flow) in the page, then on the client:
2017
+ * hydrateV1Components({ [id]: flow });
2018
+ * const cfg = await CloudRepository.Main.fetchComponentV1(id); // no request
2019
+ * ```
2020
+ *
2021
+ * Each seeded config is counted as a view the first time it is used (via /clientUsage).
2022
+ */
2023
+ export const hydrateV1Components: (flows: Record<string, any>) => void;
1941
2024
  }
1942
2025
  declare module "@myop/sdk/webcomponent/shadowRootRef" {
1943
2026
  import { RootRef } from "@myop/sdk/common";
@@ -2342,7 +2425,7 @@ declare module "@myop/sdk/host/hostSDK" {
2342
2425
  _inspection?: boolean;
2343
2426
  data?: any;
2344
2427
  /**
2345
- * Raw CSS injected into the component's iframe <head> before first paint.
2428
+ * Raw CSS injected into the component's iframe `<head>` before first paint.
2346
2429
  * Appended last so it overrides the component's own styles via cascade order.
2347
2430
  * Useful for theming v2 (HTML) components — colors, fonts, spacing, etc.
2348
2431
  */
@@ -1017,6 +1017,10 @@ var BaseMyopComponent = class {
1017
1017
  }
1018
1018
  });
1019
1019
  }
1020
+ get uiTags() {
1021
+ var _a;
1022
+ return ((_a = this.componentDefinition) == null ? void 0 : _a.uiTags) || [];
1023
+ }
1020
1024
  get markedForDisposed() {
1021
1025
  return this._markedForDisposed;
1022
1026
  }
@@ -2096,6 +2100,21 @@ var addQueryParam = (url, param, value) => {
2096
2100
  urlObj.searchParams.append(param, value);
2097
2101
  return urlObj.toString();
2098
2102
  };
2103
+ var showsSamePage = (frame, url) => {
2104
+ const current = frame.getAttribute("src");
2105
+ if (!current || !url) return false;
2106
+ const norm = (u) => {
2107
+ const x = new URL(u, document.baseURI);
2108
+ x.hash = "";
2109
+ if (x.pathname.length > 1) x.pathname = x.pathname.replace(/\/$/, "");
2110
+ return x.href;
2111
+ };
2112
+ try {
2113
+ return norm(current) === norm(url);
2114
+ } catch (e) {
2115
+ return false;
2116
+ }
2117
+ };
2099
2118
  var MyopIframeLoader = class extends BaseMyopLoader {
2100
2119
  constructor() {
2101
2120
  super(...arguments);
@@ -2105,9 +2124,10 @@ var MyopIframeLoader = class extends BaseMyopLoader {
2105
2124
  let IframeElement;
2106
2125
  const typedLoaderConfig = skin.loader;
2107
2126
  if ((container == null ? void 0 : container.nodeName) === "IFRAME") {
2108
- console.log("needs to load into an exsisting Iframe...", typedLoaderConfig.url, container);
2109
2127
  IframeElement = container;
2110
- IframeElement.src = typedLoaderConfig.url;
2128
+ if (!showsSamePage(IframeElement, typedLoaderConfig.url)) {
2129
+ IframeElement.src = typedLoaderConfig.url;
2130
+ }
2111
2131
  } else {
2112
2132
  const uniqId = uuidv4();
2113
2133
  const domId = "myop-comp-".concat(uniqId);
@@ -2250,7 +2270,7 @@ var WebcomponentLoader = class extends BaseMyopLoader {
2250
2270
  };
2251
2271
 
2252
2272
  // version:myop-sdk-version
2253
- var myop_sdk_version_default = "0.4.0-beta.4";
2273
+ var myop_sdk_version_default = "0.4.0-beta.6";
2254
2274
 
2255
2275
  // src/helpers/deliveryStore.ts
2256
2276
  var DB_NAME = "myop-delivery";
@@ -2407,7 +2427,10 @@ var convertV2VariantToComponentConfig = (config) => {
2407
2427
  loader: config.consume_variant[0].loader
2408
2428
  }
2409
2429
  ],
2410
- defaultSkin: 0
2430
+ defaultSkin: 0,
2431
+ // Only `ui:` tags ever reach the client; the server filters, absent = none.
2432
+ // @ts-ignore
2433
+ uiTags: Array.isArray(config.uiTags) ? config.uiTags : []
2411
2434
  },
2412
2435
  name: config.name
2413
2436
  };
@@ -2449,7 +2472,7 @@ var _CloudRepository = class _CloudRepository {
2449
2472
  * Opt-in delivery settings, set by myop.delivery(). Off means: this file behaves
2450
2473
  * EXACTLY as it did before — same host, same URL, same everything.
2451
2474
  */
2452
- __publicField(this, "_delivery", { minify: false, host: null, cache: false });
2475
+ __publicField(this, "_delivery", { minify: false, host: null, cache: false, flow: false });
2453
2476
  /**
2454
2477
  * What actually happened, for myop.delivery.stats(). `fellBack` is the number that
2455
2478
  * matters: it is how you find out the lane is unhealthy without waiting for a
@@ -2484,6 +2507,9 @@ var _CloudRepository = class _CloudRepository {
2484
2507
  */
2485
2508
  __publicField(this, "_localServes", /* @__PURE__ */ new Map());
2486
2509
  __publicField(this, "_flushBound", false);
2510
+ // ============ V1 Methods (Legacy) ============
2511
+ /** ids seeded by hydrateV1Component whose first use has not been counted yet */
2512
+ __publicField(this, "_hydratedV1", /* @__PURE__ */ new Set());
2487
2513
  }
2488
2514
  static get Main() {
2489
2515
  const globalMain = getGlobalMain();
@@ -2519,32 +2545,46 @@ var _CloudRepository = class _CloudRepository {
2519
2545
  * Deliberately mutates THIS instance rather than constructing a new repository:
2520
2546
  * CloudRepository.Main is a global singleton shared across bundles (see getGlobalMain),
2521
2547
  * so a second instance would be ignored by every component already using the first.
2548
+ *
2549
+ * @internal
2522
2550
  */
2523
2551
  setDelivery(opts = {}) {
2524
2552
  if (opts.minify !== void 0) this._delivery.minify = !!opts.minify;
2525
2553
  if (opts.host !== void 0) this._delivery.host = opts.host;
2526
2554
  if (opts.cache !== void 0) this._delivery.cache = !!opts.cache;
2555
+ if (opts.flow !== void 0) this._delivery.flow = !!opts.flow;
2527
2556
  }
2557
+ /** @internal */
2528
2558
  deliveryStats() {
2529
2559
  var _a;
2530
2560
  return __spreadProps(__spreadValues({}, this._deliveryStats), {
2531
2561
  host: (_a = this._delivery.host) != null ? _a : _CloudRepository.DEFAULT_HOST,
2532
2562
  minify: this._delivery.minify,
2533
- cache: this._delivery.cache
2563
+ cache: this._delivery.cache,
2564
+ flow: this._delivery.flow
2534
2565
  });
2535
2566
  }
2536
2567
  /**
2537
2568
  * Forget what this browser holds, so the next load asks the server.
2538
2569
  * `refresh()` with no ids drops everything; the counterpart to the window for the case
2539
2570
  * where a change has to be visible on THIS load — right after someone publishes.
2571
+ *
2572
+ * @internal
2540
2573
  */
2541
2574
  async refreshDelivery() {
2542
2575
  await deliveryStore.clear();
2543
2576
  }
2544
- noteLocalServe(componentId, env) {
2545
- const cur = this._localServes.get(componentId);
2577
+ /**
2578
+ * `source: 'h'` = the view was served from a config the page's SERVER embedded
2579
+ * (hydrateV1Component), not from this browser's cache window. Reported as a 4th batch
2580
+ * field (`id:env:n:h`) so our usage data can tell server-rendered views apart; a server
2581
+ * that predates it reads the first three fields and counts the view all the same.
2582
+ */
2583
+ noteLocalServe(componentId, env, source) {
2584
+ const key = source ? "".concat(componentId, ":").concat(source) : componentId;
2585
+ const cur = this._localServes.get(key);
2546
2586
  if (cur) cur.count++;
2547
- else this._localServes.set(componentId, { env, count: 1 });
2587
+ else this._localServes.set(key, { id: componentId, env, count: 1, source });
2548
2588
  this.bindFlush();
2549
2589
  }
2550
2590
  /** Report on page-hide, which is the only event that reliably fires on mobile. */
@@ -2564,7 +2604,7 @@ var _CloudRepository = class _CloudRepository {
2564
2604
  */
2565
2605
  flushLocalServes() {
2566
2606
  if (!this._localServes.size) return;
2567
- const batch = [...this._localServes.entries()].map(([id, v]) => "".concat(id, ":").concat(v.env, ":").concat(v.count)).join(",");
2607
+ const batch = [...this._localServes.entries()].map(([, v]) => "".concat(v.id, ":").concat(v.env, ":").concat(v.count).concat(v.source ? ":" + v.source : "")).join(",");
2568
2608
  this._localServes.clear();
2569
2609
  try {
2570
2610
  const url = "".concat(this.deliveryHost(), "/clientUsage?b=").concat(encodeURIComponent(batch));
@@ -2613,7 +2653,7 @@ var _CloudRepository = class _CloudRepository {
2613
2653
  /**
2614
2654
  * Enable static mode for self-hosted component registries.
2615
2655
  * In static mode, URLs are constructed as file paths instead of query params:
2616
- * ${baseUrl}/components/${componentId}/${env}.json
2656
+ * `${baseUrl}/components/${componentId}/${env}.json`
2617
2657
  */
2618
2658
  enableStaticMode() {
2619
2659
  this._staticMode = true;
@@ -2822,6 +2862,14 @@ var _CloudRepository = class _CloudRepository {
2822
2862
  const { cacheKey } = this.resolveParams(componentId, env, preview);
2823
2863
  return ((_a = this.variants[cacheKey]) == null ? void 0 : _a.resolved) || null;
2824
2864
  }
2865
+ /**
2866
+ * The `ui:` tags of an already-resolved component (`[]` if it has none or is not
2867
+ * resolved yet). Synchronous, no request: tags arrive with the component itself.
2868
+ */
2869
+ getComponentTags(componentId, env, preview) {
2870
+ var _a, _b;
2871
+ return ((_b = (_a = this.getResolvedConfig(componentId, env, preview)) == null ? void 0 : _a.type) == null ? void 0 : _b.uiTags) || [];
2872
+ }
2825
2873
  /**
2826
2874
  * Resolve which (env, preview) pair — and therefore which cache key — a call
2827
2875
  * for `componentId` refers to.
@@ -2866,7 +2914,27 @@ var _CloudRepository = class _CloudRepository {
2866
2914
  this.variants[cacheKey] = promise;
2867
2915
  this.preloadedComponents[componentId] = { env: resolvedEnv, preview: usePreview };
2868
2916
  }
2869
- // ============ V1 Methods (Legacy) ============
2917
+ /**
2918
+ * Seed a v1 component's config, so `fetchComponentV1(componentId)` answers from memory
2919
+ * with no request. The v1 counterpart of {@link hydrateComponent}.
2920
+ *
2921
+ * `flow` is what `GET /flow?id=<componentId>&auto=true` returns: either the whole body
2922
+ * (`{item: {...}}`) or its `item`. Typical use is a server that fetched it (with
2923
+ * `&prefetch=1`, so the fetch is not counted as a view) and embedded it in the page.
2924
+ *
2925
+ * The view IS counted: the first time the seeded config is used, it is reported through
2926
+ * /clientUsage (flagged `:h`, recorded as deliveryPath 'hydrated'), so hydrating never makes
2927
+ * usage disappear and server-rendered views stay distinguishable.
2928
+ */
2929
+ hydrateV1Component(componentId, flow) {
2930
+ var _a, _b;
2931
+ const item = (_a = flow == null ? void 0 : flow.item) != null ? _a : flow;
2932
+ if (!((_b = item == null ? void 0 : item.components) == null ? void 0 : _b.length)) {
2933
+ throw new Error("hydrateV1Component(".concat(componentId, "): not a /flow?auto=true response"));
2934
+ }
2935
+ this.userFlows[componentId] = Promise.resolve(item);
2936
+ this._hydratedV1.add(componentId);
2937
+ }
2870
2938
  /**
2871
2939
  * Fetch a v1 component from a flow
2872
2940
  */
@@ -2880,13 +2948,15 @@ var _CloudRepository = class _CloudRepository {
2880
2948
  }
2881
2949
  }
2882
2950
  async fetchAutoFlow(componentId) {
2951
+ if (this._hydratedV1.delete(componentId)) {
2952
+ this.noteLocalServe(componentId, "v1_auto_flow", "h");
2953
+ }
2883
2954
  if (!this.userFlows[componentId]) {
2884
2955
  this.userFlows[componentId] = new Promise(
2885
2956
  async (resolve, reject) => {
2886
2957
  try {
2887
- const res = await fetch(
2888
- "".concat(this._baseUrl, "/flow?id=").concat(componentId, "&auto=true")
2889
- );
2958
+ const path = "/flow?id=".concat(componentId, "&auto=true");
2959
+ const res = this._delivery.flow && this._delivery.host ? await this.deliveryFetch(path) : await fetch("".concat(this._baseUrl).concat(path));
2890
2960
  const json = await res.json();
2891
2961
  resolve(json.item);
2892
2962
  } catch (e) {
@@ -2935,11 +3005,12 @@ var CloudRepository = _CloudRepository;
2935
3005
  var _cloudRepository = CloudRepository.Main;
2936
3006
  var DELIVERY_HOST = "https://delivery.myop.dev";
2937
3007
  var delivery = (opts = {}) => {
2938
- var _a, _b;
2939
- const wantsLane = opts.minify !== false || opts.cache === true;
3008
+ var _a, _b, _c;
3009
+ const wantsLane = opts.minify !== false || opts.cache === true || opts.flow === true;
2940
3010
  _cloudRepository.setDelivery({
2941
3011
  minify: (_a = opts.minify) != null ? _a : false,
2942
3012
  cache: (_b = opts.cache) != null ? _b : false,
3013
+ flow: (_c = opts.flow) != null ? _c : false,
2943
3014
  host: opts.host !== void 0 ? opts.host : wantsLane ? DELIVERY_HOST : null
2944
3015
  });
2945
3016
  return deliveryStats();
@@ -2950,9 +3021,14 @@ var deliveryRefresh = async () => {
2950
3021
  };
2951
3022
  var deliveryStats = () => _cloudRepository.deliveryStats();
2952
3023
  var deliveryOff = () => {
2953
- _cloudRepository.setDelivery({ minify: false, cache: false, host: null });
3024
+ _cloudRepository.setDelivery({ minify: false, cache: false, flow: false, host: null });
2954
3025
  return deliveryStats();
2955
3026
  };
3027
+ var hydrateV1Components = (flows) => {
3028
+ for (const [id, flow] of Object.entries(flows)) {
3029
+ _cloudRepository.hydrateV1Component(id, flow);
3030
+ }
3031
+ };
2956
3032
 
2957
3033
  // src/webcomponent/messageHandlers/BaseWebComponentMessageHandler.ts
2958
3034
  var BaseWebComponentMessageHandler = class extends BaseContextMessageHandler {
@@ -4019,6 +4095,9 @@ if (window.myop && !window.myop.delivery) {
4019
4095
  api.refresh = deliveryRefresh;
4020
4096
  window.myop.delivery = api;
4021
4097
  }
4098
+ if (window.myop && !window.myop.hydrateV1) {
4099
+ window.myop.hydrateV1 = hydrateV1Components;
4100
+ }
4022
4101
  var hostSDK = window.myop.hostSDK;
4023
4102
  defineDynamicImport("hostSDK", hostSDK);
4024
4103