Alokai

2.0

Next.js 16 and Nuxt 4, Tailwind 4, and an ESM middleware that normalizes every error

Showing every integration. Set your stack in Preferences and this page hides what isn't yours.

Majorlatest 2.0.3 · 4 Mar 2026Node 20.* || >=22.14.0

In 2.0, most of the upgrade work is in your own app code, not in the packages. Both storefronts move up a framework major, CSS replaces Tailwind's config file, the middleware app becomes ESM, and every integration throws a normalized HttpError instead of its vendor SDK's own error. The CLI's version upgrade command refuses to cross a major boundary, so you edit every version by hand and apply every step yourself.

The three patches are small by comparison, and each one asks you for an edit: a turbo.json task in 2.0.1, a @storefront-ui/nuxt pin, a move of the Compass CLI plugin to 1.1.1 if you use Compass and, if you pass defineIntegrationExtension a pre-built argument, moving it back inline in 2.0.2, and CMS 404 handling in 2.0.3. Two of them also move a package: @alokai/cli in 2.0.1, and @alokai/connect to 2.0.1 and @alokai/cli-plugin-compass to 1.1.1 in 2.0.2. The 2.0.3 step needs that @alokai/connect version.

One thing to know before you start is a defect, not a change. On Next.js, the shipped replacement for your middleware.ts gets the X-Frame-Options opt-out wrong. If you adopt it as written, your storefront stops sending X-Frame-Options: DENY. Its step in the upgrade guide says what to keep instead.

Highlights

Your Next.js storefront moves to Next.js 16 with React 19

Action neededStorefront@vue-storefront/next
Why:

The storefront apps are files your project owns, so no package can move them to a new framework major. The packages can only declare which versions they need.

@vue-storefront/next 7.0.0 declares peer dependencies on Next.js 15+ and React 19. The generated Next.js app ships on next 16.1.6, react 19.2.3, next-intl 4.6.0, and @storefront-ui/react 4.0.0.

For you:

No package bump touches the app, so the framework migration is yours, and your storefront doesn't build until you do it. The work is asynchronous params and searchParams on every page, a rewritten next-intl routing config, and renaming middleware.ts to proxy.ts, which is easy to miss. The Nuxt storefront has its own framework major in this release, and the release doesn't move that one for you either.

See the step in the upgrade guide →

Your Nuxt storefront moves to Nuxt 4

Action neededStorefront@vue-storefront/nuxt
Why:

The storefront apps are files your project owns, so no package can move them to a new framework major. The packages can only declare which versions they need.

@vue-storefront/nuxt 10.0.0 requires Nuxt ^4.0.0. It comes with @nuxtjs/i18n 10, @nuxt/image 2, @vite-pwa/nuxt 1, and @storefront-ui/vue 3. nuxt-jsonld is dropped because it doesn't run on Nuxt 4.

For you:

No package bump touches the app, so the framework migration is yours, and your storefront doesn't build until you do it. The work is the i18n v10 directory move, the @nuxt/image v2 provider API, and replacing useJsonld with useHead. The Next.js storefront has its own framework major in this release, and the release doesn't move that one for you either.

See the step in the upgrade guide →

Tailwind 4 replaces tailwind.config.ts with a CSS entry point

Action neededStorefront
Why:

Tailwind 4 reads its configuration from CSS, not from a config file. There's no newer form of your tailwind.config.ts to rewrite it into, so it has to be ported.

tailwindcss moves from 3.4.4 to 4.1.14 in apps/storefront-unified-nextjs, apps/storefront-unified-nuxt, and your local packages/tailwind-config.

packages/tailwind-config is no longer a built TypeScript package. Its src/ directory, its build script, and its unbuild devDependency are deleted. It ships two plain CSS files instead, nextjs.css and nuxt.css, exported through "exports": { "./*": "./*.css" }.

Each app's tailwind.config.ts is deleted. A CSS entry point that uses @import and @source replaces it.

For you:

Port every Tailwind customization in tailwind.config.ts into CSS by hand. @tailwind base/components/utilities stops working.

Two details are easy to get wrong. packages/tailwind-config/nuxt.css imports @storefront-ui/vue/tailwind-config and the Next.js file imports the React one, so the two CSS files aren't interchangeable. apps/storefront-unified-nextjs/next.config.mjs gains a sassOptions.additionalData hook meant to inject a @reference directive into every *.module.scss, but it never runs under Next.js 16's default Turbopack bundler. Add the directive by hand to every SCSS module that uses @apply, or it fails to compile.

See the step in the upgrade guide →

The middleware app is now ESM

Action neededAlokai Connect@alokai/connect
Why:

@alokai/connect 2.0.0 imports lodash-es, which a CommonJS app can't require. apps/storefront-middleware is a file your project owns, so the package move and the app's module format have to happen together.

@alokai/connect 2.0.0 uses lodash-es instead of lodash. The generated apps/storefront-middleware declares "type": "module" and compiles with "module": "ESNext" and "moduleResolution": "Bundler". Its build runs tsc-alias --resolve-full-paths after tspc, so your path aliases still resolve in the compiled output.

@alokai/connect also has an ESM-first integration loader that falls back to CommonJS with a warning.

For you:

Nothing in the upgrade converts apps/storefront-middleware/package.json or its tsconfig.json, because they're yours. Until you convert them, a middleware on @alokai/connect 2.0.0 fails to load. Turn every require() and module.exports left in your own middleware code, extensions, and custom API methods into import/export.

See the step in the upgrade guide →

Every middleware error is now a normalized HttpError

Action neededAlokai Connect@alokai/connect
Why:

Every integration threw whatever its own vendor SDK threw, so a catch block written for one integration matched no other.

@alokai/connect 2.0.0 adds AppError, NotFoundError, UnauthorizedError, ValidationError, and HttpError, plus normalizeAxiosError, normalizeGraphQLError, and a withData method on HttpError. Three new packages carry the per-client normalizers: @alokai/middleware-axios-error-adapter, @alokai/middleware-apollo-error-adapter, and @alokai/middleware-fetch-error-adapter. Eighteen integration packages now use one of them, so their client errors arrive as HttpError.

The default error handler returns JSON for 5xx responses instead of plain text. It logs stack traces for 5xx and non-HttpError exceptions, and no longer for 4xx.

For you:

Catch blocks that test for a vendor SDK's own error type stop matching. The original error is on error.cause, so the port is mechanical, but you still have to do it. A 5xx response body your code read with response.text() is now JSON.

On commercetools the change is larger: GraphQL failures that used to come back as HTTP 200 with a populated result.errors now throw. Commercetools has a step of its own in the upgrade guide.

See the step in the upgrade guide →

All changes by area

Every change in 2.0 has one entry here, grouped by area. The highlights, from above and from the patch sections, are here too, marked with a star. Open an area to see its changes, and open a change to read why it changed and what changed. The upgrade guide from 1.4.6 to 2.0.3 collects the migration steps for the whole line.

Alokai ConnectAction needed14 changes

changed The middleware app is now ESM highlight Action needed

Nothing in the upgrade converts the middleware app's package.json and tsconfig.json, and until you do, a middleware on @alokai/connect 2.0.0 fails to load. Turn every require() and module.exports in your own middleware code, extensions, and custom API methods into import/export.

