All entries

October 10, 2026

25da58b49ad13dc7ed9b713119f713c33421e1a284d897a09a525892a334781a
Previous: fdd8d994 Bundle: 98.7 KB

Sidekick API gains surface availability checks, bar visibility control, and stricter open() handling for the mobile online store editor.

Highlights

  • sidekick.isSurfaceAvailable(surface) is a new method that reports whether the 'mobile-web-online-store-editor' surface is available.
  • sidekick.open() now accepts an optional { surface: 'mobile-web-online-store-editor' } argument, returns a boolean for surface opens, and throws a TypeError for unsupported surface arguments.
  • A new sidekick.setBarVisibility(value) method forwards bar visibility changes to the internal Sidekick API.
  • The shopify:sidekick:surfaceavailabilitychange event is now re-dispatched on globalThis when the host reports surface availability changes.
  • sidekick.toggle() now checks for the open and close APIs instead of launch, and uses isOpen to choose between opening and closing.
  • title-bar action objects now appear to emit a tone property in place of icon in their built action payload.
11 files changed +73 -38

Infrastructure Changes

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

Generated: 2026-10-08T08:06:15.850Z
Generated: 2026-10-10T08:03:46.944Z

## Files

@@ -8,7 +8,7 @@ Generated: 2026-10-08T08:06:15.850Z
|------|------|-------|------|
| _bootstrap.js | 30.7KB | 1071 | Infrastructure |
| _remote-ui.js | 6.4KB | 267 | Infrastructure |
| _utilities.js | 78.2KB | 2930 | Infrastructure |
| _utilities.js | 78.1KB | 2930 | Infrastructure |
| _web-vitals.js | 11.6KB | 527 | Infrastructure |
| analytics.js | 211B | 11 | Module |
| app-modal.js | 1.2KB | 60 | Module |
@@ -19,13 +19,13 @@ Generated: 2026-10-08T08:06:15.850Z
| id-token.js | 941B | 34 | Module |
| index.js | 2.2KB | 49 | Index |
| intents.js | 3.1KB | 106 | Module |
| internal-only.js | 528B | 26 | Module |
| internal-only.js | 540B | 26 | Module |
| loading.js | 605B | 31 | Module |
| navigation.js | 408B | 19 | Module |
| picker.js | 451B | 18 | Module |
| polaris.js | 240B | 12 | Module |
| pos.js | 5.7KB | 248 | Module |
| print.js | 568B | 25 | Module |
| print.js | 556B | 25 | Module |
| resource-picker.js | 2.8KB | 117 | Module |
| reviews.js | 365B | 16 | Module |
| s-app-nav.js | 175B | 10 | Module |
@@ -36,18 +36,18 @@ Generated: 2026-10-08T08:06:15.850Z
| share.js | 1.3KB | 58 | Module |
| shopifyQL.js | 1.2KB | 55 | Module |
| shortcut.js | 461B | 24 | Module |
| sidekick.js | 5.3KB | 179 | Module |
| sidekick.js | 6.7KB | 217 | Module |
| support.js | 508B | 21 | Module |
| telemetry.js | 1.1KB | 46 | Module |
| title-bar.js | 8.4KB | 317 | Module |
| toast.js | 1.6KB | 71 | Module |
| tools.js | 2.2KB | 75 | Module |
| tools.js | 2.1KB | 75 | 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.9KB | 66 | Module |
| **Total** | **183.5KB** | **6995** | |
| **Total** | **184.7KB** | **7033** | |

## Pipeline Stages


