All entries

September 16, 2026

df7e36cefa61036cd05ebe4133b153030760eee4e978c43d583650ee21294a01
Previous: e57eeaec Bundle: 95.9 KB

The shopifyQL module gained new availability, readiness, context, and metric-tracking APIs.

Highlights

  • Added api.shopifyQL.available() to asynchronously check whether the ShopifyQL API is present.
  • Added api.shopifyQL.ready() which checks hasPermissions and falls back after a 30 second timeout.
  • Added an internal getContext() method that throws an error if the ShopifyQL API is not available.
  • Added trackMetricCard() to report metric card analytics events through the ShopifyQL API.
  • Added a registerAnalyticsUiReady hook tied to a new internal ready promise for the ShopifyQL module.
11 files changed +66 -24

Infrastructure Changes

REPORT.md
+5 -5
@@ -1,6 +1,6 @@
# Shopify App Bridge — Unminification Report

Generated: 2026-09-15T08:03:57.378Z
Generated: 2026-09-16T08:04:17.824Z

## Files

@@ -8,7 +8,7 @@ Generated: 2026-09-15T08:03:57.378Z
|------|------|-------|------|
| _bootstrap.js | 30.1KB | 1051 | Infrastructure |
| _remote-ui.js | 6.1KB | 257 | Infrastructure |
| _utilities.js | 77.7KB | 2912 | Infrastructure |
| _utilities.js | 77.5KB | 2912 | Infrastructure |
| _web-vitals.js | 11.6KB | 527 | Infrastructure |
| analytics.js | 211B | 11 | Module |
| app.js | 346B | 15 | Module |
@@ -24,7 +24,7 @@ Generated: 2026-09-15T08:03:57.378Z
| picker.js | 451B | 18 | Module |
| polaris.js | 240B | 12 | Module |
| pos.js | 5.7KB | 248 | Module |
| print.js | 556B | 25 | Module |
| print.js | 545B | 25 | Module |
| resource-picker.js | 2.8KB | 117 | Module |
| reviews.js | 365B | 16 | Module |
| s-app-nav.js | 175B | 10 | Module |
@@ -33,7 +33,7 @@ Generated: 2026-09-15T08:03:57.378Z
| scanner.js | 2.9KB | 101 | Module |
| scopes.js | 797B | 26 | Module |
| share.js | 1.3KB | 58 | Module |
| shopifyQL.js | 262B | 12 | Module |
| shopifyQL.js | 1.2KB | 55 | Module |
| shortcut.js | 461B | 24 | Module |
| sidekick.js | 5.3KB | 179 | Module |
| support.js | 508B | 21 | Module |
@@ -46,7 +46,7 @@ Generated: 2026-09-15T08:03:57.378Z
| user.js | 940B | 37 | Module |
| visibility.js | 973B | 34 | Module |
| web-vitals.js | 1.9KB | 66 | Module |
| **Total** | **179.7KB** | **6832** | |
| **Total** | **180.4KB** | **6875** | |

## Pipeline Stages


modules/_bootstrap.js Truncated
+4 -4
@@ -498,7 +498,7 @@
        window.shopify = n.shopify;
        window.polaris = n.polaris;
        const t = window.open;
        safeAsyncCall(self, 'open', function (n, e, i) {
        Mt(self, 'open', function (n, e, i) {
          return n != null && on(n).protocol !== 'https:'
            ? window.opener.open(n, e, i)
            : t.call(this, n, e, i);
@@ -989,43 +989,43 @@
  w.send('Loading.stop');
  v.ready = Promise.resolve();
})();
var Re;
var xe;
var Oe;
var _e;
var Fe;
var Ue = -1;
var Ue;
var Be = function (t) {
var Be = -1;
var je = function (t) {
  addEventListener(
    'pageshow',
    function (n) {
      if (n.persisted) {
        t(n);
      }
    },
    true,
  );
};
  return (
    window.performance &&
    performance.getEntriesByType &&
    performance.getEntriesByType('navigation')[0]
  );
};
  return (t && t.activationStart) || 0;
... (truncated)

Diff truncated at 200 lines

modules/_utilities.js Truncated
+6 -6
@@ -200,18 +200,18 @@ function D() {
}
const N = Symbol();
const q = Symbol();
const V = Symbol();
const W = Symbol();
const H = Symbol();
const H = 'data-save-bar';
const V = 'data-save-bar';
const z = 'data-discard-confirmation';
const J = 'ui-save-bar';
const X = 'update';
const set = new Set();
  for (const t of set) t.settle();
}
  let i = false;
  let o = null;
  function r() {
@@ -602,14 +602,14 @@ function restoreProperty(t) {
    }
  }
}
function ORIGINAL_SYMBOL(t, n) {
function Tt(t, n) {
  if (!{}.hasOwnProperty.call(t, n))
    throw new TypeError('attempted to use private field on non-instance');
  return t;
}
var Tt = 0;
var ORIGINAL_SYMBOL = 0;
function Lt(t) {
  return `__private_${Tt++}_${t}`;
  return `__private_${ORIGINAL_SYMBOL++}_${t}`;
}
function It(t = false) {
  let n = null;
@@ -627,24 +627,24 @@ function It(t = false) {
        writable: true,
        value: new Set(),
      });
      ORIGINAL_SYMBOL(this, i)[i] = t;
      Tt(this, i)[i] = t;
      if (!((n = e) == null)) {
        n.add(this);
      }
    }