step →
What changed ▸
Why

@alokai/connect 2.0.0 imports lodash-es, which a CommonJS app can't require. apps/storefront-middleware is a file your project owns, so the package move and the app's module format have to happen together.

Changed

@alokai/connect 2.0.0 uses lodash-es instead of lodash. The generated apps/storefront-middleware declares "type": "module", compiles with "module": "ESNext" and "moduleResolution": "Bundler", and runs tsc-alias --resolve-full-paths after tspc. The package also has an ESM-first integration loader that falls back to CommonJS with a warning.

@alokai/connect

changed Every middleware error is now a normalized HttpError highlight Action needed

Catch blocks that test for a vendor SDK's own error type stop matching. The original error is on error.cause, so the port is mechanical. A 5xx body your code read with response.text() is now JSON, and on commercetools, GraphQL failures that used to arrive as HTTP 200 with result.errors now throw.

step →
What changed ▸
Why

Every integration threw whatever its own vendor SDK threw, so a catch block written for one integration matched no other.

Changed

@alokai/connect 2.0.0 adds AppError, NotFoundError, UnauthorizedError, ValidationError, and HttpError, plus normalizeAxiosError, normalizeGraphQLError, and HttpError.withData. Three new adapter packages carry the per-client normalizers, and eighteen integration packages use one of them. The default error handler returns JSON for 5xx responses instead of plain text. It logs stack traces for 5xx and non-HttpError exceptions only.

@alokai/connect

added A circuit breaker sits in front of every integration call

Once a backend's errors pass the threshold, calls to it are rejected fast instead of piling up timeouts. You have nothing to configure.

What changed ▸
Changed

A circuit breaker sits in front of every integration call and opens when errors pass a threshold. It's always on, runs on the BALANCED preset, and needs no configuration.

You can select a different preset per integration with circuitBreaker.preset in its config, or for every integration with the CB_PRESET environment variable: AGGRESSIVE, BALANCED, TOLERANT, FAST_FAILURE, HARD_FAIL, RELAXED_DEBUG, or EXTREME_DEBUG. The preset name is case-insensitive, and an unrecognized value falls back to BALANCED. The breaker logs its events with structured metadata and exposes them as Prometheus metrics.

@alokai/connect

added defineIntegrationExtension types a custom extension end to end

A custom extension you write with it is typed without hand-written generics.

What changed ▸
Changed

defineIntegrationExtension in @alokai/connect/integration-kit infers the types of a custom extension's API methods, hooks, and extendApp. @vsf-enterprise/sapcc-api uses it for its own custom extension.

@alokai/connect

added normalizeGraphQLError maps GraphQL error codes to HTTP status codes

A GraphQL integration of your own can normalize its errors the way the shipped integrations do.

What changed ▸
Changed

normalizeGraphQLError maps GraphQL error codes to HTTP status codes: UNAUTHENTICATED to 401, FORBIDDEN to 403, and GRAPHQL_VALIDATION_FAILED to 422. It works the same for Apollo Client, urql, and graphql-request, and it doesn't need graphql as a dependency.

@alokai/connect

changed headers inside defaultRequestConfig is read as an async function Action needed

If your SDK config passes headers inside defaultRequestConfig, make it return a promise so it typechecks. If you use the getRequestHeaders method that buildModule supplies, you have nothing to do.

step →
What changed ▸
Why

The headers value is now awaited, so its type has to say it's async.

Changed

The headers value inside defaultRequestConfig is read as an async function. A synchronous one no longer typechecks against middlewareModule.

@alokai/connect

fixed InferCustom falls back to Record<string, unknown>

A $custom value you had to cast before may now index directly.

What changed ▸
Changed

The InferCustom type alias falls back to Record<string, unknown> instead of object.

@alokai/connect

fixed CONFIG type inference resolves workflow ids again

TypeScript checks the workflow ids you index by again.

What changed ▸
Changed

CONFIG type inference works when an identify function that uses the Integration interface supplies extensions. keyof typeof config.configuration.workflows resolves to the literal union instead of string | number | symbol.

@alokai/connect

changed The dev-mode logger prints one formatted line per entry

Your development terminal shows readable lines instead of JSON objects.

What changed ▸
Changed

In development mode, the logger prints each entry as one formatted line instead of JSON. GCPStructuredDTO.severity is typed as the GCPSeverity union.

@alokai/connect

fixed middlewareModule stops throwing on a Symbol property access

React's development hooks no longer crash when they probe SDK modules by Symbol, and the SDK loads under Vite.

What changed ▸
Changed

middlewareModule in @alokai/connect/sdk returns undefined for a non-string property access instead of throwing. The SDK no longer crashes with process is not defined under browser-first bundlers such as Vite.

@alokai/connect

changed middleware-headers, redis-sdk, cookies-bridge and cms-mock-api move

Match these versions when you upgrade. There's no API change to port.

What changed ▸
Changed

@vsf-enterprise/middleware-headers 4.0.0, @vsf-enterprise/redis-sdk 3.0.0, and @alokai/cookies-bridge 1.0.2 carry only the workspace-wide build and dependency changes. @vsf-enterprise/cms-mock-api 4.0.0 adds a commerce-mock environment for the new --commerce=commerce-mock project shape.

@vsf-enterprise/middleware-headers@vsf-enterprise/redis-sdk@alokai/cookies-bridge@vsf-enterprise/cms-mock-api

changed The four core metrics move under plugins.core Action needed

If your code reads app.locals.alokaiMetrics.integrationLatency or one of its three siblings, it gets undefined until you add plugins.core to the path.

step →
What changed ▸
Why

The four core metrics now sit beside metrics you register yourself, so they move into their own namespace instead of staying at the top level.

Changed

@alokai/instrumentation 2.0.0 removes integrationLatency, integrationRequests, overallLatency, and overallRequests from the top level of AlokaiMetrics. They're under plugins.core.* instead. @alokai/instrumentation 2.0.0 also adds registerMetricPlugin and a MetricPlugin interface for registering your own metrics and endpoints.

@alokai/instrumentation

changed defineIntegrationExtension accepts an extension with no extendApiMethods at all highlight 2.0.2

An extension that only wires hooks or only sets extendApp can leave extendApiMethods out. Where you pass methods in an argument written inline, the second overload still infers them, so extension.extendApiMethods.myMethod keeps working without a !.

What changed ▸
Why

An extension that only wires hooks had to declare an empty extendApiMethods: {} just to satisfy the type.

Changed

extendApiMethods is optional on IntegrationExtensionParams. The factory that defineIntegrationExtension() returns is overloaded: one overload takes an argument without it, the other an argument with it.

@alokai/connect

changed defineIntegrationExtension narrows extendApiMethods to undefined when you pass its argument as a variable, and tsc fails highlight Action needed 2.0.2

An argument written inline, the shape the boilerplate extension in a project generated at 2.0.1 uses, changes nothing. If you built the argument as a variable first, your yarn typecheck breaks on the upgrade, so move the object back to the call site. Spreading the variable ({ ...params }) doesn't help - it still picks the no-methods overload.

step →
What changed ▸
Why