modules/_remote-ui.js Truncated
+0 -2
@@ -137,59 +137,59 @@ function m(t) {
            }, {}),
            t,
          ];
          return n;
        }
      }
          const e = [
            {
              [remoteFunctionMarker]: t,
            },
          ];
          return e;
        }
        const a = [
          {
          },
        ];
        return a;
      }
      return s;
    },
    decode: u,
    async call(t, n) {
      try {
      } finally {
      }
    },
    release(t) {
      const o = e.get(t);
      if (o) {
... (truncated)

Diff truncated at 200 lines

modules/_utilities.js Truncated
+4 -4
@@ -102,12 +102,12 @@ const U = [
  'UnexpectedAction',
  'UnsupportedOperation',
];
  });
}
function D() {
function createDeferred() {
  let t;
  let n = false;
  const promise = new Promise((n) => {
@@ -126,7 +126,7 @@ function D() {
    },
  };
}
function createDeferred() {
function D() {
  let t = Promise.resolve();
  const n = {};
  return {
@@ -135,9 +135,9 @@ function createDeferred() {
    },
    has: (t) => !!n[t],
    add(e) {
      const o = D();
      const i = createDeferred();
    },
    resolve(t) {
      const e = n[t];
@@ -212,34 +212,34 @@ function Z() {
  for (const t of K) t.settle();
}
function tt(t, { onChange, filter: e = () => true }) {
  function r() {
  }
  function a(t) {
  }
  function s() {
    const e = r();
    let o = false;
    let i = false;
    let o = false;
    for (const t of e) {
    }
    for (const t of e) {
    }
      ? {
          saveButton: {
            onAction: () =>
              (function (t) {
                for (const n of st(t))
                    rt(n);
                  }
              })(t),

Diff truncated at 200 lines

Module Changes

modules/intents.js
+2 -2
@@ -43,8 +43,8 @@ const intentsModule = ({ api, protocol, internalApiPromise, signalFactory }) =>
      protocol.subscribe(
        'AppFrame.propertiesEvent',
        ({ properties }) => {
            return new Ut('configure', 'gid://flow/stepReference/' + t, n, () =>
            return new parseUrl('configure', 'gid://flow/stepReference/' + t, n, () =>
              e.send('AppFrame.navigateBack'),
            );
          })(
@@ -63,20 +63,20 @@ const intentsModule = ({ api, protocol, internalApiPromise, signalFactory }) =>
      return () => abortController.abort();
    },
    async invoke(t, n) {
        throw Error('Intents are not supported');
      return new parseUrl(o.intents.invoke(t, n));
      return new Ut(i.intents.invoke(t, n));
    },
  };
  internalApiPromise.then((t) => {
    const n = t?.intents?.request;
    if (n && typeof n.subscribe == 'function') {
      r?.();
      r = n.subscribe((t) => {
      });
    }
  });
modules/internal-only.js
+1 -1
@@ -6,10 +6,10 @@
const internalOnlyModule = ({ api, internalApiPromise }) => {
  const e = {
    async show(t, e) {
      const o = Dt(e);
      const i = CLICKABLE_TAGS(e);
      }
    },
    async hide(t) {

modules/pos.js Truncated
+2 -2
@@ -5,10 +5,10 @@

const posModule = ({ api, protocol }) => {
  const e = new Set();
    const abortController = new AbortController();
    const a = D();
    const a = createDeferred();
    protocol.subscribe(
      'Cart.update',
      ({ data }) => {
@@ -17,22 +17,22 @@ const posModule = ({ api, protocol }) => {
      },
      {
        signal: abortController.signal,
      },
    );
    protocol.send('Cart.' + t, {
    });
    const s = await a.promise;
    e.forEach((t) => t(s));
  }
    cart: {
      async fetch() {
        const t = wn();
        const abortController = new AbortController();
        const o = D();
        const i = createDeferred();
        protocol.send('Cart.fetch', {
          id: t,
        });

Diff truncated at 200 lines

modules/print.js
+1 -1
@@ -4,13 +4,13 @@
 */

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

modules/sidekick.js Truncated
+48 -11
@@ -4,16 +4,34 @@
 */

const sidekickModule = ({ api, internalApiPromise, rpcEventTarget }) => {
    const { sidekick: t } = (await internalApiPromise) || {};
    if (!t || typeof t.isOpen != 'function') throw Error('Sidekick API is not available');
    return t.isOpen();
  };
  const i = async () => {
  async function o(...t) {
    const { sidekick: t } = (await internalApiPromise) || {};
    const e = t[0];
    if (!t || typeof t.open != 'function') throw Error('Sidekick API is not available');
    const i =
    return t.open();
      e !== null && typeof e == 'object' && Object.prototype.hasOwnProperty.call(e, 'surface');
  };
    if (
      i &&
      (t.length !== 1 ||
        Array.isArray(e) ||
        Object.keys(e).length !== 1 ||
        e.surface !== 'mobile-web-online-store-editor')
    )
      throw new TypeError('sidekick.open expected exactly one supported surface');
    const { sidekick: o } = (await internalApiPromise) || {};
    if (i)
      return !(
        !o ||
        typeof o.isSurfaceAvailable != 'function' ||
        typeof o.open != 'function' ||
        !(await o.open(e))
      );
    if (!o || typeof o.open != 'function') throw Error('Sidekick API is not available');
    await o.open();
  }
  const r = async () => {
    const { sidekick: t } = (await internalApiPromise) || {};
    if (!t || typeof t.close != 'function') throw Error('Sidekick API is not available');
@@ -35,6 +53,13 @@ const sidekickModule = ({ api, internalApiPromise, rpcEventTarget }) => {
          }),
        );
      });
      rpcEventTarget.addEventListener('shopify:sidekick:surfaceavailabilitychange', (t) => {
        globalThis.dispatchEvent(
          new CustomEvent('shopify:sidekick:surfaceavailabilitychange', {
            detail: t.detail,
          }),
        );
      });
    }
  });
  const a = {
@@ -49,39 +74,52 @@ const sidekickModule = ({ api, internalApiPromise, rpcEventTarget }) => {
        throw Error('Sidekick API is not available');
      return t.isMaintenanceActive();
    },
    isSurfaceAvailable: async (t) => {
      if (t !== 'mobile-web-online-store-editor')
        throw new TypeError('sidekick.isSurfaceAvailable expected a supported surface');
      const { sidekick: e } = (await internalApiPromise) || {};
      return !(!e || typeof e.isSurfaceAvailable != 'function' || !(await e.isSurfaceAvailable(t)));
    },
    close: r,
    toggle: async () => {
      const { sidekick: t } = (await internalApiPromise) || {};
      if (!t || typeof t.launch != 'function') throw Error('Sidekick API is not available');
      if (!t || typeof t.open != 'function' || typeof t.close != 'function')
      return (await o()) ? r() : i();
        throw Error('Sidekick API is not available');
      return (await i()) ? r() : o();
    },
    setBarVisibility: async (t) => {
      const { sidekick: e } = (await internalApiPromise) || {};
      if (!e || typeof e.setBarVisibility != 'function')
        throw Error('Sidekick API is not available');
      return e.setBarVisibility(t);
    },
    generate: async (t) => {
      const { sidekick: e } = (await internalApiPromise) || {};
      if (!e || typeof e.generate != 'function') throw Error('Sidekick API is not available');
        start(t) {
        },
      });
      const r = await e.generate({
        ...t,
        onStreamEvent: (n) => {
          if (n.event === 'message') {
          }
          t.onStreamEvent?.(n);
        },
      });
      u(r);
      r.done().finally(() => {
      });
      return {
        ...r,
      };
    },
    launch: async (t) => {
@@ -108,69 +146,69 @@ const sidekickModule = ({ api, internalApiPromise, rpcEventTarget }) => {
    },
    registerToolHandler: (t) => {
      let e;
        e?.();
        f(e);
        e = undefined;
      }
      CLICKABLE_TAGS(async () => {
      Dt(async () => {
        const { sidekick: r } = (await internalApiPromise) || {};
        if (!r || typeof r.registerToolHandler != 'function')
          throw Error('Sidekick API is not available');
        e = await r.registerToolHandler(t);
        u(e);
        }
      });
    },
    registerContextCallback: async (t) => {
      let e;
        e?.();
        f(e);
        e = undefined;
      }
      CLICKABLE_TAGS(async () => {
      Dt(async () => {
        const { sidekick: r } = (await internalApiPromise) || {};
        if (!r || typeof r.registerContextCallback != 'function')
          throw Error('Sidekick API is not available');
        e = await r.registerContextCallback(t);
        u(e);
        }
      });
    },
    registerNavigationReadinessProvider: (t) => {
      let e;
        e?.();
        f(e);
        e = undefined;
      }
      CLICKABLE_TAGS(async () => {
      Dt(async () => {
        const { sidekick: r } = (await internalApiPromise) || {};
          if (!r || typeof r.registerNavigationReadinessProvider != 'function')
            throw Error('Sidekick API is not available');
          e = await r.registerNavigationReadinessProvider(t);
          u(e);
          if (o) {
... (truncated)

Diff truncated at 200 lines

modules/title-bar.js
+3 -3
@@ -10,41 +10,41 @@ const titleBarModule = ({ protocol, internalApiPromise }) => {
      'getState',
      ({ features }) => {
        const e = features?.MarketingExternalActivityTopBar || {};
      },
      {
        once: true,
      },
    );
  });
    if (e) return e.getAttribute('title') ?? document.title;
  }
  function r(t) {
    const n = Xt(document);
    if (n) {
      const e = `${re}, ${ae}, ${se}`;
        if (e) return void e.click();
      }
    }
  }
  function a(t) {
    return {
      label: e,
      ...(o && {
        icon: o,
      }),
      ...(i && {
      }),
      ...(o && {
        tone: o,
      }),
      ...(c !== undefined && {
        pressed: c,
modules/toast.js
+2 -2
@@ -5,15 +5,15 @@

const toastModule = ({ api, protocol, internalApiPromise }) => {
  api.toast = {
      CLICKABLE_TAGS(async () => {
      Dt(async () => {
        const { toast: r } = (await internalApiPromise) || {};
        if (r?.show)
          await r.show(t, {
            ...Oe,
          });
        else {
          const abortController = new AbortController();
@@ -52,13 +52,13 @@ const toastModule = ({ api, protocol, internalApiPromise }) => {
          });
        }
      });
    },
    hide(t) {
      CLICKABLE_TAGS(async () => {
      Dt(async () => {
        } else {
          protocol.send('Toast.clear', {
            id: t,

modules/tools.js
+3 -3
@@ -4,16 +4,16 @@

const toolsModule = async ({ api, internalApiPromise }) => {
  const map = new Map();
  api.tools = {
      const abortController = new AbortController();
      CLICKABLE_TAGS(async () => {
      Dt(async () => {
        if (abortController.signal.aborted) return;
        map.get(t)?.();
          t,
          (function (t) {
            return async (...n) => {
@@ -46,25 +46,25 @@ const toolsModule = async ({ api, internalApiPromise }) => {
    },
    unregister(t) {
      const abortController = new AbortController();
      map.get(t)?.();
      map.delete(t);
      CLICKABLE_TAGS(async () => {
      Dt(async () => {
        const { tools: e } = (await internalApiPromise) || {};
        if (!abortController.signal.aborted) {
          if (!e || typeof e.unregister != 'function') throw Error('Tools API is not available');
          await e.unregister(t);
        }
      }).finally(() => {
      });
    },
    clear() {
      map.forEach((t) => t());
      map.clear();
      CLICKABLE_TAGS(async () => {
      Dt(async () => {
        const { tools: t } = (await internalApiPromise) || {};
        if (!t || typeof t.clear != 'function') throw Error('Tools API is not available');
        await t.clear();