AppbrewDevelopers
Changelog

0.27.0

App extension host, PLP grid density, in-app update, Shopify redirect deep links, two new integrations.

Contains native changes

In-app update ships a new native module, and the iOS web view changed. Picking up either needs a store release — a config publish is not enough. Everything else in this release is JavaScript and needs only an app build at 0.27.0.

Breaking

Three changes can stop your code compiling on 0.27.0. Read these before you upgrade.

  • PLP product-card registration was removed. registerPLPProductCardComponent, getPLPProductCardComponent, and the PLPProductCardProps type are gone from @gauntlet/brewery. Cards are now registered by variant key: app.components.register('product-card', '<variant>', Card). A product-grid block selects one with options.productCardVariant. Any app that overrode the PLP card must migrate.
  • ICatalogProvider gained three required methods: handleToId, idToHandle, and resolveRedirect. A partner package implementing a custom catalog provider will no longer type-check until it adds them.
  • CommonBlockKey is now string rather than a union of known block ids, so remote bundles can register ids the platform has never heard of. Not a compile break, but code relying on exhaustive narrowing loses it.

New

App extension host@gauntlet/brewery now exports an app object that owns registration and behavior: app.components.register, app.modules.register, app.trackers.add, app.actions.define/extend/run, and app.events.on/emit. Every registration returns an undo. app.actions.extend lets an integration gate, reshape, replace, or observe built-in actions like cart:add and checkout:begin without the app owner editing their code; see Extending app behavior. The existing blockRegistry pattern still works.

Result return values@gauntlet/types adds Result with ok, err, isOk, isErr, and toDisplayMessage. Every app.actions.run returns one instead of throwing, so a blocked action comes back with a reason you can show.

onConfigReady(cb) — a one-shot callback in @gauntlet/state for "app config has landed", replacing config.init(...).then(...).

PLP grid density — product listings can offer several column layouts, with a shopper-facing density toggle in the sort-and-filter row. Layouts are authored per block (options.gridLayouts, each { id, columns, productCardVariant? }) with per-layout styling, and the shopper's choice carries across listings. Build your own toggle with the new usePlpGridToggle() hook from @gauntlet/state. Page-size counts authored for a 2-up grid scale automatically so rows-per-page stay constant at other densities.

Forced and flexible in-app update — a config-driven update gate under settings.global.appUpdate: a blocking overlay when the installed version is below minRequiredVersion, or (on Android) a background download with install prompts. The iOS version check is scoped to the store's country, which fixes apps published outside the US. Adds the in-app-update common block. Requires the new native module, and degrades to the older prompt if the app has not been rebuilt.

Shopify URL redirects on deep links — opt-in via enableShopifyUrlRedirects, with a shopifyUrlRedirectsTimeoutMs cap (default 1.5s). When a link's handle no longer exists, the store's redirect is resolved before navigation parses the URL, so a dead product link can land on its replacement collection. Applies to links that open the app, which is the ad-campaign case; links tapped inside a running app keep their path.

Time-windowed carousel slides — individual slides can carry a visibility.duration window and the carousel re-renders itself at each boundary. The underlying useScheduledItems / isWithinSchedule helpers work for anything with a schedule.

Cart visibility rules by product tag — visibility conditions gain filters, aggregate (count or sum), and path, so a rule can express "the cart holds at least four units tagged gift". Note that sum fails closed if any item's value is non-numeric, and per-unit price ignores quantity; sum the line total instead.

Two new integrations — Smart Wishlist (syncs a signed-in customer's wishlist between web and app) and Unbxd Recommendations (PDP, cart, and generic recommendation blocks). Both are config-only.

Smaller additions — loyalty reward-summary, VIP-program, and wallet-transaction blocks gained v2 versions with tiering and expiry; cart list v2 exposes divider, card border, and bottom-sheet styles; toasts take numberOfLines and a leading icon on add-to-cart; product videos now carry a poster image; search suggestions can surface metafields; wallet passes respect merchant activation flags.

Fixed

  • Sign-in on the Shopify checkout web view, and a consistent sign-in success message across components.
  • An invalid freebie could persist in the cart.
  • Navigating back to a product listing re-fetched the collection because unmounting cleared its cache.
  • Deep links carrying a collection handle routed to the wrong parameter.
  • The orders list blanked while a single order loaded.
  • The price-range filter flickered when tapped outside.
  • Web-view intent links that fail to open now fall back to a configured URL.
  • iOS: window.appbrew was torn down when hideElementSelectors was set, which broke pages that rely on the bridge.
  • Review-list pagination did not scroll to the top; analytics sent a wrong transaction id; metafields were injected into product payloads where they did not belong.
  • Cold starts re-downloaded JS chunks because the script cache was not persisted.
  • The flat product-listing renderer is now used on tabbed screens too.
  • Per-block profiling was removed from rendering, cutting measurable overhead.

Upgrading

Bump every @gauntlet/* entry to 0.27.0 together with the Appbrew-published @app-brew/* packages, which move with the platform, then rebuild. Full workflow: Upgrading @gauntlet packages.

On this page