The overloads that make extendApiMethods optional pick the wrong one when the argument is a variable instead of an object literal written at the call site.

Changed

The no-methods overload is declared first, and its parameter type is Omit<IntegrationExtensionParams<...>, "extendApiMethods">. A call written as defineIntegrationExtension()(params), where params is a variable, matches it even though params carries extendApiMethods. The result types as IntegrationExtension<undefined, ...>, and any access on it fails with TS18048: 'x.extendApiMethods' is possibly 'undefined'.

@alokai/connect
StorefrontAction needed11 changes

changed Your Next.js storefront moves to Next.js 16 with React 19 highlight Action needed

No package bump touches the app, so the framework migration is yours, and your storefront doesn't build until you do it. The work is asynchronous params and searchParams, a rewritten next-intl routing config, and renaming middleware.ts to proxy.ts.

step →
What changed ▸
Why

The storefront apps are files your project owns, so no package can move them to a new framework major. The packages can only declare which versions they need.

Changed

@vue-storefront/next 7.0.0 declares peer dependencies on Next.js 15+ and React 19. The generated app ships on next 16.1.6, react 19.2.3, next-intl 4.6.0, and @storefront-ui/react 4.0.0.

@vue-storefront/next

changed Your Nuxt storefront moves to Nuxt 4 highlight Action needed

No package bump touches the app, so the framework migration is yours, and your storefront doesn't build until you do it. The work is the i18n v10 directory move, the @nuxt/image v2 provider API, and replacing useJsonld with useHead.

step →
What changed ▸
Why

The storefront apps are files your project owns, so no package can move them to a new framework major. The packages can only declare which versions they need.

Changed

@vue-storefront/nuxt 10.0.0 requires Nuxt ^4.0.0. It comes with @nuxtjs/i18n 10, @nuxt/image 2, @vite-pwa/nuxt 1, and @storefront-ui/vue 3. nuxt-jsonld is dropped because it doesn't run on Nuxt 4.

@vue-storefront/nuxt

changed Tailwind 4 replaces tailwind.config.ts with a CSS entry point highlight Action needed

Port every customization in tailwind.config.ts into CSS by hand. @tailwind base/components/utilities stops working. The two CSS files aren't interchangeable: nuxt.css imports @storefront-ui/vue/tailwind-config and the Next.js one imports the React one. next.config.mjs gains a sassOptions.additionalData hook meant to inject @reference into every *.module.scss, but it never runs under Next.js 16's default Turbopack bundler. Add the directive by hand to every SCSS module that uses @apply, or it fails to compile.

step →
What changed ▸
Why

Tailwind 4 reads its configuration from CSS, not from a config file. There's no newer form of your tailwind.config.ts to rewrite it into, so it has to be ported.

Changed

tailwindcss moves from 3.4.4 to 4.1.14 in both storefront apps and your local packages/tailwind-config. That package is no longer a built TypeScript package, and ships nextjs.css and nuxt.css instead. Each app's tailwind.config.ts is deleted, and a CSS entry point that uses @import and @source replaces it.

changed env() from @vue-storefront/next replaces next-runtime-env Action needed

Every Alokai Next.js storefront generated up to 1.4.6 imports from next-runtime-env, so rewriting those imports is required, not optional.

step →
What changed ▸
Why

Your storefront read runtime environment variables through a third-party package. Alokai now ships that function itself, so your imports have to change.

Changed

env() from @vue-storefront/next replaces the next-runtime-env package. It reads NEXT_PUBLIC_* variables on both the server and the client. AlokaiProvider injects them, so you don't add a provider of your own. Changes you make at runtime in the Alokai Console apply without a rebuild.

@vue-storefront/next

changed @alokai/instrumentation-nuxt-module replaces the Nuxt 3 module

In a Nuxt project, you swap the package as part of the Nuxt 4 step, not separately.

What changed ▸
Changed

@alokai/instrumentation-nuxt-module 1.0.0 replaces @alokai/instrumentation-nuxt3-module. @alokai/instrumentation no longer sends traces when the host is localhost.

@alokai/instrumentation-nuxt-module@alokai/instrumentation-nuxt3-module

changed ProductCardVertical takes the product prop directly

The component is your own file and no upgrade rewrites it, so nothing breaks and no step covers it. The new shape is optional. If you adopt it, update your call sites at the same time.

What changed ▸
Changed

ProductCardVertical takes the product prop directly instead of receiving it through its ancestor components.

changed The X-Frame-Options opt-out in the shipped Next.js request-handling file is inverted Action needed

If you adopt the shipped file as written, the value nearly every project copied from .env.example turns the header off, and your storefront stops sending X-Frame-Options: DENY. Keep your own !== 'true' condition instead.

step →
What changed ▸
Why

The shipped request-handling file turns off the X-Frame-Options header for the value most projects set.

Changed

The X-Frame-Options opt-out in the Next.js storefront's request-handling file reads env('NEXT_PUBLIC_DISABLE_X_FRAME_OPTIONS_HEADER') !== 'false'. It used to read !== 'true'. .env.example still ships NEXT_PUBLIC_DISABLE_X_FRAME_OPTIONS_HEADER=false.

changed cms-components-utils and eslint-config follow the storefront

Both updates belong with the framework step, because the Next.js migration needs the lint rule off.

What changed ▸
Changed

@vsf-enterprise/cms-components-utils 3.1.1 tracks the Storefront UI version bump. @vue-storefront/eslint-config 5.1.2 disables react/destructuring-assignment.

@vsf-enterprise/cms-components-utils@vue-storefront/eslint-config

fixed @storefront-ui/nuxt now declares Nuxt 4 support itself instead of leaning on your resolutions override highlight 2.0.2

On 3.3.0 the module resolves onto your own Nuxt 4 kit without the override, and nothing is broken today if the override is there. The upgrade never rewrites this manifest, so the move is a hand edit.

step →
What changed ▸
Why

At 3.1.1, the module asked for a Nuxt 3 @nuxt/kit while the app runs Nuxt 4. In a generated project, only a resolutions entry papered over that.

Changed

apps/storefront-unified-nuxt/package.json moves @storefront-ui/nuxt from 3.1.1 to 3.3.0, where @nuxt/kit relaxes to >=3.13.2 and @nuxtjs/tailwindcss to >=7.0.0-beta.1. The bundled @storefront-ui/vue stays at 3.1.1, so no component changes.

@storefront-ui/nuxt

fixed A CMS outage makes your CMS route answer 404, and the fix is yours to apply highlight Action needed 2.0.3

The upgrade doesn't repair this: your sf-modules/<cms module>/components/connect-cms-page.tsx was written when your project was created or when you adopted the module, and no published package carries the fix to it. The fix is a hand edit, with a cost on your category and product pages to weigh first.

step →
What changed ▸
Why

Your connectCmsPage discards every CMS error, so a CMS outage looks like a page that doesn't exist and your content URLs answer 404 for its whole duration. Search engines and your CDN act on that 404.

Changed

connectCmsPage now checks the error before it decides what to do. Every CMS module's source replaces its blanket .catch() with isSpecificSdkHttpError(error, { statusCode: 404 }) from @alokai/connect/sdk: a 404 falls through to the existing !page branch, and any other error is rethrown. cms-builderio also moves its notFound() call into its own page, so the wrapper hands page={null} to the consumer.

