All entries

March 24, 2026

cdc43ba6c45f2a775537c0bb36919fe44f85839e0c753c443d71bd0133e763af
Previous: 55c89da0 Bundle: 91.9 KB

This build introduces first-class support for app intents — apps can now read structured intent data from the URL, respond to intents with ok/error/closed outcomes, and detect intent context via `environment.intent`. Two new modules (`analytics` and `tools`) were added, and the title bar gains support for `<s-button-group>` elements.

Highlights

  • Two new modules registered: `analytics.js` and `tools.js`
  • `intents` module: new `api.data.intent` property that parses and exposes structured intent payload (`type`, `action`, `data`) from the URL's `intent` query parameter
  • `intents` module: new `api.intents.response` object with `ok()`, `error()`, and `closed()` methods for sending a response back to the intent caller (only exposed when an intent is present)
  • `environment` module: added `intent` boolean property indicating whether the app was launched with an intent
  • `title-bar` module: button-group serialization now recognises `<s-button-group>` elements (in addition to `<s-menu>`) and emits `groupType: 'inline'` vs `'menu'` accordingly
  • Internal bootstrap config object gains a `data: {}` field used to share intent state across modules
  • New internal `at()` utility lazily detects presence of the `intent` URL parameter (result is cached after first call)
26 files changed +825 -709

Infrastructure Changes

REPORT.md
+14 -12
@@ -1,29 +1,30 @@
# Shopify App Bridge — Unminification Report

Generated: 2026-03-07T23:05:59.046Z
Generated: 2026-03-24T11:21:11.827Z

## Files

| File | Size | Lines | Type |
|------|------|-------|------|
| _bootstrap.js | 32.0KB | 1133 | Infrastructure |
| _bootstrap.js | 32.0KB | 1134 | Infrastructure |
| _remote-ui.js | 6.0KB | 256 | Infrastructure |
| _utilities.js | 69.2KB | 2574 | Infrastructure |
| _utilities.js | 70.6KB | 2631 | Infrastructure |
| _web-vitals.js | 11.6KB | 527 | Infrastructure |
| analytics.js | 211B | 11 | Module |
| app.js | 346B | 15 | Module |
| client.js | 303B | 15 | Module |
| environment.js | 223B | 13 | Module |
| environment.js | 241B | 14 | Module |
| fetch.js | 2.8KB | 82 | Module |
| id-token.js | 640B | 28 | Module |
| index.js | 2.1KB | 46 | Index |
| intents.js | 1.2KB | 43 | Module |
| internal-only.js | 607B | 30 | Module |
| id-token.js | 661B | 28 | Module |
| index.js | 2.2KB | 48 | Index |
| intents.js | 2.7KB | 89 | Module |
| internal-only.js | 615B | 30 | Module |
| loading.js | 605B | 31 | Module |
| navigation.js | 408B | 19 | Module |
| navigation.js | 416B | 19 | Module |
| picker.js | 451B | 18 | Module |
| polaris.js | 240B | 12 | Module |
| pos.js | 5.8KB | 251 | Module |
| print.js | 571B | 25 | Module |
| print.js | 556B | 25 | Module |
| resource-picker.js | 2.8KB | 119 | Module |
| reviews.js | 365B | 16 | Module |
| s-app-nav.js | 175B | 10 | Module |
@@ -37,14 +38,15 @@ Generated: 2026-03-07T23:05:59.046Z
| sidekick.js | 4.6KB | 154 | Module |
| support.js | 508B | 21 | Module |
| telemetry.js | 813B | 30 | Module |
| title-bar.js | 7.6KB | 300 | Module |
| title-bar.js | 7.9KB | 307 | Module |
| toast.js | 1.7KB | 73 | Module |
| tools.js | 1.8KB | 66 | Module |
| ui-modal.js | 153B | 10 | Module |
| ui-nav-menu.js | 164B | 10 | Module |
| user.js | 940B | 37 | Module |
| visibility.js | 973B | 34 | Module |
| web-vitals.js | 1.8KB | 64 | Module |
| **Total** | **166.9KB** | **6370** | |
| **Total** | **172.0KB** | **6561** | |

## Pipeline Stages