... (truncated)

Diff truncated at 200 lines

modules/_web-vitals.js Truncated
+0 -1
@@ -194,57 +194,57 @@ var ii = function (t, n) {
    }),
  );
};
  passive: true,
  capture: true,
};
  }
};
    var t = {
      entryType: 'first-input' /* FID PerformanceObserver entry type */,
      name: Re.type,
... (truncated)

Diff truncated at 200 lines

Module Changes

modules/fetch.js
+1 -1
@@ -23,7 +23,7 @@ const deepClone = ({ api, protocol, internalApiPromise }) => {
          verified: false,
        };
  }
  safeAsyncCall(globalThis, 'fetch', async function (a, s) {
  Mt(globalThis, 'fetch', async function (a, s) {
    const request = new Request(a instanceof Request ? a.clone() : a, s);
    const { appOrigins: u = [] } = api.config;
    const url = new URL(request.url);
modules/print.js
+1 -1
@@ -4,8 +4,8 @@
 */

const printModule = ({ protocol, internalApiPromise }) => {
    safeAsyncCall(self, 'print', function () {
    Mt(self, 'print', function () {
      const e = document.scrollingElement?.scrollHeight || document.body.offsetHeight;
      Dt(async () => {
        const { print: i } = (await internalApiPromise) || {};

modules/share.js
+1 -1
@@ -4,9 +4,9 @@
 */

const shareModule = ({ protocol, internalApiPromise }) => {
  const e = navigator.share;
  safeAsyncCall(navigator, 'share', async function (i) {
  Mt(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;

modules/shopifyQL.js
+44 -1
@@ -7,5 +7,48 @@ const shopifyQLModule = ({ api, internalApiPromise }) => {
  const e = Promise.resolve(internalApiPromise)
    .then((t) => t?.shopifyQL ?? null)
    .catch(() => null);
  api.shopifyQL = Pe(e);
  let i;
  const promise = new Promise((t) => {
    i = t;
  });
  promise.catch(() => {});
  const r = Se(e);
  const a = r.__internal;
  r.__internal = a;
  r.available = () => e.then((t) => t != null);
  r.ready = async () => {
    let t;
    try {
      return await Promise.race([
        (async () => {
          const t = await e;
          if (!t) return Ee;
          const n = await t.hasPermissions();
          return n.isAvailable ? (await promise, n) : n;
        })(),
        new Promise((n) => {
          t = setTimeout(() => {
            n(Ee);
          }, 3e4);
        }),
      ]);
    } catch {
      return Ee;
    } finally {
      clearTimeout(t);
    }
  };
  a.getContext = async () => {
    const t = await e;
    if (!t) throw Error('ShopifyQL API is not available');
    return t.getContext();
  };
  a.registerAnalyticsUiReady = i;
  a.trackMetricCard = async (t) => {
    const n = await e;
    if (n) {
      await n.trackMetricCard(t);
    }
  };
  api.shopifyQL = r;
};

modules/title-bar.js
+2 -2
@@ -280,9 +280,9 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
                const n = t[zn];
                const e = t.getAttribute('label') ?? 'Actions';
                const i = t.getAttribute('icon') || undefined;
                const o = generateId(t.tagName, 's-menu')
                const o = Yt(t.tagName, 's-menu')
                  ? 'menu'
                  : generateId(t.tagName, 's-button-group')
                  : Yt(t.tagName, 's-button-group')
                    ? 'inline'
                    : undefined;
                return {

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

// Registry entry referenced as: Le
// Registry entry referenced as: Ie


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

// Registry entry referenced as: Ie
// Registry entry referenced as: $e