changed The CMS 404 fix makes a CMS outage break your category and product pages highlight Action needed 2.0.3

Today a CMS 500 on a category page is invisible. After the fix, the same 500 takes the category or product page down with it - the right trade for a content route and a debatable one for your catalog, so it's yours to decide. Narrowing the fix to the CMS route only isn't simple, because most projects have a single connect-cms-page.tsx that all three routes import.

step →
What changed ▸
Why

connectCmsPage wraps more than your CMS catch-all route, so a CMS error the fix rethrows escapes from your category and product pages too.

Changed

In a generated Next.js project, connectCmsPage also wraps app/[locale]/(default)/category/[[...slugs]]/page.tsx and app/[locale]/(default)/product/[slug]/[id]/page.tsx. On those pages the CMS content is optional, rendered through page?.componentsTop and page?.componentsBottom.

CLI & toolingAction needed15 changes

changed Alokai packages are built with tsdown

Every package you install from this release has a regenerated module format and entry points, even where its source didn't change.

What changed ▸
Changed

The @vsf-enterprise and @alokai packages are built with tsdown. Most move from Rollup; the five unified-api-* packages, @alokai/cli, @alokai/cli-plugin-compass, @vsf-enterprise/module-kit and @vsf-enterprise/storefront-cli move from unbuild, and @vue-storefront/next from tsup. The Nuxt modules keep building with nuxt-module-build. The change reaches 58 published packages.

changed Internal dependencies were updated for Yarn 4 compatibility across 53 packages

This update is why so many packages in this release carry a major version bump with no API change of their own.

What changed ▸
Changed

53 packages update their internal dependencies for Yarn 4 compatibility.

changed Dependency versions were aligned across 45 SDK, tooling and shared-config packages

The alignment comes with the package versions you upgrade to, and you have nothing to apply.

What changed ▸
Changed

Dependency versions are aligned across 45 SDK, tooling, and shared-config packages, including all four packages the ecosystem version pins.

changed 19 packages take their shared types from the -types packages

A type you import from an -api package may now resolve through its -types package instead.

What changed ▸
Changed

19 packages take shared types from the -types packages instead of redeclaring them. @alokai/cli, @alokai/connect, @vue-storefront/next, and @vue-storefront/nuxt are among them.

changed @vue-storefront/changesets and @vue-storefront/sdk-axios-request-sender changed owner

Both packages are internal to the build. @vue-storefront/sdk-axios-request-sender reaches you only as a dependency of the SDK packages.

What changed ▸
Changed

Ownership of @vue-storefront/changesets and @vue-storefront/sdk-axios-request-sender is transferred. Their public API and behavior don't change.

@vue-storefront/changesets@vue-storefront/sdk-axios-request-sender

added The CLI detects and uses your project's package manager

If you adopt the new middleware manifest, your project needs @antfu/ni available.

What changed ▸
Changed

@alokai/cli 2.4.0 detects the package manager your project is configured for - npm, yarn, pnpm, or bun - and runs it through ni. When @antfu/ni is missing, the CLI reports an installation message instead of failing with spawn nr ENOENT. The generated apps/storefront-middleware/package.json runs nr start in its start:standalone script.

@alokai/cli

fixed store commands gain --skip-compose and a round of fixes

The upgrade brings all of it in with the new @alokai/cli, and there's nothing to apply.

What changed ▸
Changed

store build accepts a --skip-compose flag. The CLI no longer generates tailwind.config.ts files, because Tailwind 4 is configured from CSS.

Store composition skips excluded directories and copies files in parallel. It no longer wrongly excludes nested directories such as node_modules/@alokai/compass/lib.

The CLI resolves the package-manager binary reliably under Yarn Berry. store prepare no longer hits an ESLint failure, and store deploy no longer fails on a missing assemble-release-plan patch. The CLI supports Next.js 15+ deployment, drops an unused zod dependency, and runs its Docker containers on Node.js 22 instead of Node.js 18.

@alokai/cli

added storefront-cli adds an interactive dev-module command

You don't need a hand-written config in the module directory to author a module locally.

What changed ▸
Changed

@vsf-enterprise/storefront-cli 3.2.0 adds an interactive dev-module command. It generates tsconfig.json, eslint.config.mjs, and .prettierrc.mjs inside module directories and keeps them out of .out. The add-module command accepts --cwd, and create accepts --commerce=commerce-mock.

@vsf-enterprise/storefront-cli

removed file-modifier removes createAddToFunctionFirstObjectArgumentVisitor Action needed

This affects you only if you author modules. An install.js that calls the removed visitor stops building. If you assert on a module's expected output character for character, regenerate its fixtures.

step →
What changed ▸
Why

Two visitors did the same job: the first-argument visitor is the Nth-argument visitor at position: 0.

Changed

@vsf-enterprise/file-modifier 4.0.0 removes createAddToFunctionFirstObjectArgumentVisitor. createAddToFunctionNthObjectArgumentVisitor with position: 0 replaces it. The package adds createUpdateJsxVisitor, createAddInterfacePropertyVisitor, createAddToFunctionParameterDestructuringVisitor, createJsxStatements, createJsxAttributes, jsxElementMatches, jsxExpressionMatches, findRootJsxStatements, findNode, compareNodes, and parseNode.

Its visitors emit double-quoted strings. This fixes modifications of Tailwind class attributes.

@vsf-enterprise/file-modifier

changed module-kit derives its paths from store.sourcePath

A module installs correctly into a project whose apps don't live under /apps.

What changed ▸
Changed

@vsf-enterprise/module-kit 5.0.0 derives the middleware, Nuxt, Next.js, and Playwright paths from store.sourcePath instead of assuming /apps. It adds baseNextjsAppSchemas and baseNuxtPagesSchemas, adds moduleConfig to createAddMiddlewareModuleVisitor, and adds commerce-mock to ECOMMERCE_VALUES. Module installation no longer copies the config files that dev-module generates.

@vsf-enterprise/module-kit

changed The integration boilerplates generate Vitest configuration

A newly generated integration comes with the test runner the middleware app already uses. The CLI resolves both boilerplate versions, so you don't edit a manifest.

What changed ▸
Changed

@alokai/boilerplate-integration and @alokai/boilerplate-integration-extension 2.0.0 generate Vitest configuration instead of Jest. Tests run against the middleware app's own vitest.config.ts. The integration boilerplate also includes the Next.js async params and next-intl redirect changes.

@alokai/boilerplate-integration@alokai/boilerplate-integration-extension

fixed The Playwright app gains the typescript devDependency it was missing

The Playwright manifest is your file, so the typescript, h3, and unstorage edits are yours to make if you want them.

What changed ▸
Changed

apps/playwright/package.json gains the typescript devDependency it was missing, at 5.6.2. Its h3 pin moves to 1.15.5, and its unstorage pin moves to 1.17.4.

changed A newly created project receives AGENTS.md and CLAUDE.md

Your own .cursorrules and .windsurfrules stay where they are and keep working. The upgrade doesn't remove them.

What changed ▸
Changed

