0.35.0
A new bottom bar engine with the iOS 26 Liquid Glass bar, view_item sent for every way of reaching a product, deep links that survive an unparseable screen path, Meta ads that open at their destination, B2B wholesale prices, and remote components that fail on their own.
Native changes: every app needs a store release
@gauntlet/brewerynow declares two native peers: the new@app-brew/tab-barpackage andreact-native-haptic-feedback, plus the JS-only@react-navigation/bottom-tabsat 7.4.7. Add all three to the app'spackage.json(pnpm exec appbrew-sync-depsdoes this), runpod install, and ship a store release.@app-brew/tab-baris iOS only and refuses to compile below Xcode 26 (the iOS 26 SDK), so iOS builds now need Xcode 26. Android does not link it.@app-brew/webviewgains acontentInsetBottomprop on iOS and Android, so the page clears a bar floating over it.@app-brew/quick-actionschanges on Android: adding a shortcut reports whether its remote icon failed to load.
Breaking
The bottom bar runs on React Navigation's bottom-tabs navigator. Tab
screens are now hosted by @react-navigation/bottom-tabs instead of the
child navigator. Tabs mount when first opened and freeze while in the
background. The bar itself looks and behaves as before unless the new
options below are set. If a tab misbehaves, set
navigation.bottomBar.engine to 'legacy-child-nav' to go back to the old
host while you report it; that switch will be removed in a later release.
ChildNav is no longer exported from @gauntlet/brewery. It was the
tab host's navigator. A shell that forks brewery's should create its own
with createChildNavigator() from @gauntlet/child-navigator.
Phone inputs default to the first country-code layout. With no
countryCodelayout set, the flag and calling code now sit together in the
country picker button, and the separate calling-code text is hidden. Before,
the default was second. Set countryCodelayout: 'second' in the input's
config options to keep the old look. The separate-borders layout is
unaffected.
view_item is sent from navigation state, not from pushRoute.
pushRoute and replaceRoute no longer send it; brewery's Shell sends it
when the navigator settles on a product screen (see Changed). An app that
renders its own NavigationContainer instead of Shell no longer gets
view_item and must send it from its own onStateChange.
Subscription blocks without an appId show every selling plan. The
subscription selector, its dropdown, and the selling-plan price, discount
and compare-at-price components used to render nothing when options.appId
was missing. They now accept the plans of every selling plan group on the
product. Set appId to keep them scoped to one subscription app.
backgroundOptionsSchema in @gauntlet/types is a refined schema. It
gains a liquid kind and now rejects a liquid background without
liquid.fallback. As a refined zod schema it no longer has .extend() or
.shape.
New
Bottom bar options. navigation.bottomBar gains a behavior object:
animation (none, fade, shift, scale, spring; default fade),
hideOnKeyboard, hideOnScroll, hapticFeedback, preloadAdjacentScreens,
lazy, freezeOnBlur and rePressReload. The top-level
preloadAdjacentScreens and hideOnScroll still work and are deprecated.
Tabs gain a badge (cart count, wishlist count, a static value, a store
path, or none, shown as a count or a dot) that replaces badgeLocation, a
themeKey for per-tab styles in theme.bottomBar.tabOverrides, and a
screen can hide the bar with bottomBar.hide.
Liquid Glass bar on iOS 26. Set theme.bottomBar.liquid.enabled and the
bar becomes UIKit's own tab bar on devices running iOS 26 with a binary that
links @app-brew/tab-bar. Every tab needs a nativeIcon (an SF Symbol or an
image URL) or the search role, and the bar holds at most five tabs;
otherwise, and on Android and older iOS, the docked bar renders as before. A
screen's footer can float over the list on glass with
footer.liquid (glass, pill, accessory or float), and a Box
background can be liquid with a solid fallback colour for every other
device.
@gauntlet/bss-b2b — B2B wholesale prices, published for the first
time. Signed-in customers see their wholesale prices and volume tiers in
the shared price components, and check out at those prices through a draft
order. Register BssB2bProvider as the app's pricing module; the
bss-b2b-volume-tiers and bss-b2b-checkout blocks complete it.
Remote components fail on their own. Every component an instant-code
bundle registers renders inside its own error boundary. A crash falls back
to the component it replaced, or to nothing, instead of replacing the whole
app with the error screen, and it is reported as InstantCodeError with
the component's kind and key. Load failures and rejected manifests are
reported too; network drops are not.
Purchase options block. purchase-options lets a customer choose
between one-time purchase and subscription on the product page, and opens
the subscription frequency sheet.
Apply-coupon modal. The apply-coupon-modal block lists the cart's
coupons as ticket cards under a sheet header. Applying one shows a toast and
goes back. view-coupons
can open it, or any other link, through options.applyCouponLink.
Flits referral links open in the app. Mount FlitsReferralPrompt next
to Shell and a Flits referral link opens a prompt that accepts the invite,
sending signed-out customers to sign in first. The
flits-share-referral-link block shares the referral link instead of the
code.
Server-side GA4 purchase for Firebase. With the Firebase integration's
serverPurchase setting on and Measurement API secrets set, the GA4
purchase event is sent from the order webhook rather than the app, so
orders whose buyer leaves for a payment app are counted. The app then skips
its own purchase and stamps Firebase identifiers on the cart.
Smaller additions.
image-list:options.heading.numberOfLinestruncates item titles.payment-details:source.totalInfoTextadds a note under the total, such as "Inclusive of all taxes".add-to-cart:style.loadercolours or hides the loading shimmer.- WebEngage (tracker v2):
uniqueIdpickscustomerId(the default),emailorphoneas the user identity. - Stamped:
settings.global.sendVariantSkuToStampedsends the default variant's SKU with review requests, so Stamped product groups apply. Off by default. settings.global.preserveGoogleUtmSourcekeepsutm_source=googlewhen the link also carries agclid, which otherwise rewrites it togoogle_ads. Off by default.
Changed
view_item is sent for every way of reaching a product. Before, it was
sent only when in-app navigation pushed or replaced a product screen.
Products opened from a deep link, a push notification, a Meta or other
campaign link, or a link inside a web page sent nothing. Now each new
product screen sends it once, and opening a different product in a running
app sends it again. Going back to a product, or switching tabs and
returning, does not. Expect higher view_item counts in every destination
that receives it, such as GA4, Meta, AppsFlyer, Branch and Klaviyo, in
proportion to how much traffic arrives by link.
Link UTM parameters set the event source. A Firebase push notification
link, and an in-app link whose URL carries utm_* parameters, now record
those parameters as the event source.
WebEngage (tracker v2) follows event renames. Login, logout and purchase
handling now works when those events are renamed through eventsMapper, and
screen views go through the mapper too, so a renamed page_view is sent
under its new name.
Quick actions register once. Home-screen shortcuts are registered when their config changes rather than on every launch, so a kill during launch no longer leaves the menu empty.
Fixed
- Deep links and an unparseable screen path. A screen whose id or
deepLinkPathReact Navigation cannot parse, such as one with a colon inside a segment, made every deep link in the app fail: the app opened on its first screen and the link was ignored. That screen's path is now left out of the linking config, so every other link works, and a link to that screen opens the store page in a web view. - Meta ads open at the destination. A Meta ad that opened the app
through App Links carried its target inside
al_applink_data, and the app tried to read a product path from that escaped blob, landing on a page that did not exist. The app now opens the ad's target URL, also for deferred links on first launch after install. - Deep links to fallback tab screens resolve inside the tabs, and query
values such as
%2Bin a deep link are no longer decoded twice. - GoKwik KwikPass sign-in returns to the redirect screen by popping the sign-in and OTP screens, and closes the sheet hosting it, so back no longer lands on the OTP step.
- Cold-start quick actions wait for the splash and app init before opening their screen, so launch no longer swallows the tap.
- Keyboard. The screen list no longer lifts when a field inside a web page has focus.
- Address form. After adding an address, the form goes back to the screen that opened it instead of pushing a second address list.
- Move to cart passes all of its config options to the add-to-cart button, not just the title and type.
- Flits sends referral-code acceptance as form data, which the API expects.
Performance
Product cards render less. The card, its leaf components and the PDP product
info are memoised with props scoped to each field, and useModal selects
with shallow equality, so its consumers no longer re-render on every store
write.
Tooling
@app-brew/build-tools shares app dependencies with remotes. The host
now shares every dependency in the app's package.json with instant-code
remotes, not just the core set, so a remote reuses the host's copy instead
of bundling its own, and stateful libraries such as toasts run as one
instance. A remote still bundles a fallback for each, so a remote built now
runs on binaries built before, and remotes built before keep working on new
binaries. Remote images now load by URL from the remote's own
remote-assets/ folder, so images that only a remote ships render in
release builds.
env-watch-loader.cjs ships in the package. Apps that install
build-tools from the registry no longer fail with Cannot find module './env'.
Upgrading? The workflow is at Upgrading @gauntlet packages.
0.36.0
App start-up back to 0.34 speed: build-tools no longer registers every app dependency for instant code at launch.
0.34.0
Keyboard handling measured on every screen, Shopify APIs pinned to 2026-07, a launch crash on encoded deep links fixed, free-gift lines that no longer duplicate, Fare Freight shipping rates, LiveMeUp live shopping, and dependency sync for apps in their own repo.