modules/_bootstrap.js Truncated
+54 -53
@@ -22,7 +22,7 @@
          : t.defer
            ? (console.error('The script tag loading App Bridge has `defer`.'), false)
            : t.src
              ? new URL(t.src).hostname != ut
              ? new URL(t.src).hostname != ft
                ? (console.error(
                    'The script tag loading App Bridge is not loading App Bridge from the Shopify CDN.',
                  ),
@@ -64,7 +64,7 @@
  const { config: i, params: o } = (function () {
    var n;
    const searchParams = new URLSearchParams(location.search);
    const i = lt;
    const i = dt;
    b(
      i,
      (function () {
@@ -94,7 +94,7 @@
          if (o.src)
            try {
              const url = new URL(o.src);
              if (url.hostname === ut && rt.test(url.pathname)) {
              if (url.hostname === ft && st.test(url.pathname)) {
                url.searchParams.forEach((t, n) => {
                  if (t) {
                    e[n] = t;
@@ -125,7 +125,7 @@
            .replace(/shopify-/i, '')
            .toLowerCase()
            .replace(/-+(.)/g, (t, n) => n.toUpperCase());
          e[n] = dt(n, (t = i.getAttribute('content')) != null ? t : undefined);
          e[n] = ht(n, (t = i.getAttribute('content')) != null ? t : undefined);
        }
        return e;
      })(),
@@ -141,7 +141,7 @@
      })(searchParams),
    );
    const o = (function (t) {
      const n = ft.filter((n) => !(n in t));
      const n = pt.filter((n) => !(n in t));
      if (n.length !== 0)
        throw Error('App Bridge Next: missing required configuration fields: ' + n);
      return t;
@@ -161,7 +161,7 @@
  const s = new URL('https://' + r).origin;
  const l =
    globalThis.shopify?.transport ||
    (C() && window === window.top
    (P() && window === window.top
      ? {
          addEventListener: globalThis.addEventListener.bind(globalThis),
          removeEventListener: globalThis.removeEventListener.bind(globalThis),
@@ -182,8 +182,8 @@
  const d = (function (t = false) {
    let n = null;
    let e = t ? null : new Set();
    var i = createPrivateKey('value');
    var o = createPrivateKey('callbacks');
    var i = interceptProperty('value');
    var o = interceptProperty('callbacks');
    class r {
      constructor(t) {
        var n;
@@ -195,24 +195,24 @@
          writable: true,
          value: new Set(),
        });
        checkPrivateField(this, i)[i] = t;
        ORIGINAL_SYMBOL(this, i)[i] = t;
        if (!((n = e) == null)) {
          n.add(this);
        }
      }
      get value() {
        return checkPrivateField(this, i)[i];
        return ORIGINAL_SYMBOL(this, i)[i];
      }
      set value(t) {
        if (t !== checkPrivateField(this, i)[i]) {
          checkPrivateField(this, i)[i] = t;
          checkPrivateField(this, o)[o].forEach((n) => n(t));
        if (t !== ORIGINAL_SYMBOL(this, i)[i]) {
          ORIGINAL_SYMBOL(this, i)[i] = t;
          ORIGINAL_SYMBOL(this, o)[o].forEach((n) => n(t));
        }
      }
      subscribe(t) {
        checkPrivateField(this, o)[o].add(t);
        ORIGINAL_SYMBOL(this, o)[o].add(t);
        return () => {
          checkPrivateField(this, o)[o].delete(t);
          ORIGINAL_SYMBOL(this, o)[o].delete(t);
        };
      }
    }
@@ -276,7 +276,7 @@
              };
            },
          },
          X: {
          K: {
            configurable: true,
            value: 1,
          },
@@ -331,7 +331,7 @@
            },
          };
          e = {
            [wt]: o,
            [yt]: o,
          };
        } else if (t instanceof File) {
          e = {
@@ -340,7 +340,7 @@
              type: t.type,
              lastModified: t.lastModified,
            },
            content: gt(t),
            content: createPrivateKey(t),
          };
        } else {
          if (Array.isArray(t)) {
@@ -358,8 +358,8 @@
        return e;
      };
      const o = (t) => {
        if (t && typeof t == 'object' && wt in t) {
          const e = t[wt];
        if (t && typeof t == 'object' && yt in t) {
          const e = t[yt];
          return n(e);
        }
        return (function (t) {
@@ -376,7 +376,7 @@
            typeof t.content == 'string'
          );
        })(t)
          ? new File([bt(t.content)], t.metadata.name, {
          ? new File([gt(t.content)], t.metadata.name, {
              type: t.metadata.type,
              lastModified: t.metadata.lastModified,
            })
@@ -432,8 +432,8 @@
            } else {
              if (
                !(
                  (ht.test(new URL(t.origin).hostname) && t.origin !== location.origin) ||
                  (C() && t.origin === location.origin)
                  (vt.test(new URL(t.origin).hostname) && t.origin !== location.origin) ||
                  (P() && t.origin === location.origin)
                )
              )
                return;
@@ -462,7 +462,7 @@
    return {
      send: function (t, n) {
        if (t !== 'getState') {
          o('dispatch', vt(t, n));
          o('dispatch', wt(t, n));
        } else {
          o('getState', {});
        }
@@ -480,7 +480,7 @@
        if (!((i = e?.signal) == null)) {
          i.addEventListener('abort', () => abortController.abort());
        }
        const s = vt(
        const s = wt(
          t,
          e.id
            ? {
@@ -511,7 +511,7 @@
        );
        o('subscribe', s);
        r(
          vt('Client.initialize').type,
          wt('Client.initialize').type,
          () => {
            o('unsubscribe', s);
            o('subscribe', s);
@@ -527,6 +527,7 @@
    config: i,
    protocol: w,
    origin: s,
    data: {},
    setSignals(t) {
      d.applyRealSignal(t);
    },
@@ -537,10 +538,10 @@
    value: y,
  });
  const g = new ot();
  const A = createDeferred();
  const A = U();
... (truncated)

Diff truncated at 200 lines

modules/_utilities.js Truncated
+415 -358
@@ -43,21 +43,21 @@ function k(t) {
    return false;
  }
}
function C() {
function P() {
  return k('Unframed') && 'MobileWebView' in window;
}
function P() {
function C() {
  return k('Shopify Mobile');
}
function S() {
  return k('Extensibility');
}
function L() {
function T() {
  return k('Shopify POS');
}
const T = 'app-iframe';
const L = 'app-iframe';
const I = /frame:\/*([^/]+)\/([^/]+)(?:\/([^/]+))?(?:\/([^/]+))?$/;
const M = (() => {
const O = (() => {
  var t;
  const [, n, e, i] = (t = window.name.match(I)) != null ? t : [];
  return {
@@ -66,9 +66,9 @@ const M = (() => {
    mode: i,
  };
})();
const x = window.name.startsWith(T) || M.scope === 'main';
const O = M.scope === 'modal';
const R = [
const M = window.name.startsWith(L) || O.scope === 'main';
const R = O.scope === 'modal';
const x = [
  'hmac',
  'locale',
  'protocol',
@@ -83,7 +83,7 @@ const R = [
];
function $(t) {
  const url = new URL(t);
  R.forEach((t) => url.searchParams.delete(t));
  x.forEach((t) => url.searchParams.delete(t));
  return url;
}
const _ = [
@@ -104,7 +104,7 @@ function subscribeAllErrors(t, n, e) {
    t.subscribe('Error.' + i, n, e);
  });
}
function createDeferred() {
function U() {
  let t;
  let n = false;
  const promise = new Promise((n) => {
@@ -123,7 +123,7 @@ function createDeferred() {
    },
  };
}
function N() {
function createDeferred() {
  let t = Promise.resolve();
  const n = {};
  return {
@@ -132,7 +132,7 @@ function N() {
    },
    has: (t) => !!n[t],
    add(e) {
      const i = createDeferred();
      const i = U();
      n[e] = i;
      t = t.then(() => i.promise);
    },
@@ -149,7 +149,7 @@ function N() {
    },
  };
}
function U({ keys, held, handler, keyEvent: i = 'keydown' }) {
function N({ keys, held, handler, keyEvent: i = 'keydown' }) {
  let o = [];
  const r = (i) => {
    if (keys.flat().includes(i.key)) {
@@ -200,10 +200,10 @@ const q = Symbol();
const W = Symbol();
const V = Symbol();
const z = 'data-save-bar';
const H = 'data-discard-confirmation';
const K = 'ui-save-bar';
const X = 'update';
function G(t, { onChange, filter: e = () => true }) {
const G = 'data-discard-confirmation';
const H = 'ui-save-bar';
const K = 'update';
function X(t, { onChange, filter: e = () => true }) {
  function i() {
    const i = et(t).filter((t) => Q(t) && e(t));
    let o = false;
@@ -213,7 +213,7 @@ function G(t, { onChange, filter: e = () => true }) {
      if (o) break;
    }
    for (const t of i) {
      r = t.hasAttribute(H);
      r = t.hasAttribute(G);
      if (r) break;
    }
    const a = o
@@ -318,7 +318,7 @@ function G(t, { onChange, filter: e = () => true }) {
    subtree: true,
    childList: true,
    attributes: true,
    attributeFilter: [z, H],
    attributeFilter: [z, G],
  });
  return {
    onChange: i,
@@ -335,7 +335,7 @@ function G(t, { onChange, filter: e = () => true }) {
}
function J(t, { onChange, filter: e = () => true }) {
  function i() {
    const l = Array.from(t.querySelectorAll(K)).filter((t) => e(t) && t.showing);
    const l = Array.from(t.querySelectorAll(H)).filter((t) => e(t) && t.showing);
    const u = l.length > 0 ? l[l.length - 1] : undefined;
    const d = u
      ? {
@@ -359,17 +359,17 @@ function J(t, { onChange, filter: e = () => true }) {
    if (
      (n = t.target) &&
      (n instanceof Element || n instanceof it(n).Element) &&
      n.nodeName.toLowerCase() === K
      n.nodeName.toLowerCase() === H
    ) {
      t.stopPropagation();
      i();
    }
  }
  t.addEventListener(X, o);
  t.addEventListener(K, o);
  return {
    onChange: i,
    unobserve: () => {
      t.removeEventListener(X, o);
      t.removeEventListener(K, o);
    },
  };
}
@@ -462,21 +462,32 @@ class ot {
    return !i.defaultPrevented;
  }
}
const rt = /\/app\-?bridge[/.-]/i;
const at = 'https://cdn.shopify.com/shopifycloud/app-bridge.js';
const st =
let rt;
function at() {
  var t;
  if (rt === undefined)
    try {
      rt = new URLSearchParams(window?.location?.search).has('intent');
    } catch (err) {
      rt = false;
    }
  return rt || false;
}
const st = /\/app\-?bridge[/.-]/i;
const ct = 'https://cdn.shopify.com/shopifycloud/app-bridge.js';
const lt =
  (e = typeof document == 'object' ? window.document.currentScript?.src : undefined) != null
    ? e
    : at;
const ct =
    : ct;
const ut =
  (function (t) {
    try {
      return new URL(t).origin;
    } catch (err) {
      return null;
    }
  })(st) || '';
const lt = {
  })(lt) || '';
const dt = {
  apiKey: '',
  appOrigins: [],
  debug: {},
@@ -485,8 +496,8 @@ const lt = {
  locale: 'en-US',
  host: '',
};
const ut = new URL(/^https:\/\/cdn\.shopify(\.com|cdn\.net)$/.test(ct) ? st : at).hostname;
function dt(t, n) {
const ft = new URL(/^https:\/\/cdn\.shopify(\.com|cdn\.net)$/.test(ut) ? lt : ct).hostname;
function ht(t, n) {
... (truncated)

Diff truncated at 200 lines

modules/_web-vitals.js Truncated
+183 -183
@@ -5,7 +5,7 @@
 * @description Web Vitals metrics: CLS, FCP, FID, INP, LCP, TTFB
 */

var le = function (t, n, e) {
var de = function (t, n, e) {
  try {
    if (PerformanceObserver.supportedEntryTypes.includes(t)) {
      var i = new PerformanceObserver(function (t) {
@@ -26,7 +26,7 @@ var le = function (t, n, e) {
    }
  } catch (err) {}
};
var ue = function (t, n, e, i) {
var fe = function (t, n, e, i) {
  var o;
  var r;
  return function (a) {
@@ -40,14 +40,14 @@ var ue = function (t, n, e, i) {
    }
  };
};
var de = function (t) {
var he = function (t) {
  requestAnimationFrame(function () {
    return requestAnimationFrame(function () {
      return t();
    });
  });
};
var fe = function (t) {
var pe = function (t) {
  var n = function (n) {
    if (n.type === 'pagehide' || document.visibilityState === 'hidden') {
      t(n);
@@ -56,7 +56,7 @@ var fe = function (t) {
  addEventListener('visibilitychange', n, true);
  addEventListener('pagehide', n, true);
};
var he = function (t) {
var ve = function (t) {
  var n = false;
  return function (e) {
    if (!n) {
@@ -65,42 +65,42 @@ var he = function (t) {
    }
  };
};
var pe = -1;
var ve = function () {
var me = -1;
var we = function () {
  return document.visibilityState !== 'hidden' || document.prerendering ? 1 / 0 : 0;
};
var me = function (t) {
  if (document.visibilityState === 'hidden' && pe > -1) {
    pe = t.type === 'visibilitychange' ? t.timeStamp : 0;
    be();
var be = function (t) {
  if (document.visibilityState === 'hidden' && me > -1) {
    me = t.type === 'visibilitychange' ? t.timeStamp : 0;
    ge();
  }
};
var we = function () {
  addEventListener('visibilitychange', me, true);
  addEventListener('prerenderingchange', me, true);
var ye = function () {
  addEventListener('visibilitychange', be, true);
  addEventListener('prerenderingchange', be, true);
};
var be = function () {
  removeEventListener('visibilitychange', me, true);
  removeEventListener('prerenderingchange', me, true);
var ge = function () {
  removeEventListener('visibilitychange', be, true);
  removeEventListener('prerenderingchange', be, true);
};
var ye = function () {
  if (pe < 0) {
    pe = ve();
    we();
    re(function () {
var Ae = function () {
  if (me < 0) {
    me = we();
    ye();
    se(function () {
      setTimeout(function () {
        pe = ve();
        we();
        me = we();
        ye();
      }, 0);
    });
  }
  return {
    get firstHiddenTime() {
      return pe;
      return me;
    },
  };
};
var ge = function (t) {
var Ee = function (t) {
  if (document.prerendering) {
    addEventListener(
      'prerenderingchange',
@@ -113,19 +113,19 @@ var ge = function (t) {
    t();
  }
};
var Ae = /* FCPThresholds: FCP thresholds */ [1800, 3e3];
var Ee = function (t, n) {
var ke = /* FCPThresholds: FCP thresholds */ [1800, 3e3];
var Pe = function (t, n) {
  n = n || {};
  ge(function () {
  Ee(function () {
    var e;
    var i = ye();
    var o = ce('FCP');
    var r = le('paint', function (t) {
    var i = Ae();
    var o = ue('FCP');
    var r = de('paint', function (t) {
      t.forEach(function (t) {
        if (t.name === 'first-contentful-paint' /* FCP PerformanceObserver entry type */) {
          r.disconnect();
          if (t.startTime < i.firstHiddenTime) {
            o.value = Math.max(t.startTime - se(), 0);
            o.value = Math.max(t.startTime - le(), 0);
            o.entries.push(t);
            e(true);
          }
@@ -133,11 +133,11 @@ var Ee = function (t, n) {
      });
    });
    if (r) {
      e = ue(t, o, Ae, n.reportAllChanges);
      re(function (i) {
        o = ce('FCP');
        e = ue(t, o, Ae, n.reportAllChanges);
        de(function () {
      e = fe(t, o, ke, n.reportAllChanges);
      se(function (i) {
        o = ue('FCP');
        e = fe(t, o, ke, n.reportAllChanges);
        he(function () {
          o.value = performance.now() - i.timeStamp;
          e(true);
        });
@@ -145,13 +145,13 @@ var Ee = function (t, n) {
    }
  });
};
var ke = /* CLSThresholds: CLS thresholds */ [0.1, 0.25];
var Ce = function (t, n) {
var Ce = /* CLSThresholds: CLS thresholds */ [0.1, 0.25];
var Se = function (t, n) {
  n = n || {};
  Ee(
    he(function () {
  Pe(
    ve(function () {
      var e;
      var i = ce('CLS', 0);
      var i = ue('CLS', 0);
      var o = 0;
      var r = [];
      var a = function (t) {
@@ -174,18 +174,18 @@ var Ce = function (t, n) {
          e();
        }
      };
      var s = le('layout-shift' /* CLS PerformanceObserver entry type */, a);
      var s = de('layout-shift' /* CLS PerformanceObserver entry type */, a);
      if (s) {
        e = ue(t, i, ke, n.reportAllChanges);
        fe(function () {
        e = fe(t, i, Ce, n.reportAllChanges);
        pe(function () {
          a(s.takeRecords());
          e(true);
        });
        re(function () {
        se(function () {
          o = 0;
          i = ce('CLS', 0);
          e = ue(t, i, ke, n.reportAllChanges);
          de(function () {
          i = ue('CLS', 0);
          e = fe(t, i, Ce, n.reportAllChanges);
          he(function () {
            return e();
          });
... (truncated)

Diff truncated at 200 lines

modules/index.js
+2 -0
@@ -10,6 +10,7 @@
// _web-vitals.js   — web-vitals v3 library

// Modules
// analytics.js
// app.js  — App lifecycle and state management
// client.js  — Client initialization and RPC connection
// environment.js  — Environment detection (embedded, mobile, POS)
@@ -38,6 +39,7 @@
// telemetry.js  — Telemetry and analytics reporting
// title-bar.js  — Title bar custom element with breadcrumbs and buttons
// toast.js  — Toast notification (show/clear/action)
// tools.js
// ui-modal.js  — Custom <ui-modal> element
// ui-nav-menu.js  — Custom <ui-nav-menu> element
// user.js  — User information and preferences

Module Changes

modules/environment.js
+4 -3
@@ -5,8 +5,9 @@

const environmentModule = ({ api }) => {
  api.environment = {
    mobile: P(),
    embedded: top !== self || C(),
    pos: L(),
    mobile: C(),
    embedded: top !== self || P(),
    pos: T(),
    intent: at(),
  };
};

modules/fetch.js
+4 -4
@@ -3,8 +3,8 @@
 * Intercepted fetch with auth headers and session token refresh
 */

// Registry entry referenced as: Lt
const Lt = ({ api, protocol, internalApiPromise }) => {
// Registry entry referenced as: It
const It = ({ api, protocol, internalApiPromise }) => {
  const i = self.fetch;
  async function o(t, n) {
    const e = new Headers(n.headers).get('Shopify-Challenge-Required');
@@ -16,7 +16,7 @@ const Lt = ({ api, protocol, internalApiPromise }) => {
          verified: false,
        };
  }
  interceptProperty(globalThis, 'fetch', async function (r, a) {
  Tt(globalThis, 'fetch', async function (r, a) {
    var s;
    const request = new Request(r instanceof Request ? r.clone() : r, a);
    const { appOrigins: l = [] } = api.config;
@@ -78,4 +78,4 @@ const Lt = ({ api, protocol, internalApiPromise }) => {
  });
};

const fetchModule = Lt;
const fetchModule = It;

modules/id-token.js
+3 -3
@@ -3,8 +3,8 @@
 * Session token (ID token) request/response
 */

// Registry entry referenced as: Tt
const Tt = ({ api, protocol, internalApiPromise }) => {
// Registry entry referenced as: deepClone
const deepClone = ({ api, protocol, internalApiPromise }) => {
  api.idToken = async function () {
    const { idToken: t } = (await internalApiPromise) || {};
    return t
@@ -24,4 +24,4 @@ const Tt = ({ api, protocol, internalApiPromise }) => {
  };
};

const idTokenModule = Tt;
const idTokenModule = deepClone;

modules/intents.js
+50 -4
@@ -4,16 +4,34 @@
 */

const intentsModule = ({ api, protocol, internalApiPromise }) => {
  api.data.intent = (function () {
    try {
      const t = new URLSearchParams(location.search).get('intent');
      if (t) {
        const n = JSON.parse(t);
        if (n == null || typeof n != 'object' || Array.isArray(n))
          throw Error('Invalid intent data');
        if (typeof n.type != 'string' || !n.type.length) throw Error('Invalid intent type');
        if (typeof n.action != 'string' || !n.action.length) throw Error('Invalid intent action');
        if (n.data && (typeof n.data != 'object' || Array.isArray(n.data)))
          throw Error('Invalid intent data');
        return n;
      }
    } catch (err) {
      console.error(err);
    }
  })();
  const abortController = new AbortController();
  api.intents = {
    register(t) {
      const e = new URLSearchParams(location.search).get('step_reference') || '';
      const abortController = new AbortController();
      const i = new AbortController();
      protocol.send('AppFrame.requestProperties');
      protocol.subscribe(
        'AppFrame.propertiesEvent',
        ({ properties }) => {
          const o = (function (t, n, e) {
            return new Mt('configure', 'gid://flow/stepReference/' + t, n, () =>
            return new safeAsyncCall('configure', 'gid://flow/stepReference/' + t, n, () =>
              e.send('AppFrame.navigateBack'),
            );
          })(
@@ -26,10 +44,10 @@ const intentsModule = ({ api, protocol, internalApiPromise }) => {
          t(o);
        },
        {
          signal: abortController.signal,
          signal: i.signal,
        },
      );
      return () => abortController.abort();
      return () => i.abort();
    },
    async invoke(t, n) {
      const o = await internalApiPromise;
@@ -39,4 +57,32 @@ const intentsModule = ({ api, protocol, internalApiPromise }) => {
      return new xt(o.intents.invoke(t, n));
    },
  };
  if (at()) {
    async function o() {
      const c = (await internalApiPromise) || {};
      if (
        typeof c.intents?.response?.ok != 'function' ||
        typeof c.intents?.response?.error != 'function' ||
        typeof c.intents?.response?.closed != 'function'
      )
        throw Error('Cannot respond to intent in this context');
      if (abortController.signal.aborted) throw Error('Cannot resolve an intent multiple times');
      abortController.abort();
      return c.intents.response;
    }
    api.intents.response = {
      async ok(t) {
        const n = await o();
        return await n.ok(t);
      },
      async error(t, n) {
        const e = await o();
        return await e.error(t, n);
      },
      async closed() {
        const t = await o();
        return await t.closed();
      },
    };
  }
};

modules/internal-only.js
+1 -1
@@ -8,7 +8,7 @@ const internalOnlyModule = ({ api, internalApiPromise }) => {
    async show(t, e) {
      var i;
      var o;
      const r = deepClone(e);
      const r = SHOPIFY_PROTOCOLS(e);
      const a = await internalApiPromise;
      if (a && a.internalModal) {
        await (i = a.internalModal).show?.call(i, t, r);

modules/navigation.js
+2 -2
@@ -4,13 +4,13 @@
 */

const navigationModule = (t) => {
  const n = zt(t);
  const n = Ht(t);
  t.internalApiPromise.then((e) => {
    const { navigation: i } = e || {};
    if (i?.version === 2)
      try {
        n();
        Vt(t);
        generateId(t);
      } catch (err) {
        console.error('Failed to set up navigation: ' + err);
      }

modules/pos.js
+6 -6
@@ -6,9 +6,9 @@
const posModule = ({ api, protocol }) => {
  const e = new Set();
  async function i(t, i) {
    const o = generateId();
    const o = Yt();
    const abortController = new AbortController();
    const a = createDeferred();
    const a = U();
    protocol.subscribe(
      'Cart.update',
      ({ data }) => {
@@ -30,9 +30,9 @@ const posModule = ({ api, protocol }) => {
  const o = {
    cart: {
      async fetch() {
        const t = generateId();
        const t = Yt();
        const abortController = new AbortController();
        const i = createDeferred();
        const i = U();
        protocol.send('Cart.fetch', {
          id: t,
        });
@@ -200,7 +200,7 @@ const posModule = ({ api, protocol }) => {
      protocol.send('Pos.close');
    },
    async device() {
      const t = createDeferred();
      const t = U();
      protocol.subscribe(
        'getState',
        ({ pos }) => {
@@ -218,7 +218,7 @@ const posModule = ({ api, protocol }) => {
      return t.promise;
    },
    async location() {
      const t = createDeferred();
      const t = U();
      protocol.subscribe(
        'getState',
        ({ pos }) => {

modules/print.js
+3 -3
@@ -4,10 +4,10 @@
 */

const printModule = ({ protocol, internalApiPromise }) => {
  if (P() || L()) {
    interceptProperty(self, 'print', function () {
  if (C() || T()) {
    Tt(self, 'print', function () {
      const i = document.scrollingElement?.scrollHeight || document.body.offsetHeight;
      safeAsyncCall(async () => {
      ALL_PROTOCOLS(async () => {
        const { print: e } = (await internalApiPromise) || {};
        if (e) {
          await e({

modules/resource-picker.js
+3 -3
@@ -9,15 +9,15 @@ const resourcePickerModule = ({ api, protocol, internalApiPromise }) => {
    if (i) return i.finally(() => t(o));
    const r = await internalApiPromise;
    const promise = new Promise((t, e) => {
      const a = generateId();
      const a = Yt();
      const {
        type: s,
        query: c,
        selectionIds: l,
        action: u,
        multiple: d,
      } = Object.assign({}, Yt, o);
      const f = Object.assign({}, Yt.filter, o.filter);
      } = Object.assign({}, Zt, o);
      const f = Object.assign({}, Zt.filter, o.filter);
      if (!set.has(s))
        return e(
          Error(

modules/s-app-nav.js
+3 -3
@@ -3,7 +3,7 @@
 * Custom <s-app-nav> element for app navigation
 */

// Registry entry referenced as: dn
const dn = un('s-app-nav');
// Registry entry referenced as: hn
const hn = fn('s-app-nav');

const sAppNavModule = dn;
const sAppNavModule = hn;

modules/s-app-window.js
+3 -3
@@ -3,9 +3,9 @@
 * Custom <s-app-window> element for app window management
 */

// Registry entry referenced as: Wn
const Wn = Fn('s-app-window', {
// Registry entry referenced as: zn
const zn = Bn('s-app-window', {
  variantLock: 'app-window',
});

const sAppWindowModule = Wn;
const sAppWindowModule = zn;

modules/save-bar.js
+13 -13
@@ -4,11 +4,11 @@
 */

const saveBarModule = ({ api, saveBarManager, internalApiPromise }) => {
  if (x) {
  if (M) {
    api.saveBar = {
      show: async (t) => mn(t).show(),
      hide: async (t) => mn(t).hide(),
      toggle: async (t) => mn(t).toggle(),
      show: async (t) => bn(t).show(),
      hide: async (t) => bn(t).hide(),
      toggle: async (t) => bn(t).toggle(),
      async leaveConfirmation() {
        if (!saveBarManager.isSaveBarVisible) return;
        const t = await internalApiPromise;
@@ -17,7 +17,7 @@ const saveBarModule = ({ api, saveBarManager, internalApiPromise }) => {
        if (i && typeof i.leaveConfirmation == 'function') {
          await i.leaveConfirmation();
        }
        const o = document.querySelectorAll(fn);
        const o = document.querySelectorAll(pn);
        await Promise.all(Array.from(o).map((t) => t.hide()));
        const r = document.querySelectorAll('form');
        await Promise.all(
@@ -27,13 +27,13 @@ const saveBarModule = ({ api, saveBarManager, internalApiPromise }) => {
        );
      },
    };
    G(document, {
    X(document, {
      onChange(t) {
        saveBarManager.set({
          mainAppFromForm: t,
        });
      },
      filter: (t) => !qn(t),
      filter: (t) => !Vn(t),
    });
    J(document, {
      onChange(t) {
@@ -41,10 +41,10 @@ const saveBarModule = ({ api, saveBarManager, internalApiPromise }) => {
          mainAppFromCustomElement: t,
        });
      },
      filter: (t) => !qn(t),
      filter: (t) => !Vn(t),
    });
    y(
      fn,
      pn,
      class extends A {
        constructor() {
          super(...arguments);
@@ -119,10 +119,10 @@ const saveBarModule = ({ api, saveBarManager, internalApiPromise }) => {
          }
        }
        o() {
          on(this, pn);
          an(this, mn);
          this.V();
          this.dispatchEvent(
            new CustomEvent(X, {
            new CustomEvent(K, {
              bubbles: true,
              cancelable: true,
            }),
@@ -131,8 +131,8 @@ const saveBarModule = ({ api, saveBarManager, internalApiPromise }) => {
        V() {
          const t = this.querySelectorAll(':scope > [variant=primary]');
          const n = this.querySelectorAll(':scope > :not([variant=primary])');
          this.q = vn(t[t.length - 1]);
          this.W = vn(n[n.length - 1]);
          this.q = wn(t[t.length - 1]);
          this.W = wn(n[n.length - 1]);
        }
      },
    );

modules/scanner.js
+5 -5
@@ -10,7 +10,7 @@ const scannerModule = ({ api, protocol, internalApiPromise }) => {
      return t?.capture
        ? t.capture()
        : new Promise((t, e) => {
            const i = generateId();
            const i = Yt();
            const abortController = new AbortController();
            const { signal: r } = abortController;
            function a(t) {
@@ -50,11 +50,11 @@ const scannerModule = ({ api, protocol, internalApiPromise }) => {
            protocol.subscribe(
              'getState',
              ({ features }) => {
                if (zn(features)) {
                if (Hn(features)) {
                  s();
                } else {
                  (function () {
                    const t = generateId();
                    const t = Yt();
                    const e = new AbortController();
                    abortController.signal.addEventListener('abort', () => e.abort());
                    subscribeAllErrors(
@@ -71,7 +71,7 @@ const scannerModule = ({ api, protocol, internalApiPromise }) => {
                    protocol.subscribe(
                      'Features.update',
                      ({ features: t }) => {
                        if (zn(t)) {
                        if (Hn(t)) {
                          e.abort();
                          s();
                        }
@@ -84,7 +84,7 @@ const scannerModule = ({ api, protocol, internalApiPromise }) => {
                    protocol.send('Features.request', {
                      id: t,
                      feature: 'Scanner',
                      action: Vn,
                      action: Gn,
                    });
                  })();
                }

modules/share.js
+3 -3
@@ -4,15 +4,15 @@
 */

const shareModule = ({ protocol, internalApiPromise }) => {
  if (!P() && !L()) return;
  if (!C() && !T()) return;
  const e = navigator.share;
  interceptProperty(navigator, 'share', async function (i) {
  Tt(navigator, 'share', async function (i) {
    if (!i) return e.call(navigator, i);
    const { share: o } = (await internalApiPromise) || {};
    const { title: r, text: a, url: s } = i;
    if (!o)
      return new Promise((n, e) => {
        const i = generateId();
        const i = Yt();
        const abortController = new AbortController();
        const { signal: c } = abortController;
        function l(t) {

modules/shortcut.js
+4 -4
@@ -4,10 +4,10 @@
 */

const shortcutModule = ({ protocol, internalApiPromise }) => {
  if (!Hn) {
    Hn = true;
    Kn.forEach((e) => {
      U({
  if (!Kn) {
    Kn = true;
    Xn.forEach((e) => {
      N({
        ...e,
        handler: async () => {
          const { shortcut: i } = (await internalApiPromise) || {};

modules/sidekick.js
+2 -2
@@ -113,7 +113,7 @@ const sidekickModule = ({ api, internalApiPromise, rpcEventTarget }) => {
        u(e);
        e = undefined;
      }
      safeAsyncCall(async () => {
      ALL_PROTOCOLS(async () => {
        const { sidekick: r } = (await internalApiPromise) || {};
        if (!r || typeof r.registerToolHandler != 'function')
          throw Error('Sidekick API is not available');
@@ -136,7 +136,7 @@ const sidekickModule = ({ api, internalApiPromise, rpcEventTarget }) => {
        u(e);
        e = undefined;
      }
      safeAsyncCall(async () => {
      ALL_PROTOCOLS(async () => {
        const { sidekick: r } = (await internalApiPromise) || {};
        if (!r || typeof r.registerContextCallback != 'function')
          throw Error('Sidekick API is not available');

modules/title-bar.js
+34 -27
@@ -26,17 +26,17 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
    var n;
    const i = document.querySelector('s-page');
    if (i) {
      const n = `${In}, ${Mn}, ${xn}`;
      const e = Array.from(i.querySelectorAll(n)).find((n) => n[bn] == t);
      const n = `${Mn}, ${Rn}, ${xn}`;
      const e = Array.from(i.querySelectorAll(n)).find((n) => n[gn] == t);
      if (e) return void e.click();
      const o = Array.from(document.querySelectorAll('s-menu'));
      const o = Array.from(document.querySelectorAll('s-menu, s-button-group'));
      for (const i of o) {
        const n = Array.from(i.querySelectorAll('s-button')).find((n) => n[bn] == t);
        const n = Array.from(i.querySelectorAll('s-button')).find((n) => n[gn] == t);
        if (n) return void n.click();
      }
    }
    const o = Array.from((n = e?.querySelectorAll('button, a')) != null ? n : []).find(
      (n) => n[bn] == t,
      (n) => n[gn] == t,
    );
    if (!(o == null)) {
      o.click();
@@ -69,10 +69,10 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
    let p;
    (function () {
      var t;
      const i = document.documentElement?.getElementsByTagName?.call(t, Pn);
      const i = document.documentElement?.getElementsByTagName?.call(t, Tn);
      if (i && i.length) {
        for (const o of i)
          if (!qn(o)) {
          if (!Vn(o)) {
            e = o;
            break;
          }
@@ -104,7 +104,7 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
        };
      }
    } else {
      const t = yn({
      const t = An({
        hideElements: true,
        context: document,
      });
@@ -113,17 +113,17 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
          title: t.title || o(),
        };
        if (t.breadcrumb) {
          t.breadcrumb[bn] = 'breadcrumb';
          p.breadcrumbs = gn(t.breadcrumb);
          t.breadcrumb[gn] = 'breadcrumb';
          p.breadcrumbs = En(t.breadcrumb);
        }
        if (t.primaryAction) {
          const n = gn(t.primaryAction);
          const n = En(t.primaryAction);
          p.buttons = Object.assign((u = p.buttons) != null ? u : {}, {
            primary: n,
          });
        }
        if (t.secondaryActions) {
          const n = An(t.secondaryActions, {
          const n = kn(t.secondaryActions, {
            hideElements: true,
            context: document,
          });
@@ -186,7 +186,7 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
  });
  new MutationObserver((t) => {
    for (let n of t) {
      if (Rn(n.target) || [].some.call(n.addedNodes, $n) || [].some.call(n.removedNodes, $n))
      if (_n(n.target) || [].some.call(n.addedNodes, Fn) || [].some.call(n.removedNodes, Fn))
        return s();
      const t = n.target instanceof Element ? n.target : n.target.parentElement;
      if (
@@ -207,17 +207,17 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
  protocol.subscribe('TitleBar.breadcrumbs.button.click', (t) => r?.(t.id));
  protocol.subscribe('MarketingExternalActivityTopBar.buttons.button.click', (t) => r?.(t.id));
  y(
    Pn,
    Tn,
    class extends A {
      static get observedAttributes() {
        return ['title'];
      }
      connectedCallback() {
        this.u = new MutationObserver(() => {
          if (!qn(this)) {
          if (!Vn(this)) {
            this.o();
          }
          this.H();
          this.G();
        });
        this.u.observe(this, {
          childList: true,
@@ -227,18 +227,18 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
        });
        this.o();
      }
      K() {
      H() {
        const t = this.querySelector(':scope > [variant=breadcrumb]');
        if (t) {
          t[bn] = 'breadcrumb';
          t[gn] = 'breadcrumb';
        }
        return t;
      }
      H() {
      G() {
        this.dispatchEvent(new Event('change'));
      }
      o() {
        on(this, Tn);
        an(this, On);
        s();
      }
      disconnectedCallback() {
@@ -252,7 +252,7 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
        this.o();
      }
      buttons() {
        const t = this.K();
        const t = this.H();
        const n = this.querySelector(':scope > [variant=primary]');
        const e = Array.from(
          this.querySelectorAll(
@@ -260,22 +260,29 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
          ),
        ).map((t) =>
          t.nodeName !== 'SECTION'
            ? On(t)
            ? $n(t)
            : (function (t) {
                var n;
                if (!t[bn]) {
                  t[bn] = generateId();
                if (!t[gn]) {
                  t[gn] = Yt();
                }
                const e = t[bn];
                const e = t[gn];
                const i = (n = t.getAttribute('label')) != null ? n : 'Actions';
                const o = t.getAttribute('icon') || undefined;
                const r =
                  t.tagName === 'S-MENU'
                    ? 'menu'
                    : t.tagName === 'S-BUTTON-GROUP'
                      ? 'inline'
                      : undefined;
                return {
                  id: e,
                  label: i,
                  ...(o && {
                    icon: o,
                  }),
                  buttons: Array.from(t.querySelectorAll('button, a')).map(On),
                  buttons: Array.from(t.querySelectorAll('button, a')).map($n),
                  groupType: r,
                };
              })(t),
        );
@@ -287,7 +294,7 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
            : {}),
          ...(n
            ? {
                primaryButton: On(n),
                primaryButton: $n(n),
              }
            : {}),
          secondaryButtons: e,

modules/toast.js
+5 -5
@@ -6,12 +6,12 @@
const toastModule = ({ api, protocol, internalApiPromise }) => {
  api.toast = {
    show(t, i = {}) {
      const o = generateId();
      safeAsyncCall(async () => {
      const o = Yt();
      ALL_PROTOCOLS(async () => {
        const { toast: r } = (await internalApiPromise) || {};
        if (r?.show)
          await r.show(t, {
            ...Xn,
            ...Jn,
            ...i,
            id: o,
          });
@@ -23,7 +23,7 @@ const toastModule = ({ api, protocol, internalApiPromise }) => {
            isError: s,
            onAction: c,
            onDismiss: l,
          } = Object.assign({}, Xn, i);
          } = Object.assign({}, Jn, i);
          protocol.subscribe('Toast.action', () => c?.(), {
            id: o,
            signal: abortController.signal,
@@ -57,7 +57,7 @@ const toastModule = ({ api, protocol, internalApiPromise }) => {
      return o;
    },
    hide(t) {
      safeAsyncCall(async () => {
      ALL_PROTOCOLS(async () => {
        const { toast: i } = (await internalApiPromise) || {};
        if (i?.hide) {
          await i.hide(t);

modules/ui-modal.js
+3 -3
@@ -3,7 +3,7 @@
 * Custom <ui-modal> element
 */

// Registry entry referenced as: Gn
const Gn = Fn('ui-modal');
// Registry entry referenced as: Yn
const Yn = Bn('ui-modal');

const uiModalModule = Gn;
const uiModalModule = Yn;

modules/ui-nav-menu.js
+3 -3
@@ -3,7 +3,7 @@
 * Custom <ui-nav-menu> element
 */

// Registry entry referenced as: Jn
const Jn = un('ui-nav-menu');
// Registry entry referenced as: Qn
const Qn = fn('ui-nav-menu');

const uiNavMenuModule = Jn;
const uiNavMenuModule = Qn;

modules/web-vitals.js
+3 -3
@@ -4,7 +4,7 @@
 */

const webVitalsModule = async ({ api, protocol, internalApiPromise, rpcEventTarget }) => {
  if (typeof window == 'undefined' || window.__is_web_vitals_initialized__ || L() || (P() && !S()))
  if (typeof window == 'undefined' || window.__is_web_vitals_initialized__ || T() || (C() && !S()))
    return;
  window.__is_web_vitals_initialized__ = true;
  let o = null;
@@ -17,7 +17,7 @@ const webVitalsModule = async ({ api, protocol, internalApiPromise, rpcEventTarg
      }
    },
  };
  const r = await Promise.resolve().then(() => Ye);
  const r = await Promise.resolve().then(() => Ze);
  const { config: a } = (await api) || {};
  const { webVitals: s } = (await internalApiPromise) || {};
  const c = !!s;
@@ -25,7 +25,7 @@ const webVitalsModule = async ({ api, protocol, internalApiPromise, rpcEventTarg
    reportAllChanges: c,
  };
  let u = true;
  Yn.forEach(({ fn: t, name }) => {
  Zn.forEach(({ fn: t, name }) => {
    r[t](
      ((t) => async (i) => {
        if (c && typeof s?.report == 'function') {