A newly created project receives AGENTS.md and CLAUDE.md instead of .cursorrules and .windsurfrules. Its CI workflow gets a Typecheck project step, and it no longer gets commitlint.

removed A generated project stops declaring @vsf-enterprise/unified-api-mocks

The published 3.0.0 still resolves, and nothing in a generated project imports it. Leaving it in your manifest breaks nothing, and removing it is safe.

What changed ▸
Changed

A generated project no longer declares @vsf-enterprise/unified-api-mocks. This release no longer builds the package.

@vsf-enterprise/unified-api-mocks

fixed yarn typecheck on a composed store now has a task that builds the middleware first highlight Action needed 2.0.1

The upgrade doesn't touch turbo.json, and the CLI writes per-store tasks only when you add a store, so add both kinds of entry to your existing project once.

step →
What changed ▸
Why

On a composed store, yarn typecheck ran tsc --noEmit without building the middleware first, so it needed declaration output that no task produced. And because .out/ is gitignored, turbo could answer a per-store typecheck from cache whatever you had edited.

Changed

A generated project's root turbo.json gains storefront-unified-nextjs#typecheck and storefront-unified-nuxt#typecheck, each with dependsOn: ["storefront-middleware#build"]. The CLI now copies typecheck alongside the other per-store tasks, producing storefront-unified-nextjs-<store>#typecheck with dependsOn: ["storefront-middleware-<store>#build"] and inputs: ["**"].

@alokai/cli
CompassAction needed2 changes

changed @alokai/compass 2.0.0 removes two export paths and adds an SDK module Action needed

If you use Compass, move every import from @alokai/compass/next and @alokai/compass/client, and rewrite code that iterates AssistantMessage.content as an array.

step →
What changed ▸
Why

The client-side API was split across two export paths, @alokai/compass/next and @alokai/compass/client.

Changed

@alokai/compass 2.0.0 removes the @alokai/compass/next and @alokai/compass/client export paths. A first-party SDK module at @alokai/compass/sdk replaces them. Integration types move to @alokai/compass/server.

AssistantMessage's content is an object instead of an array. You can supply the whole AssistantMessageContent, so you can set contextType and componentId yourself.

getMcpSessionData is on both the API client and the SDK module. ChatGPT Apps sessions are tracked by the openai/session body parameter instead of the Mcp-Session-Id header. Compass fetches its credentials from an external secrets manager keyed on ALOKAI_COMPASS_API_KEY.

Cache keys include DOCKER_IMAGE_TAG. The OpenAI models are pinned to gpt-4.1-2025-04-14, gpt-4.1-mini-2025-04-14, and gpt-4o-mini-2024-07-18. A new defineMcpWidget helper builds MCP widgets, and .tsx MCP widgets hot reload. Tool schemas get chatHistory and isCalledByAi properties automatically.

@alokai/compass

changed compass tool generate writes one file per schema

If you import a generated schema by its file path, that path changes.

What changed ▸
Changed

In @alokai/cli-plugin-compass 1.1.0, compass tool generate writes each Zod schema to its own file instead of one combined file.

@alokai/cli-plugin-compass
SAP Commerce CloudAction needed4 changes

removed sapcc-api removes the legacy extension and the custom logger hooks Action needed

A legacy endpoint you still call returns 404 from the middleware, and your build doesn't fail on it. A logger key in your SAPCC integration config is ignored, so a custom logger you set there stops being used.

step →
What changed ▸
Why

Both were long deprecated. Their removal fails quietly, not with a build error, so code that still uses them keeps building and then misbehaves at runtime.

Changed

@vsf-enterprise/sapcc-api 11.0.0 removes the deprecated legacy extension, with its API methods and its exported types. It also removes setupLogger and validateLogger. You configure custom logging through the standard @alokai/connect logger.

@vsf-enterprise/sapcc-api

fixed SAPCC token handling throws typed errors

A misconfigured token setup tells you what's wrong, instead of returning an undefined that surfaces further down.

What changed ▸
Changed

Token handling in @vsf-enterprise/sapcc-api throws ValidationError for bad OAuth credentials, endpoints, or URIs. It throws HttpError with the real status code for authentication failures. ApplicationTokenService.getApplicationToken() throws on a token response that isn't JSON. Before, it returned undefined.

@vsf-enterprise/sapcc-api

added ASM typings ship in @vsf-enterprise/sapcc-types Action needed

If you adopted the SAP-ASM Storefront module, its files are yours, and the upgrade doesn't rewrite their imports. You change them to the Asm namespace yourself.

step →
What changed ▸
Why

The SAP-ASM module took its types from the webservices SDK, not from the types package the rest of the integration uses.

Changed

@vsf-enterprise/sapcc-types 4.1.0 ships the ASM typings under the Asm namespace. The SAP-ASM module takes its types from there, not from @vsf-enterprise/sap-commerce-assisted-service-module-webservices-sdk.

@vsf-enterprise/sapcc-types

changed unified-api-sapcc and the SAPCC SDKs move

These are versions to match. There's no API change to port.

What changed ▸
Changed

@vsf-enterprise/unified-api-sapcc 6.0.0 updates changeCustomerPassword to work with the normalized HttpErrors, and moves to zod v4.

@vsf-enterprise/sapcc-sdk 7.0.0, @vsf-enterprise/sap-commerce-webservices-sdk 7.0.1, @vsf-enterprise/sap-commerce-assisted-service-module-webservices-sdk 4.0.1, and @vsf-enterprise/smartedit-sdk 3.0.0 carry only the workspace-wide changes.

@vsf-enterprise/unified-api-sapcc@vsf-enterprise/sapcc-sdk@vsf-enterprise/sap-commerce-webservices-sdk@vsf-enterprise/sap-commerce-assisted-service-module-webservices-sdk@vsf-enterprise/smartedit-sdk
commercetoolsAction needed3 changes

changed commercetools GraphQL errors stop being data and start being exceptions Action needed

Code that checks result.errors never runs its error branch again, so every such call site needs a try/catch.

step →
What changed ▸
Why

A GraphQL failure arrived as a successful HTTP response with an error payload. A catch block never saw it, so only an error branch that read result.errors handled it.

Changed

Every GraphQL method in @vsf-enterprise/commercetools-api 8.0.0 throws a normalized HttpError instead of returning the errors in the response. Business-logic errors throw 422, and network failures throw 502. Every operation runs with errorPolicy: 'all' and fetchPolicy: 'no-cache'.

customerSignMeUp (alias signUp) throws on failure instead of returning undefined. The updateCart version-mismatch retry stays, and so does the deliberate error hiding in customerCreatePasswordResetToken. The default customer data adds isEmailVerified.

@vsf-enterprise/commercetools-api

changed unified-api-commercetools reads GraphQL errors off error.data

The unified methods follow the new commercetools error shape on their own.

What changed ▸
Changed

In @vsf-enterprise/unified-api-commercetools 5.0.0, loginCustomer and changeCustomerPassword read GraphQL errors from error.data.graphQLErrors.

@vsf-enterprise/commercetools-sdk 6.0.0 and @vsf-enterprise/commercetools-types 3.0.2 carry only the workspace-wide changes.

@vsf-enterprise/unified-api-commercetools@vsf-enterprise/commercetools-sdk@vsf-enterprise/commercetools-types

