Skip to content

Releases: bigcommerce/catalyst

@bigcommerce/create-catalyst@2.0.0

Choose a tag to compare

@github-actions github-actions released this 02 Jul 16:38
0043364

Major Changes

  • #3077 a45ab43 Thanks @jorgemoya! - Reduce create-catalyst to a thin wrapper that delegates to catalyst create. pnpm create catalyst / npx create-catalyst still scaffold a project — now by invoking @bigcommerce/catalyst under the hood — so the scaffolding UX is unchanged. The standalone init, integration, and telemetry subcommands are removed; use catalyst channel link and catalyst telemetry from the consolidated CLI instead.

Patch Changes

  • Updated dependencies [a45ab43]:
    • @bigcommerce/catalyst@1.0.0

@bigcommerce/catalyst@1.0.0

Choose a tag to compare

@github-actions github-actions released this 02 Jul 17:45
61413d3

Major Changes

  • #3077 a45ab43 Thanks @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 storefrontcatalyst create downloads a clean, standalone project (flattened from core/, 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 from npm_config_user_agent.
    • Browser-based authentication — Run catalyst auth login to authenticate via an OAuth device code flow. Credentials are stored locally in .bigcommerce/project.json for use by all subsequent commands. CI/CD environments can use --store-hash and --access-token flags or environment variables instead.
    • Project & channel management — Create, link, and list BigCommerce infrastructure projects with catalyst project, and connect storefront channels with catalyst channel.
    • Build & deploycatalyst build runs the OpenNext Cloudflare build pipeline (deriving the Wrangler compatibility_date dynamically) and generates deployment artifacts. catalyst deploy bundles, 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 previewcatalyst start launches a local Cloudflare Workers preview of your built storefront via the OpenNext adapter.
    • Live & historical logscatalyst logs tail streams real-time application logs with color-coded levels and auto-reconnect; catalyst logs query retrieves historical logs.
    • In-place upgradescatalyst upgrade upgrades a project to a newer version via a resilient 3-way merge (git merge-tree, falling back to per-file git 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 create Scaffold and connect a Catalyst storefront to your BigCommerce store
    catalyst auth Authenticate, sign out, and verify stored credentials
    catalyst project Create, link, and list infrastructure projects
    catalyst channel Connect a storefront channel to your project
    catalyst build Build your Catalyst project for deployment
    catalyst deploy Build and deploy to BigCommerce Native Hosting
    catalyst env Manage persisted deployment environment variables
    catalyst domains Manage custom domains for a Native Hosting project
    catalyst start Start a local Cloudflare Workers preview
    catalyst logs Stream live logs and query historical logs
    catalyst upgrade Upgrade a project to a newer version via 3-way merge
    catalyst version Display CLI, Node.js, and platform info
    catalyst telemetry View 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.

@bigcommerce/create-catalyst@1.1.0

Choose a tag to compare

@github-actions github-actions released this 26 Jun 13:39
81b88df

Minor Changes

  • #3055 854aab5 Thanks @jorgemoya! - Deprecate the create-catalyst integration command. 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 forthcoming catalyst upgrade command. The command still functions for now; full removal will follow in a future major version.

@bigcommerce/catalyst-makeswift@1.8.0

Choose a tag to compare

@github-actions github-actions released this 26 Jun 20:26
fce3519

Minor Changes

  • #2913 097eea7 Thanks @agurtovoy! - Enable interaction-mode site navigation in Makeswift builder

  • Pulls in changes from the @bigcommerce/catalyst-core@1.8.0 release. For more information about what was included in the @bigcommerce/catalyst-core@1.8.0 release, see the changelog entry.

Patch Changes

  • #2950 4d511dc Thanks @agurtovoy! - Fix 404 error on switching between localized Makeswift pages with locale-specific paths when TRAILING_SLASH=true

@bigcommerce/catalyst-core@1.8.0

Choose a tag to compare

@github-actions github-actions released this 26 Jun 13:39
81b88df

Minor Changes

  • #3024 3cec674 Thanks @mfaris9! - Honor the merchant's Tax Display setting (Inc., Ex., or Both) from the BigCommerce control panel across PDP, PLP, search, compare, and home. When set to Both, 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 Both mode (PricingFragment, pricesTransformer, Price types, page-data settings queries, analytics helpers). See PR #3024 for the full diff.

  • #3015 15e365a Thanks @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 874e332 Thanks @Tharaae! - Display backorder information for variants on PDP.

  • #3033 8bc379d Thanks @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 2c99731 Thanks @jorgemoya! - Add a catalyst field to core/package.json (catalyst.version and catalyst.ref) that tracks the true Catalyst version independently of the top-level version, which merchants may repurpose for their own deploy tagging. The backend user-agent now reports catalyst.version (falling back to version for projects created before the field existed), and the release pipeline keeps the field in sync on each version bump.

  • #3035 b4215f0 Thanks @jorgemoya! - Scope the consent manager cookie (c15t-consent) to the current host instead of the top-level domain. Previously crossSubdomain: true caused 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 5034ea3 Thanks @chanceaclark! - Gate catalyst.visitorId, catalyst.visitId, and currencyCode cookies 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 new startVisit server action sets the cookies and fires the server-side visitStartedEvent immediately rather than waiting for the next full-page navigation.

  • #3047 1ab2c82 Thanks @chanceaclark! - Make authjs.session-token and authjs.anonymous-session-token browser-session cookies (no Expires attribute) to satisfy Essential cookie classification requirements.

    What changed

    Anonymous session token: anonymousSignIn no longer sets maxAge on the cookie. Without it, Next.js omits Max-Age/Expires and the cookie becomes a session cookie that the browser drops when it closes.

    Auth session token: Auth.js v5 unconditionally writes Expires on the session token cookie and provides no config option to suppress it. Two post-processing steps strip the attribute:

    • proxies/with-auth.ts — strips Expires from Set-Cookie response headers on every page request.
    • auth/index.ts — wraps signIn and updateSession to re-set the cookie via cookies().set() without Expires immediately 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 maxAge on anonymousSignIn: The default 7-day maxAge has been removed. If your app relies on anonymous sessions persisting across browser restarts, add it back in your own anonymousSignIn call:

    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 in with-auth.ts and the patchSessionTokenCookies wrapper in auth/index.ts now handle this centrally. Leaving both in place will cause redundant cookie writes.

    If you import signIn or updateSession directly from auth/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 94c503e Thanks @bc-svc-local! - Update translations.

  • #3048 226f2f3 Thanks @bc-svc-local! - Update translations.

@bigcommerce/catalyst-makeswift@1.7.0

Choose a tag to compare

@github-actions github-actions released this 02 Jun 14:12
bcd87c3

Minor Changes

  • Pulls in changes from the @bigcommerce/catalyst-core@1.7.0 release. For more information about what was included in the @bigcommerce/catalyst-core@1.7.0 release, see the changelog entry.

@bigcommerce/catalyst-core@1.7.0

Choose a tag to compare

@github-actions github-actions released this 01 Jun 17:01
3c96c47

Minor Changes

  • #2989 518d20a Thanks @jorgemoya! - Restore locale-aware lang attribute on the root <html> tag. The previous root layout hardcoded lang="en" for all locales; ownership of <html>/<body> now lives in app/[locale]/layout.tsx so lang={locale} reflects the active locale. The root app/layout.tsx is now a passthrough, and app/not-found.tsx is self-sufficient (renders its own <html>/<body>) to preserve the branded 404 for non-localized requests.

  • #2825 7b38d98 Thanks @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_TOKEN to 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.ts to 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 withGraphqlProxy proxy should be placed after withChannelId and before withRoutes in the chain.

Patch Changes

  • #3002 24cc310 Thanks @bc-alexsaiannyi! - Fix cart summary Discounts row not showing manual discounts applied via the Management Checkout API

  • #2976 a85fa42 Thanks @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 4e44415 Thanks @mfaris9! - Default brand PLP sort to featured to honor the merchant's product sort order.

  • #2964 d00beeb Thanks @chanceaclark! - Prevent breadcrumb array mutation on cached web pages by spreading the React cache() result before reversing, and fix an off-by-one in truncateBreadcrumbs that incorrectly truncated arrays exactly at the target length. Also defer ProductReviewSchema to client-only rendering to avoid a DOMPurify SSR crash.

  • #3005 37e0a7c Thanks @mfaris9! - Fix formField.required mismatch for checkbox-group fields in DynamicForm. The schema branch was missing .optional() for non-required checkbox groups.

  • #3013 9aacfdc Thanks @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. The with-routes proxy is now wrapped in auth(), and webpage page-data queries switch to an uncached fetch when a customer token is present.

  • #2963 a8dd99e Thanks @chanceaclark! - Fix DynamicForm not rendering hidden field types, which caused pageEntityId to be NaN on contact form submission.

  • #3014 a792a86 Thanks @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 existing Cart.GiftCertificate.giftCertificate translation key, with the amount shown in the separate price column (the order list view now populates price/totalPrice for gift certificates, which were previously empty).

  • #3008 77c8e8d Thanks @bc-svc-local! - Update translations.

  • #2959 4870221 Thanks @bc-svc-local! - Update translations.

  • #2987 e18feb6 Thanks @bc-svc-local! - Update translations.

  • #3022 c5fc1af Thanks @bc-svc-local! - Update translations.

  • Updated dependencies [f4216a6]:

    • @bigcommerce/catalyst-client@1.0.2

@bigcommerce/catalyst-client@1.0.2

Choose a tag to compare

@github-actions github-actions released this 01 Jun 17:01
3c96c47

Patch Changes

  • #3018 f4216a6 Thanks @parthshahp! - Fix client.fetch so that custom headers passed via fetchOptions.headers properly override the client's default headers. Headers are now built via a Headers object using .set(), so case-insensitive overrides work as expected.

@bigcommerce/catalyst-makeswift@1.6.4

Choose a tag to compare

@chanceaclark chanceaclark released this 13 May 21:05
1ace66f

Patch Changes

  • #3007 13b3c2e Thanks @chanceaclark! - Bump Next.js and React to address security vulnerabilities
    • next: ~16.1.6 → ~16.2.6 — fixes middleware bypass, SSRF, XSS, and cache poisoning CVEs
    • react / 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

Choose a tag to compare

@chanceaclark chanceaclark released this 13 May 17:02
0c93b6a

Patch Changes

  • #3007 13b3c2e Thanks @chanceaclark! - Bump Next.js and React to address security vulnerabilities
    • next: ~16.1.6 → ~16.2.6 — fixes middleware bypass, SSRF, XSS, and cache poisoning CVEs
    • react / react-dom: 19.1.5 → 19.1.7 — fixes GHSA-rv78-f8rc-xrxh (DoS via OOM/CPU exhaustion on server function endpoints)