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.
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();