changed The Stripe packages carry only the workspace-wide changes

Their behavior doesn't change, so the upgrade is only a version bump.

What changed ▸
Changed

@vsf-enterprise/stripe-commercetools 9.0.0 and @vsf-enterprise/stripe-commercetools-sdk 4.0.0 carry only the tsdown build change and the dependency updates for Yarn 4.

@vsf-enterprise/stripe-commercetools@vsf-enterprise/stripe-commercetools-sdk
Magento 2Action needed2 changes

changed Magento normalizes its GraphQL errors Action needed

A response that used to return HTTP 200 with an error payload now throws, so code that reads the payload never runs. Match HttpError in a catch block instead, and read the original error from error.cause.

step →
What changed ▸
Why

Magento returned its GraphQL errors in an HTTP 200 response, as commercetools did, so a catch block never saw them.

Changed

@vsf-enterprise/magento-api 9.0.0 normalizes every GraphQL error to HttpError and throws it.

@vsf-enterprise/magento-api

fixed unified-api-magento stops mutating frozen carts

The Cannot assign to read only property errors from frozen carts are fixed with the package version.

What changed ▸
Changed

@vsf-enterprise/unified-api-magento 6.0.0 no longer mutates the frozen cart objects that Apollo Client returns under errorPolicy: 'all'. It works on a new cart instead.

@vsf-enterprise/magento-sdk 7.0.0 and @vsf-enterprise/magento-types 4.0.2 carry only the workspace-wide changes.

@vsf-enterprise/unified-api-magento@vsf-enterprise/magento-sdk@vsf-enterprise/magento-types
BigCommerceAction needed2 changes

changed BigCommerce normalizes its v2 and v3 client errors Action needed

A catch block that matches the BigCommerce clients' own error types no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

The BigCommerce v2 and v3 clients threw their own error types, so a catch block written for them matched no other integration.

Changed

@vsf-enterprise/bigcommerce-api 9.0.0 normalizes errors from the v2 and v3 clients to HttpError. It exports the BigCommerceAdapter type. It also moves graphql-request from ^7.2.0 to ^7.4.0.

@vsf-enterprise/bigcommerce-api

fixed bigcommerce-types exports ProductPreOrder as a type

The ESM runtime error from ProductPreOrder is gone with the package version.

What changed ▸
Changed

@vsf-enterprise/bigcommerce-types 3.1.1 exports ProductPreOrder with export type, which fixes an ESM runtime error. @vsf-enterprise/unified-api-bigcommerce 5.0.0 standardizes its errors on context.createHttpError(), with the ValidationError and UnauthorizedError domain errors.

@vsf-enterprise/bigcommerce-types@vsf-enterprise/unified-api-bigcommerce
Salesforce Commerce Cloud1 change

changed unified-api-sfcc standardizes on context.createHttpError()

This is a version to match, with no API change of its own.

What changed ▸
Changed

@vsf-enterprise/unified-api-sfcc 5.0.0 moves to zod v4 and fixes its package typings. Its API methods standardize on context.createHttpError(), with the ValidationError and UnauthorizedError domain errors.

@vsf-enterprise/unified-api-sfcc
Elastic PathAction needed1 change

changed Elastic Path normalizes errors from the Moltin/EPCC client Action needed

A catch block that matches the EPCC client's own error types no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

The EPCC client threw its own error types and put the status code inside an errors array, so a catch block had to dig it out.

Changed

@vsf-enterprise/epcc-api 5.0.0 normalizes errors from clients created via onCreate() to HttpError. It keeps the 4xx or 5xx status code, including a status the client put in the errors array. It marks every error upstream: true and exports the EpccAdapter type.

@vsf-enterprise/epcc-api
ContentfulAction needed1 change

changed Contentful normalizes its client errors Action needed

A catch block that matches sys.id === 'NotFound' or a raw axios error no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

Contentful's SDK threw its own NotFoundError beside bare axios errors, so a catch block had to match both.

Changed

@vsf-enterprise/contentful-api 7.0.0 normalizes errors from clients created via init() to HttpError. It maps the SDK's NotFoundError to 404, with the resource details attached. It marks errors upstream: true and exports the ContentfulAdapter type.

@vsf-enterprise/contentful-sdk 7.0.0 carries only the workspace-wide changes.

@vsf-enterprise/contentful-api@vsf-enterprise/contentful-sdk
ContentstackAction needed3 changes

changed Contentstack field names keep the CMS's own snake_case Action needed

Components you render through RenderCmsContent need no change, because the module's wrapper components map the names for you. Rename every field name you read yourself.

step →
What changed ▸
Why

The integration converted Contentstack field names to camelCase, so the names in your code didn't match your Contentstack schema, and you couldn't use its generated TypeScript types directly.

Changed

@vsf-enterprise/contentstack-api 7.0.0 returns Contentstack field names in the CMS's own snake_case, instead of converting them to camelCase. For example, page.componentsAboveFold becomes page.components_above_fold, and data.backgroundImage becomes data.background_image.

@vsf-enterprise/contentstack-api

fixed Contentstack live preview initializes correctly, and getLivePreviewAttributes arrives Action needed

If your own package.json declares @contentstack/live-preview-utils, re-pin it to ^4.2.1. Otherwise you have nothing to do.

step →
What changed ▸
Why

The SDK's live preview initialization had a bug, and Visual Builder had no helper for inline editing.

Changed

@vsf-enterprise/contentstack-sdk 7.0.0 fixes how live preview initializes and requires @contentstack/live-preview-utils ^4.2.1. The new sdk.contentstack.utils.getLivePreviewAttributes() returns the attributes Visual Builder needs for inline editing.

The enable: true opt-in, the move to @contentstack/live-preview-utils v4 and the extractComponents removal came with 6.0.0, at 1.4.3.

@vsf-enterprise/contentstack-sdk@contentstack/live-preview-utils

fixed Contentstack returns live-edit tags and fixes two runtime incompatibilities

The live-edit tags and both compatibility fixes arrive with the package versions, with nothing to change in your code.

What changed ▸
Changed

The unified normalizers and unified.getPage in @vsf-enterprise/contentstack-api return the live-edit tags whenever { livePreview: { enable: true } } is configured. An ESM incompatibility in the package is fixed.

@vsf-enterprise/contentstack-sdk works in the Next.js Edge Runtime in the request-handling file. That file is middleware.ts on Next.js 15 and earlier, and Next.js 16 renames it to proxy.ts.

@vsf-enterprise/contentstack-api@vsf-enterprise/contentstack-sdk
StoryblokAction needed1 change

changed Storyblok normalizes its client errors Action needed

A catch block that matches the Storyblok client's own error types no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

The Storyblok client threw its own error types, so a catch block written for it matched no other integration.

Changed

@vsf-enterprise/storyblok-api 4.0.0 normalizes errors from clients created via init() to HttpError. It keeps the upstream status codes, marks errors upstream: true, and exports the StoryblokAdapter type.

@vsf-enterprise/storyblok-sdk 3.0.0 carries only the workspace-wide changes.

@vsf-enterprise/storyblok-api@vsf-enterprise/storyblok-sdk
AmplienceAction needed1 change

changed Amplience normalizes ContentClient errors Action needed

