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.
20.* || >=22.14.0In 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
@vue-storefront/nextThe 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.
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.
Your Nuxt storefront moves to Nuxt 4
@vue-storefront/nuxtThe 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.
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.
Tailwind 4 replaces tailwind.config.ts with a CSS entry point
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.
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.
The middleware app is now ESM
@alokai/connect@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.
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.
Every middleware error is now a normalized HttpError
@alokai/connectEvery 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.
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.
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.
What changedWhy, and what changed ▸
@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", 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/connectchanged 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.
What changedWhy, and what changed ▸
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 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/connectadded 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 changedWhy, and what 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/connectadded defineIntegrationExtension types a custom extension end to end
A custom extension you write with it is typed without hand-written generics.
What changedWhy, and what 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/connectadded 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 changedWhy, and what 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/connectchanged 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.
What changedWhy, and what changed ▸
The headers value is now awaited, so its type has to say it's async.
The headers value inside defaultRequestConfig is read as an async function. A synchronous one no longer typechecks against middlewareModule.
@alokai/connectfixed InferCustom falls back to Record<string, unknown>
A $custom value you had to cast before may now index directly.
What changedWhy, and what changed ▸
The InferCustom type alias falls back to Record<string, unknown> instead of object.
@alokai/connectfixed CONFIG type inference resolves workflow ids again
TypeScript checks the workflow ids you index by again.
What changedWhy, and what 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/connectchanged The dev-mode logger prints one formatted line per entry
Your development terminal shows readable lines instead of JSON objects.
What changedWhy, and what 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/connectfixed 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 changedWhy, and what 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/connectchanged 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 changedWhy, and what 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-apichanged 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.
What changedWhy, and what changed ▸
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.
@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/instrumentationchanged 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 changedWhy, and what changed ▸
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 it, the other an argument with it.
@alokai/connectchanged 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.
What changedWhy, and what changed ▸
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">. 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/connectStorefrontAction 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.
What changedWhy, and what changed ▸
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 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/nextchanged 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.
What changedWhy, and what changed ▸
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.
@vue-storefront/nuxtchanged 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.
What changedWhy, and what changed ▸
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 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.
What changedWhy, and what changed ▸
Your storefront read runtime environment variables through a third-party package. Alokai now ships that function itself, so your imports have to change.
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/nextchanged @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 changedWhy, and what 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-modulechanged 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 changedWhy, and what 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.
What changedWhy, and what changed ▸
The shipped request-handling file turns off the X-Frame-Options header for the value most projects set.
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 changedWhy, and what 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-configfixed @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.
What changedWhy, and what changed ▸
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.
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/nuxtfixed 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.
What changedWhy, and what changed ▸
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.
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.
What changedWhy, and what changed ▸
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.
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 changedWhy, and what 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 changedWhy, and what 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 changedWhy, and what 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 changedWhy, and what 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 changedWhy, and what 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-senderadded The CLI detects and uses your project's package manager
If you adopt the new middleware manifest, your project needs @antfu/ni available.
What changedWhy, and what 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/clifixed 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 changedWhy, and what 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/cliadded 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 changedWhy, and what 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-cliremoved 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.
What changedWhy, and what changed ▸
Two visitors did the same job: the first-argument visitor is the Nth-argument visitor at position: 0.
@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-modifierchanged module-kit derives its paths from store.sourcePath
A module installs correctly into a project whose apps don't live under /apps.
What changedWhy, and what 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-kitchanged 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 changedWhy, and what 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-extensionfixed 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 changedWhy, and what 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 changedWhy, and what 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 changedWhy, and what changed ▸
A generated project no longer declares @vsf-enterprise/unified-api-mocks. This release no longer builds the package.
@vsf-enterprise/unified-api-mocksfixed 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.
What changedWhy, and what changed ▸
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.
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/cliCompassAction 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.
What changedWhy, and what changed ▸
The client-side API was split across two export paths, @alokai/compass/next and @alokai/compass/client.
@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/compasschanged compass tool generate writes one file per schema
If you import a generated schema by its file path, that path changes.
What changedWhy, and what 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-compassSAP 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.
What changedWhy, and what changed ▸
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.
@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-apifixed 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 changedWhy, and what 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-apiadded 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.
What changedWhy, and what changed ▸
The SAP-ASM module took its types from the webservices SDK, not from the types package the rest of the integration uses.
@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-typeschanged unified-api-sapcc and the SAPCC SDKs move
These are versions to match. There's no API change to port.
What changedWhy, and what 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-sdkcommercetoolsAction 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.
What changedWhy, and what changed ▸
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.
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-apichanged unified-api-commercetools reads GraphQL errors off error.data
The unified methods follow the new commercetools error shape on their own.
What changedWhy, and what 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-typeschanged The Stripe packages carry only the workspace-wide changes
Their behavior doesn't change, so the upgrade is only a version bump.
What changedWhy, and what 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-sdkMagento 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.
What changedWhy, and what changed ▸
Magento returned its GraphQL errors in an HTTP 200 response, as commercetools did, so a catch block never saw them.
@vsf-enterprise/magento-api 9.0.0 normalizes every GraphQL error to HttpError and throws it.
@vsf-enterprise/magento-apifixed 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 changedWhy, and what 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-typesBigCommerceAction 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.
What changedWhy, and what changed ▸
The BigCommerce v2 and v3 clients threw their own error types, so a catch block written for them matched no other integration.
@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-apifixed bigcommerce-types exports ProductPreOrder as a type
The ESM runtime error from ProductPreOrder is gone with the package version.
What changedWhy, and what 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-bigcommerceSalesforce 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 changedWhy, and what 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-sfccElastic 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.
What changedWhy, and what changed ▸
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.
@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-apiContentfulAction 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.
What changedWhy, and what changed ▸
Contentful's SDK threw its own NotFoundError beside bare axios errors, so a catch block had to match both.
@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-sdkContentstackAction 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.
What changedWhy, and what changed ▸
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.
@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-apifixed 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.
What changedWhy, and what changed ▸
The SDK's live preview initialization had a bug, and Visual Builder had no helper for inline editing.
@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-utilsfixed 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 changedWhy, and what 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-sdkStoryblokAction 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.
What changedWhy, and what changed ▸
The Storyblok client threw its own error types, so a catch block written for it matched no other integration.
@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-sdkAmplienceAction 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.
What changedWhy, and what changed ▸
Amplience threw its own ContentNotFoundError beside unwrapped axios errors, so a catch block had to match both.
@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-sdkBuilder.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.
What changedWhy, and what changed ▸
Builder.io network and fetch failures arrived without a status code of their own, so a catch block had nothing to branch on.
@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-sdkBloomreach 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.
What changedWhy, and what changed ▸
The Bloomreach Content client threw its own error types, so a catch block written for it matched no other integration.
@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-managerSanityAction 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.
What changedWhy, and what changed ▸
The Sanity client threw two error classes of its own, so a catch block had to match both.
@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-sdkSmartEdit1 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 changedWhy, and what 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-apiAlgoliaAction 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.
What changedWhy, and what changed ▸
The Algolia client threw its own error types, so a catch block written for it matched no other integration.
@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-apiBloomreach 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.
What changedWhy, and what changed ▸
Bloomreach publishes its Discovery API as a REST API with OpenAPI specs, and the integration used GraphQL instead.
@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-sdkConstructor.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.
What changedWhy, and what changed ▸
The Constructor.io client threw its own error types, so a catch block written for it matched no other integration.
@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-apiCoveoAction needed1 change
removed Coveo replaces WhitelistException with HttpError Action needed
A catch block that matches WhitelistException or HttpException no longer matches. Match HttpError instead.
What changedWhy, and what changed ▸
The Coveo integration threw its own WhitelistException, so a catch block written for it matched no other integration.
@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-apiCI / 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 changedWhy, and what 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
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.
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.
The CMS 404 fix makes a CMS outage break your category and product pages
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.
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.
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
@storefront-ui/nuxtAt 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.
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.
defineIntegrationExtension accepts an extension with no extendApiMethods at all
@alokai/connectAn 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.
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
@alokai/connectThe 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'.
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.
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
@alokai/cliOn 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.
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.