Releases: bigcommerce/catalyst
Release list
@bigcommerce/create-catalyst@2.0.0
Major Changes
- #3077
a45ab43Thanks @jorgemoya! - Reducecreate-catalystto a thin wrapper that delegates tocatalyst create.pnpm create catalyst/npx create-catalyststill scaffold a project — now by invoking@bigcommerce/catalystunder the hood — so the scaffolding UX is unchanged. The standaloneinit,integration, andtelemetrysubcommands are removed; usecatalyst channel linkandcatalyst telemetryfrom the consolidated CLI instead.
Patch Changes
- Updated dependencies [
a45ab43]:- @bigcommerce/catalyst@1.0.0
@bigcommerce/catalyst@1.0.0
Major Changes
-
#3077
a45ab43Thanks @jorgemoya! - Introducing the Catalyst CLI (@bigcommerce/catalyst) — a single command-line tool for scaffolding, building, and deploying your Catalyst storefront to BigCommerce's Native Hosting infrastructure.Highlights
- Scaffold a storefront —
catalyst createdownloads a clean, standalone project (flattened fromcore/,workspace:dependencies resolved to published versions, fresh git repo) via tarball extraction and connects it to your BigCommerce store. The package manager is auto-detected fromnpm_config_user_agent. - Browser-based authentication — Run
catalyst auth loginto authenticate via an OAuth device code flow. Credentials are stored locally in.bigcommerce/project.jsonfor use by all subsequent commands. CI/CD environments can use--store-hashand--access-tokenflags or environment variables instead. - Project & channel management — Create, link, and list BigCommerce infrastructure projects with
catalyst project, and connect storefront channels withcatalyst channel. - Build & deploy —
catalyst buildruns the OpenNext Cloudflare build pipeline (deriving the Wranglercompatibility_datedynamically) and generates deployment artifacts.catalyst deploybundles, uploads, and deploys your storefront with real-time progress streaming. Pass runtime secrets with--secret KEY=VALUE; environment variables are auto-detected as deploy secrets. - Persisted deployment env vars — Manage deployment environment variables across deploys with
catalyst env(list and remove; values are masked). - Custom domains — Add, list, check the status of, and remove custom domains for a Native Hosting project with
catalyst domains. - Local preview —
catalyst startlaunches a local Cloudflare Workers preview of your built storefront via the OpenNext adapter. - Live & historical logs —
catalyst logs tailstreams real-time application logs with color-coded levels and auto-reconnect;catalyst logs queryretrieves historical logs. - In-place upgrades —
catalyst upgradeupgrades a project to a newer version via a resilient 3-way merge (git merge-tree, falling back to per-filegit merge-file), producing resolvable conflict markers instead of ever aborting. - Smart credential resolution — Configuration is resolved in priority order: CLI flags →
--env-file→ process environment variables →.bigcommerce/project.json. - Telemetry — Anonymous usage telemetry with session and correlation IDs for support. Opt out anytime with
catalyst telemetry disable.
Commands
Command Description catalyst createScaffold and connect a Catalyst storefront to your BigCommerce store catalyst authAuthenticate, sign out, and verify stored credentials catalyst projectCreate, link, and list infrastructure projects catalyst channelConnect a storefront channel to your project catalyst buildBuild your Catalyst project for deployment catalyst deployBuild and deploy to BigCommerce Native Hosting catalyst envManage persisted deployment environment variables catalyst domainsManage custom domains for a Native Hosting project catalyst startStart a local Cloudflare Workers preview catalyst logsStream live logs and query historical logs catalyst upgradeUpgrade a project to a newer version via 3-way merge catalyst versionDisplay CLI, Node.js, and platform info catalyst telemetryView or change telemetry collection status Getting started
cd core pnpm add @bigcommerce/catalyst@latest @opennextjs/cloudflare@1.17.3 pnpm catalyst auth login pnpm catalyst project create pnpm catalyst deploy --secret BIGCOMMERCE_STORE_HASH=<hash> --secret BIGCOMMERCE_STOREFRONT_TOKEN=<token>
For full documentation, see the Native Hosting Overview and CLI Reference.
- Scaffold a storefront —
@bigcommerce/create-catalyst@1.1.0
Minor Changes
- #3055
854aab5Thanks @jorgemoya! - Deprecate thecreate-catalyst integrationcommand. It now prints a deprecation warning when invoked and is hidden from--help. The command builds integration patches by diffing git tags, which won't work once Catalyst projects are distributed as tarballs (no git history) — it will be replaced by the forthcomingcatalyst upgradecommand. The command still functions for now; full removal will follow in a future major version.
@bigcommerce/catalyst-makeswift@1.8.0
Minor Changes
-
#2913
097eea7Thanks @agurtovoy! - Enable interaction-mode site navigation in Makeswift builder -
Pulls in changes from the
@bigcommerce/catalyst-core@1.8.0release. For more information about what was included in the@bigcommerce/catalyst-core@1.8.0release, see the changelog entry.
Patch Changes
- #2950
4d511dcThanks @agurtovoy! - Fix 404 error on switching between localized Makeswift pages with locale-specific paths when TRAILING_SLASH=true
@bigcommerce/catalyst-core@1.8.0
Minor Changes
-
#3024
3cec674Thanks @mfaris9! - Honor the merchant's Tax Display setting (Inc.,Ex., orBoth) from the BigCommerce control panel across PDP, PLP, search, compare, and home. When set toBoth, prices render stacked with(Inc. Tax)and(Ex. Tax)labels, including sale strike-throughs per line.Migration
For forks that can't rebase cleanly: pricing was refactored end-to-end to support inc/ex tax variants and a
Bothmode (PricingFragment,pricesTransformer,Pricetypes, page-data settings queries, analytics helpers). See PR #3024 for the full diff. -
#3015
15e365aThanks @mfaris9! - Consume merchant-configured per-locale URL subfolders from the BigCommerce Storefront GraphQL API (Locale.path). The locale that sits at the bare root URL (/) is derived from the CP configuration: if the default locale has no path, it sits at root; otherwise, if exactly one non-default locale has no path, that one sits at root; otherwise every locale gets a prefix. Locales with a path use it; locales without a path fall back to their locale code.
Patch Changes
-
#3031
874e332Thanks @Tharaae! - Display backorder information for variants on PDP. -
#3033
8bc379dThanks @jorgemoya! - Fix broken images in WYSIWYG content (web pages, blog posts, product description and warranty). Images uploaded through the Control Panel editor are stored as store-root-relative WebDAV paths (/content/...and/product_images/...) that 404 on the headless storefront domain; they are now rewritten to absolute BigCommerce CDN URLs. -
#3056
2c99731Thanks @jorgemoya! - Add acatalystfield tocore/package.json(catalyst.versionandcatalyst.ref) that tracks the true Catalyst version independently of the top-levelversion, which merchants may repurpose for their own deploy tagging. The backend user-agent now reportscatalyst.version(falling back toversionfor projects created before the field existed), and the release pipeline keeps the field in sync on each version bump. -
#3035
b4215f0Thanks @jorgemoya! - Scope the consent manager cookie (c15t-consent) to the current host instead of the top-level domain. PreviouslycrossSubdomain: truecaused the cookie to be set on the root domain (e.g..example.com) for stores running on a sub-domain, so it appeared on both the root domain and the sub-domain. Removing it makes the cookie host-only, so it now exists only on the sub-domain the store runs on. -
#3046
5034ea3Thanks @chanceaclark! - Gatecatalyst.visitorId,catalyst.visitId, andcurrencyCodecookies behind shopper consent. The visitor and visit cookies now require measurement consent and the currency preference cookie requires functionality consent. When consent is absent, existing analytics cookies are deleted on the next request. When measurement consent is granted mid-session, a newstartVisitserver action sets the cookies and fires the server-sidevisitStartedEventimmediately rather than waiting for the next full-page navigation. -
#3047
1ab2c82Thanks @chanceaclark! - Makeauthjs.session-tokenandauthjs.anonymous-session-tokenbrowser-session cookies (noExpiresattribute) to satisfy Essential cookie classification requirements.What changed
Anonymous session token:
anonymousSignInno longer setsmaxAgeon the cookie. Without it, Next.js omitsMax-Age/Expiresand the cookie becomes a session cookie that the browser drops when it closes.Auth session token: Auth.js v5 unconditionally writes
Expireson the session token cookie and provides no config option to suppress it. Two post-processing steps strip the attribute:proxies/with-auth.ts— stripsExpiresfromSet-Cookieresponse headers on every page request.auth/index.ts— wrapssignInandupdateSessionto re-set the cookie viacookies().set()withoutExpiresimmediately after Auth.js writes it, covering the sign-in and session-update paths that middleware cannot reach.
Max-Age=0(used by Auth.js for cookie deletion on sign-out) is intentionally left intact.Migration
If you have a custom
maxAgeonanonymousSignIn: The default 7-daymaxAgehas been removed. If your app relies on anonymous sessions persisting across browser restarts, add it back in your ownanonymousSignIncall:cookieJar.set(anonymousCookieName, jwt, { httpOnly: true, sameSite: 'lax', secure: useSecureCookies, maxAge: 60 * 60 * 24 * 7, // restore 7-day persistence if needed });
If you already have your own
Expires-stripping workaround: Remove it. The middleware regex inwith-auth.tsand thepatchSessionTokenCookieswrapper inauth/index.tsnow handle this centrally. Leaving both in place will cause redundant cookie writes.If you import
signInorupdateSessiondirectly fromauth/index.ts: No change needed — the signatures are identical. The exports are now thin async wrappers that call the Auth.js originals and then patch any session token cookies written during the call. -
#3058
94c503eThanks @bc-svc-local! - Update translations. -
#3048
226f2f3Thanks @bc-svc-local! - Update translations.
@bigcommerce/catalyst-makeswift@1.7.0
Minor Changes
- Pulls in changes from the
@bigcommerce/catalyst-core@1.7.0release. For more information about what was included in the@bigcommerce/catalyst-core@1.7.0release, see the changelog entry.
@bigcommerce/catalyst-core@1.7.0
Minor Changes
-
#2989
518d20aThanks @jorgemoya! - Restore locale-awarelangattribute on the root<html>tag. The previous root layout hardcodedlang="en"for all locales; ownership of<html>/<body>now lives inapp/[locale]/layout.tsxsolang={locale}reflects the active locale. The rootapp/layout.tsxis now a passthrough, andapp/not-found.tsxis self-sufficient (renders its own<html>/<body>) to preserve the branded 404 for non-localized requests. -
#2825
7b38d98Thanks @chanceaclark! - Add GraphQL proxy to enable client-side GraphQL requests through the storefront. This proxy forwards requests from allowed clients (such as checkout-sdk-js) to the BigCommerce Storefront API using a dedicated unauthenticated storefront token for API authorization, while still passing through the customer access token for customer-specific data. No browser cookies are forwarded.Migration
Step 1: Add environment variable
Add a
BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKENto your.env.local. This should be a storefront API token scoped for client-side proxy use with minimal permissions.Step 2: Create proxy
Create a new file
core/proxies/with-graphql-proxy.ts:import { NextResponse, URLPattern } from 'next/server'; import { z } from 'zod'; import { auth } from '~/auth'; import { client } from '~/client'; import { type ProxyFactory } from './compose-proxies'; const ALLOWED_REQUESTERS = ['checkout-sdk-js']; const graphqlPathPattern = new URLPattern({ pathname: '/graphql' }); const bodySchema = z.object({ query: z.unknown(), variables: z.record(z.unknown()).default({}), }); export const withGraphqlProxy: ProxyFactory = (next) => { return async (request, event) => { // Only handle /graphql path if (!graphqlPathPattern.test(request.nextUrl.toString())) { return next(request, event); } const requester = request.headers.get('x-catalyst-graphql-proxy-requester'); // Validate required header if (!requester || !ALLOWED_REQUESTERS.includes(requester)) { return next(request, event); } // Only handle POST requests if (request.method !== 'POST') { return new NextResponse('Method not allowed', { status: 405 }); } // Wrap in auth to get customer access token for customer-specific data return auth(async (req) => { try { // Parse incoming GraphQL request body const body: unknown = await req.json(); const { query, variables } = bodySchema.parse(body); if (!query) { return NextResponse.json({ error: 'Missing query' }, { status: 400 }); } // Get customer access token if authenticated const customerAccessToken = req.auth?.user?.customerAccessToken; // Proxy the request using the existing client with an unauthenticated storefront token const response = await client.fetch({ document: query, variables, customerAccessToken, fetchOptions: { headers: { Authorization: `Bearer ${process.env.BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN}`, }, next: { revalidate: 0 }, }, }); return NextResponse.json(response); } catch (error) { // eslint-disable-next-line no-console console.error(error); return NextResponse.json(error, { status: 500 }); } // @ts-expect-error auth() overload expects middleware return type, but we return NextResponse directly for the proxy })(request, event); }; };
Step 3: Register proxy
Update
core/proxy.tsto include the new proxy in the composition chain:import { composeProxies } from './proxies/compose-proxies'; import { withAnalyticsCookies } from './proxies/with-analytics-cookies'; import { withAuth } from './proxies/with-auth'; import { withChannelId } from './proxies/with-channel-id'; + import { withGraphqlProxy } from './proxies/with-graphql-proxy'; import { withIntl } from './proxies/with-intl'; import { withRoutes } from './proxies/with-routes'; export const proxy = composeProxies( withAuth, withAnalyticsCookies, withIntl, withChannelId, + withGraphqlProxy, withRoutes, );The
withGraphqlProxyproxy should be placed afterwithChannelIdand beforewithRoutesin the chain.
Patch Changes
-
#3002
24cc310Thanks @bc-alexsaiannyi! - Fix cart summary Discounts row not showing manual discounts applied via the Management Checkout API -
#2976
a85fa42Thanks @jorgemoya! - Add X-Correlation-ID header to all GraphQL requests. Each page render gets a stable UUID that persists across all fetches within the same render, enabling easier request tracing in server logs. -
#3021
4e44415Thanks @mfaris9! - Default brand PLP sort tofeaturedto honor the merchant's product sort order. -
#2964
d00beebThanks @chanceaclark! - Prevent breadcrumb array mutation on cached web pages by spreading the Reactcache()result before reversing, and fix an off-by-one intruncateBreadcrumbsthat incorrectly truncated arrays exactly at the target length. Also deferProductReviewSchemato client-only rendering to avoid a DOMPurify SSR crash. -
#3005
37e0a7cThanks @mfaris9! - FixformField.requiredmismatch forcheckbox-groupfields inDynamicForm. The schema branch was missing.optional()for non-required checkbox groups. -
#3013
9aacfdcThanks @chanceaclark! - Pass the customer access token through route resolution and the normal/contact webpage queries so customer-restricted web pages are accessible (and appear in navigation) for authenticated customers. Thewith-routesproxy is now wrapped inauth(), and webpagepage-dataqueries switch to an uncached fetch when a customer token is present. -
#2963
a8dd99eThanks @chanceaclark! - Fix DynamicForm not rendering hidden field types, which causedpageEntityIdto beNaNon contact form submission. -
#3014
a792a86Thanks @parthshahp! - TRAC-276 translate the gift certificate line item title in cart, order list, and order details. Previously the title was rendered as the raw English"{amount} Gift Certificate"string stored on the BigCommerce backend; it is now rendered from the existingCart.GiftCertificate.giftCertificatetranslation key, with the amount shown in the separate price column (the order list view now populatesprice/totalPricefor gift certificates, which were previously empty). -
#3008
77c8e8dThanks @bc-svc-local! - Update translations. -
#2959
4870221Thanks @bc-svc-local! - Update translations. -
#2987
e18feb6Thanks @bc-svc-local! - Update translations. -
#3022
c5fc1afThanks @bc-svc-local! - Update translations. -
Updated dependencies [
f4216a6]:- @bigcommerce/catalyst-client@1.0.2
@bigcommerce/catalyst-client@1.0.2
Patch Changes
- #3018
f4216a6Thanks @parthshahp! - Fixclient.fetchso that custom headers passed viafetchOptions.headersproperly override the client's default headers. Headers are now built via aHeadersobject using.set(), so case-insensitive overrides work as expected.
@bigcommerce/catalyst-makeswift@1.6.4
Patch Changes
- #3007
13b3c2eThanks @chanceaclark! - Bump Next.js and React to address security vulnerabilitiesnext: ~16.1.6 → ~16.2.6 — fixes middleware bypass, SSRF, XSS, and cache poisoning CVEsreact/react-dom: 19.1.5 → 19.1.7 — fixes GHSA-rv78-f8rc-xrxh (DoS via OOM/CPU exhaustion on server function endpoints)
@bigcommerce/catalyst-core@1.6.3
Patch Changes
- #3007
13b3c2eThanks @chanceaclark! - Bump Next.js and React to address security vulnerabilitiesnext: ~16.1.6 → ~16.2.6 — fixes middleware bypass, SSRF, XSS, and cache poisoning CVEsreact/react-dom: 19.1.5 → 19.1.7 — fixes GHSA-rv78-f8rc-xrxh (DoS via OOM/CPU exhaustion on server function endpoints)