A catch block that matches ContentNotFoundError or a raw axios error no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

Amplience threw its own ContentNotFoundError beside unwrapped axios errors, so a catch block had to match both.

Changed

@vsf-enterprise/amplience-api 7.0.0 normalizes ContentClient errors to HttpError. It maps the SDK's ContentNotFoundError to 404, and an unwrapped axios error to its own status code. It also exports the AmplienceAdapter type.

@vsf-enterprise/amplience-sdk 5.0.0 carries only the workspace-wide changes.

@vsf-enterprise/amplience-api@vsf-enterprise/amplience-sdk
Builder.ioAction needed1 change

changed Builder.io normalizes its client errors Action needed

A catch block that matches the Builder.io client's own error types no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

Builder.io network and fetch failures arrived without a status code of their own, so a catch block had nothing to branch on.

Changed

@vsf-enterprise/builderio-api 5.0.0 normalizes errors from clients created via init() to HttpError. It keeps the upstream status code where there is one, and returns 502 for network and fetch failures. It also exports the BuilderAdapter type.

@vsf-enterprise/builderio-sdk 5.0.0 carries only the workspace-wide changes.

@vsf-enterprise/builderio-api@vsf-enterprise/builderio-sdk
Bloomreach ContentAction needed1 change

changed Bloomreach Content normalizes its client errors Action needed

A catch block that matches the Bloomreach Content client's own error types no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

The Bloomreach Content client threw its own error types, so a catch block written for it matched no other integration.

Changed

@vsf-enterprise/bloomreach-content-api 4.0.0 normalizes errors from clients created via buildClient() to HttpError. It also exports the BloomreachContentAdapter type.

@vsf-enterprise/bloomreach-content-sdk 6.0.0 and @vsf-enterprise/bloomreach-content-manager 3.0.0 carry only the workspace-wide changes and updated TSDocs.

@vsf-enterprise/bloomreach-content-api@vsf-enterprise/bloomreach-content-sdk@vsf-enterprise/bloomreach-content-manager
SanityAction needed1 change

changed Sanity normalizes ClientError and ServerError Action needed

A catch block that matches ClientError or ServerError no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

The Sanity client threw two error classes of its own, so a catch block had to match both.

Changed

@vsf-enterprise/sanity-api 6.0.0 normalizes ClientError and ServerError from the Sanity client to HttpError, with their original status codes. It marks errors upstream: true and exports the SanityAdapter type alias.

@vsf-enterprise/sanity-sdk 4.0.0 carries only the workspace-wide changes.

@vsf-enterprise/sanity-api@vsf-enterprise/sanity-sdk
SmartEdit1 change

changed smartedit-api returns real status codes from getPage

You can tell SmartEdit failures apart by their status code, instead of getting one opaque error.

What changed ▸
Changed

getPage in @vsf-enterprise/smartedit-api 6.0.0 returns 400 Bad Request for missing configuration, 404 Not Found for a missing page, and 500 Internal Server Error for a server failure. It also logs the underlying error.

@vsf-enterprise/smartedit-api
AlgoliaAction needed1 change

changed Algolia normalizes its client errors Action needed

A catch block that matches the Algolia client's own error types no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

The Algolia client threw its own error types, so a catch block written for it matched no other integration.

Changed

@vsf-enterprise/algolia-api 7.0.0 normalizes errors from clients created via init() to HttpError. It marks every error upstream: true and exports the AlgoliaAdapter type alias.

@vsf-enterprise/algolia-api
Bloomreach DiscoveryAction needed1 change

added A REST-based Bloomreach Discovery integration arrives beside the GraphQL one, and Discovery normalizes its client errors Action needed

The legacy configuration keeps working, so the move to REST is one you schedule. The error change isn't optional: a catch block that matches the Discovery client's own error types no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

Bloomreach publishes its Discovery API as a REST API with OpenAPI specs, and the integration used GraphQL instead.

Changed

@vsf-enterprise/bloomreach-discovery-api 7.0.0 implements the official Bloomreach Discovery REST API. It covers Product and Category Search, Autosuggest, Content Search, Bestseller, Recommendations and Pathways, Email Widget, and Facet 3.0. Its typed methods are generated from the OpenAPI specs, and a createUnifiedExtension provides searchProducts and getProductDetails.

A legacy configuration block keeps the GraphQL endpoint running beside the REST API during a migration. A new search-bloomreach Storefront module installs the storefront side.

The same package normalizes its client errors to HttpError, with 502 for network errors. @vsf-enterprise/bloomreach-discovery-sdk 6.0.0 carries only the workspace-wide changes and updated TSDocs.

@vsf-enterprise/bloomreach-discovery-api@vsf-enterprise/bloomreach-discovery-sdk
Constructor.ioAction needed1 change

changed Constructor.io normalizes its client errors Action needed

A catch block that matches the Constructor.io client's own error types no longer matches. Match HttpError instead, and read the original error from error.cause.

step →
What changed ▸
Why

The Constructor.io client threw its own error types, so a catch block written for it matched no other integration.

Changed

@vsf-enterprise/constructor-io-api 4.0.0 normalizes client errors to HttpError, and returns 400 for missing or invalid parameters. It marks errors upstream: true and keeps the request URL on them. It also exports the ConstructorIOAdapter type alias and the ConstructorIONormalizerConfig interface.

@vsf-enterprise/constructor-io-api
CoveoAction needed1 change

removed Coveo replaces WhitelistException with HttpError Action needed

A catch block that matches WhitelistException or HttpException no longer matches. Match HttpError instead.

step →
What changed ▸
Why

The Coveo integration threw its own WhitelistException, so a catch block written for it matched no other integration.

Changed

@vsf-enterprise/coveo-api 4.0.0 replaces WhitelistException with HttpError at status 400. Errors from the CoveoService axios client are normalized to HttpError too. The package also moves zod from v3 to v4.

@vsf-enterprise/coveo-api
CI / deployment workflows1 change

fixed The continuous-delivery workflow's memory fix needs nothing from you

You have nothing to apply from this release. If neither edit is in your workflow, apply 1.4.4's workflow step. The release's only edit to continuous-delivery.yml, a duplicate free-up-space step, is harmless and not worth copying.

What changed ▸
Changed

This release carries a fix for out-of-memory and out-of-storage failures in the generated continuous-delivery.yml workflow. The fix rests on two edits that shipped in 1.4.4: freeing up space by removing the Android SDK from the runner, and NODE_OPTIONS: "--max-old-space-size=4096" on the Deploy store step. Both are already in your workflow if your project was generated at 1.4.4 or later, or if you applied 1.4.4's workflow step.

The only change the release makes to that file is a second, duplicate Free up space in the actions runner step.

Patches in 2.0.x

2.0.3

4 Mar 2026 · Patch · 2 of 78 packages moved

One change, and it lands entirely in files your project owns: connect-cms-page.tsx and ConnectCmsPage.vue under sf-modules/, which the upgrade never rewrites. No published package carries it, so running the upgrade command changes nothing about how your CMS pages behave. The fix is a hand edit, and it has a cost to weigh before you make it.

A CMS outage makes your CMS route answer 404, and the fix is yours to apply

Action neededStorefront2.0.3
Why:

Your connectCmsPage discards every error the CMS returns, so a CMS that's down, rate-limiting you, or rejecting your token looks the same as a page that doesn't exist. Your content URLs answer HTTP 404 for the whole outage, and search engines and your CDN act on that 404.

connectCmsPage now checks the error before it decides what to do. Every CMS module's source - cms-mock, cms-amplience, cms-bloomreach-content, cms-builderio, cms-contentful, cms-contentstack, cms-smartedit and cms-storyblok - replaces its blanket .catch() with isSpecificSdkHttpError(error, { statusCode: 404 }) from @alokai/connect/sdk. A 404 falls through to the existing !page branch, and any other error is rethrown.

cms-builderio also moves its notFound() call out of connectCmsPage and into its own app/[locale]/(cms)/[[...slug]]/page.tsx. The wrapper hands page={null} to the consumer, and the consumer decides.

For you:

The upgrade doesn't repair this: your sf-modules/<cms module>/components/connect-cms-page.tsx is yours, written when your project was created or when you adopted the module. A generated project's copy reads .catch(() => null), and a module you adopted reads .catch((error: unknown) => logger.error(error)). The fix is a hand edit in each copy, and it has a cost on your category and product pages to weigh first.

See the step in the upgrade guide →

The CMS 404 fix makes a CMS outage break your category and product pages

Action neededStorefront2.0.3
Why:

connectCmsPage wraps more than your CMS catch-all route, so a CMS error the fix rethrows escapes from your category and product pages too.

In a generated Next.js project, connectCmsPage also wraps app/[locale]/(default)/category/[[...slugs]]/page.tsx and app/[locale]/(default)/product/[slug]/[id]/page.tsx. On those pages the CMS content is optional, rendered through page?.componentsTop and page?.componentsBottom. A rethrown non-404 error propagates out of those server components too.

For you:

Today a CMS 500 on a category page is invisible - the catalog renders without its CMS slots. After you apply the fix, the same 500 takes the category or product page down with it. That's the right trade for a CMS-driven content route and a debatable one for your catalog, so it's yours to decide: apply the fix and accept that cost, or skip it and keep the 404.

Narrowing the fix to your CMS route only isn't the simple third option it sounds like. Most projects have a single connect-cms-page.tsx, re-exported through a barrel and imported by the CMS, category, and product routes alike, so there's no per-route copy to edit. The step sets out what narrowing would take.

See the step in the upgrade guide →

2.0.2

2 Mar 2026 · Patch · 5 of 78 packages moved

Two changes: one for Nuxt projects, and one for anyone who writes a middleware integration extension. The Nuxt one is a pin in your own apps/storefront-unified-nuxt/package.json, so the upgrade doesn't move it. The extendApiMethods one has two highlights below, because it does two things: an extension can now leave its methods out, and an extension whose argument you built as a variable rather than inline now fails tsc.

@storefront-ui/nuxt now declares Nuxt 4 support itself instead of leaning on your resolutions override

OptionalStorefront2.0.2@storefront-ui/nuxt
Why:

At 3.1.1, the module asked for a Nuxt 3 @nuxt/kit while your app runs nuxt 4.3.0. What papered over it was the "@nuxt/kit" entry in your root package.json resolutions, which a project generated at 2.0.0 or 2.0.1 has, but which 2.0.0's own migration guide never told an upgrading project to add.

apps/storefront-unified-nuxt/package.json moves @storefront-ui/nuxt from 3.1.1 to 3.3.0. In 3.3.0, @nuxt/kit relaxes from ^3.13.2 to >=3.13.2, and @nuxtjs/tailwindcss from ^7.0.0-beta.1 to >=7.0.0-beta.1. The bundled @storefront-ui/vue stays at 3.1.1, so no component changes.

For you:

On 3.3.0 the module resolves onto your own Nuxt 4 kit without the override. Nothing is broken today if the override is there - staying on 3.1.1 only keeps you dependent on it. The move is a hand edit, and the step covers what your manifest may hold now, since that depends on how you reached 2.0.x.

See the step in the upgrade guide →

defineIntegrationExtension accepts an extension with no extendApiMethods at all

OptionalAlokai Connect2.0.2@alokai/connect
Why:

An extension that only wires hooks had to declare an empty extendApiMethods: {} just to satisfy the type.

extendApiMethods is optional on IntegrationExtensionParams. The factory that defineIntegrationExtension() returns is overloaded: one overload takes an argument without extendApiMethods, the other an argument with it.

For you:

An extension that only wires hooks or only sets extendApp can leave extendApiMethods out. Where you pass methods in an argument written inline, the second overload still infers them, so extension.extendApiMethods.myMethod keeps working without a !.

defineIntegrationExtension narrows extendApiMethods to undefined when you pass its argument as a variable, and tsc fails

Action neededAlokai Connect2.0.2@alokai/connect
Why:

The overloads that make extendApiMethods optional pick the wrong one when the argument is a variable instead of an object literal written at the call site.

The no-methods overload is declared first, and its parameter type is Omit<IntegrationExtensionParams<...>, "extendApiMethods">, where every property left is optional. TypeScript rejects extra properties only on an object literal written in place. So a call written as defineIntegrationExtension()(params), where params is a variable, matches that first overload even though params carries extendApiMethods. The result types as IntegrationExtension<undefined, ...>, and any access on it fails with TS18048: 'x.extendApiMethods' is possibly 'undefined'.

For you:

If you write the argument inline - defineIntegrationExtension()({ name: '...', extendApiMethods: methods }) - nothing changes. That's the shape the boilerplate extension in a project generated at 2.0.1 uses. If you built the argument as a variable first, your yarn typecheck breaks on the upgrade, so move the object back to the call site. Spreading the variable ({ ...params }) doesn't help - it still picks the no-methods overload.

See the step in the upgrade guide →

2.0.1

23 Feb 2026 · Patch · 3 of 78 packages moved

One change, and it's a repair to yarn typecheck on a composed store. Of the packages you install, only @alokai/cli moves, but the fix itself lands in your project's own turbo.json, which no upgrade rewrites. So it's a hand edit you make once.

yarn typecheck on a composed store now has a task that builds the middleware first

Action neededCLI & tooling2.0.1@alokai/cli
Why:

On a composed store, yarn typecheck ran tsc --noEmit without building the middleware first, so it needed declaration output that no task produced. And because .out/ is in your .gitignore and turbo leaves gitignored files out of its hash, a per-store typecheck could answer from cache whatever you had edited.

A generated project's root turbo.json gains storefront-unified-nextjs#typecheck and storefront-unified-nuxt#typecheck, each with dependsOn: ["storefront-middleware#build"]. When the CLI writes a store's per-app tasks, it now copies typecheck alongside build, lint, test:integration and test:integration:ui. That produces storefront-unified-nextjs-<store>#typecheck with dependsOn: ["storefront-middleware-<store>#build"] and inputs: ["**"], so the middleware builds first and turbo hashes what you edited.

For you:

Neither kind of entry reaches an existing project on its own: the upgrade doesn't touch turbo.json, and the CLI writes per-store tasks only when you add a store. Add both to your turbo.json once.

See the step in the upgrade guide →

On this page