Alokai

2.1

opt-in method-level circuit breakers, and a metrics gauge that had been reporting open breakers as closed

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

Minorlatest 2.1.3 · 23 Mar 2026Node 20.* || >=22.14.0

Most of this line lands in files your project owns, so the upgrade command doesn't deliver it and you apply it by hand. In 2.1.0 you can scope a circuit breaker to a single API method, and the middleware_circuit_breaker_state gauge no longer reports a tripped breaker as healthy. 2.1.2 carries a security fix that restores the X-Frame-Options header in Next.js storefronts generated at 2.0.0 through 2.1.1, alongside a Cloudinary guard and a typing fix. 2.1.3 republishes the type declarations of the five unified-api packages, which had silently degraded to any in your project.

Two things to know before you start. 2.1.0, 2.1.1, and 2.1.2 pin the same four core package versions, so version upgrade can't tell them apart and will offer to move you past a release you haven't applied. @alokai/compass jumps to 3.0.0 and requires @alokai/connect at exactly 2.1.0 as a peer, so the two have to move together. The upgrade guide linked below collects every step for the line.

Highlights

Give a failing endpoint its own circuit breaker instead of tripping the whole integration

OptionalAlokai Connect@alokai/connect
Why:

One slow endpoint could trip the circuit breaker for its whole integration and take every other method on that platform down with it.

An integration's circuitBreaker config accepts granularity: 'method'. It keys each breaker by API method, such as commerce/getProduct (or commerce/unified/getProduct when an extension handles the call), instead of by integration (commerce). The default stays 'integration' and produces the same key as before, so nothing changes until you set it. A methods: string[] sibling narrows it further: only the listed methods get their own breaker, and every other method keeps sharing the integration-level one.

You can override both without touching code, and an environment variable wins over the value in config.ts. CB_GRANULARITY and CB_METHODS apply to every integration, and CB_<INTEGRATION>_GRANULARITY and CB_<INTEGRATION>_METHODS apply to one integration and win over the global ones. Write the integration name in uppercase, with - replaced by _. An unrecognized value logs a warning and falls back instead of throwing.

For you:

If one slow endpoint on your commerce platform has been taking your whole catalog offline, this setting stops it. Add granularity: 'method' beside the preset in apps/storefront-middleware/integrations/<your integration>/config.ts. A generated project ships that file with no circuitBreaker block, and the breaker runs on the BALANCED preset whether you configured it or not, so if the block is missing, add all of it:

circuitBreaker: {
  preset: 'BALANCED',
  granularity: 'method',
},

Each method's breaker lives for the lifetime of the process, so an integration with twenty methods holds twenty breaker instances instead of one. The middleware reads the environment variables once, on the first request that reaches each integration, and caches them for the life of the process. Changing one at runtime does nothing until you restart the middleware. If you read circuitBreakerRegistry directly, opting in changes the shape of its keys.

Your circuit breaker state gauge stopped reporting an open breaker as closed

Action neededAlokai Connect@alokai/connect
Why:

middleware_circuit_breaker_state reported an open breaker as closed, so nothing reading the metric could tell a tripped breaker from a healthy one.

The middleware always registers the middleware_circuit_breaker_state gauge and exposes it on GET /alokai-metrics, labeled by integration. Its documented values are 1=closed, 0.5=half-open, 0=open. The gauge now reports 0 while a breaker is open. When an integration has more than one breaker, it reports the most degraded state among them.

On @alokai/connect 2.0.1 - the package version, not an ecosystem release - an open breaker set the gauge to 1, the same value as a closed one. The gauge could only ever read 1 or 0.5 and never reached 0.

For you:

This reaches you with the upgrade whether or not you touch the circuitBreaker config, because every project's middleware registers the metric. If you alert on or chart middleware_circuit_breaker_state, an alert on == 0 couldn't fire on @alokai/connect 2.0.1 and now can. An alert built to work around the gap, such as one that watches for 0.5 as the only failure signal, is now incomplete.

The upgrade can't repair your history. Every data point your scraper stored before the upgrade reports 1 for periods when a breaker was open, so a postmortem or an alert threshold derived from that window reads a value that was never true. Nothing in your project can rewrite it.

See the step in the upgrade guide →

All changes by area

Every change in 2.1 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 2.0.3 to 2.1.3 collects the migration steps for the whole line.

Alokai ConnectAction needed3 changes

added Give a failing endpoint its own circuit breaker instead of tripping the whole integration highlight

To stop one slow endpoint from taking its whole integration down, add granularity: 'method' beside the preset in your integration's config.ts. If the file has no circuitBreaker block, which is how a generated project ships it, add the whole block. Each method's breaker lives for the lifetime of the process, and the middleware reads the environment variables once per integration and caches them, so a runtime change needs a restart.

What changed ▸
Why

One slow endpoint could trip the circuit breaker for its whole integration and take every other method on that platform down with it.

Changed

An integration's circuitBreaker config accepts granularity: 'method', which keys each breaker by API method instead of by integration. A methods: string[] sibling narrows it to the listed methods. The default is unchanged, so nothing changes until you set it. CB_GRANULARITY / CB_METHODS and their per-integration variants override both without a code change.

@alokai/connect

fixed Your circuit breaker state gauge stopped reporting an open breaker as closed highlight Action needed

This reaches you with the upgrade whether or not you configure a breaker, because every middleware registers middleware_circuit_breaker_state. An alert on == 0 couldn't fire before and now can, and one built to work around the gap is now incomplete. The upgrade can't repair your history: every point stored before it reports 1 for periods when a breaker was open.

step →
What changed ▸
Why

middleware_circuit_breaker_state reported an open breaker as closed, so nothing reading the metric could tell a tripped breaker from a healthy one.

Changed

The gauge now reports 0 while a breaker is open. When an integration has more than one breaker, it reports the most degraded state among them. On @alokai/connect 2.0.1 it could only ever read 1 or 0.5.

@alokai/connect

fixed The unified API packages' type declarations resolve in your project again Action needed 2.1.3

Bump your platform's package in apps/storefront-middleware/package.json - the upgrade command doesn't move it. Nothing else in your code changes. If you wrote or extended middleware methods while the type was any, your first typecheck after the bump shows anything it was hiding.

What changed ▸
Why

At the versions you're on, createUnifiedExtension's parameters and the extendApiMethods object it returns aren't type-checked. The published declarations import a type from a package that isn't on npm, and the generated apps' skipLibCheck: true hides the error, so the type silently becomes any.

Changed

The declarations no longer import from an unpublished package, so they resolve in your project. Each package adds a "./dist/*" subpath export, which the declarations use to reach each other.

@vsf-enterprise/unified-api-sapcc@vsf-enterprise/unified-api-magento@vsf-enterprise/unified-api-commercetools@vsf-enterprise/unified-api-bigcommerce@vsf-enterprise/unified-api-sfcc
StorefrontAction needed4 changes

fixed The Nuxt browser build gets an implementation of Node's util highlight Action needed 2.1.1

nuxt.config.ts belongs to your project, so no version bump delivers this - you add the alias to the file yourself. The problem isn't new in 2.1.1: @alokai/connect has imported util since well before 2.1.0, so a Nuxt storefront already carries it.

step →
What changed ▸
Why

The Nuxt browser build has no implementation of Node's util, yet the logger it bundles imports inspect from util and calls it on a code path meant for the browser.

Changed

apps/storefront-unified-nuxt/nuxt.config.ts gains a vite.resolve.alias entry that maps util to unenv/node/util. Nuxt aliases Node builtins for the client only under experimental.clientNodeCompat, which is off by default and isn't enabled anywhere in the storefront. unenv is already in your tree as a Nuxt dependency, so you don't add it.

security The X-Frame-Options header is sent again by default highlight Action needed 2.1.2

proxy.ts is yours, so check it before you edit it. A project generated at 2.0.0 through 2.1.1 has been served without the header, while one that upgraded into 2.0.0 most likely still has !== 'true' and was never exposed - a blind edit there would take the header off. If you run CMS live preview, the step tells you to set NEXT_PUBLIC_DISABLE_X_FRAME_OPTIONS_HEADER to true.

step →
What changed ▸
Why

A vulnerability in what the shipped storefront proxy sends has been identified and fixed. Whether your own proxy.ts has it depends on how your project reached this release.

Changed

In apps/storefront-unified-nextjs/proxy.ts, the guard on the X-Frame-Options: DENY header changes from env('NEXT_PUBLIC_DISABLE_X_FRAME_OPTIONS_HEADER') !== 'false' to !== 'true'. The shipped .env.example sets that variable to false, so the old condition dropped the header from every response. true is now the only value that turns the header off. New projects also get a comment on the variable in .env.example.

fixed Cloudinary images with paths over 255 characters render again highlight Action needed 2.1.2

Cloudinary images with source paths over 255 characters render unoptimized at full size instead of not at all, and a warning through @/sdk/logger names each offending src. The loader file is yours, and the upgrade doesn't rewrite it.

step →
What changed ▸
Why

If you use the Cloudinary image loader, any image with a source path over 255 characters came back as a 400 and rendered nothing. Cloudinary caps public_id at 255 characters.

Changed

apps/storefront-unified-nextjs/config/image-loaders/cloudinary/cloudinary.ts gains a guard. When src.length > 255, the loader logs a warning and returns src unchanged instead of building an upload URL. The public_id is also the address Cloudinary fetches the original image from, so it can't be hashed or truncated.

fixed getTypedApiClient accepts a second integration's context highlight Action needed 2.1.2

Calling getTypedApiClient(context, 'commerce') from a second integration's method, such as a SmartEdit or CMS method, now compiles. You have this helper only if your project was generated at 1.4.0 or later, or you added it by hand from 1.4.0's optional migration guide. The upgrade doesn't create it or edit it.

step →
What changed ▸
Why

The helper typed its context parameter against the commerce integration's own context. So a call from any other integration's method failed typecheck, with nothing wrong behind it.

Changed

In apps/storefront-middleware/integrations/typedApiClient.ts, context is typed with the base IntegrationContext from @alokai/connect/middleware instead of the one from @/types. Every integration context extends the base type. Two import lines change and nothing else.

CLI & toolingAction needed1 change

fixed integration generate no longer stops to ask which package manager you use highlight Action needed 2.1.3

The prompt fix arrives with the version bump and needs nothing from you. The @antfu/ni declaration doesn't: no upgrade rewrites your root package.json, so it's yours to add. On a yarn workspace nothing is broken today - @alokai/cli declares @antfu/ni itself and yarn hoists it - so the declaration stops the resolution from depending on hoisting. The Command "ni" not found failure comes from a separate check this release doesn't touch. If you've seen it, adding the declaration is the repair.

step →
What changed ▸
Why

When a command ran ni in a directory with no lockfile, ni stopped at an interactive prompt asking which package manager you use. integration generate hit it, because it scaffolds in a temporary directory, and a non-interactive run can't answer the prompt.

Changed

@alokai/cli 2.4.2 detects your package manager from the project root and passes it to every command it runs through ni, so the prompt can't appear. A project generated at 2.1.3 also declares "@antfu/ni": "^28.0.0" in the root package.json devDependencies, not only through @alokai/cli's own dependencies.

@alokai/cli
SAP Commerce Cloud1 change

deprecated Token refresh gains a factory form, and the option it replaces is deprecated 2.1.1

A custom refresh endpoint can now go through the SDK's own httpClient, which wasn't reachable at module-configuration time. Nothing breaks on the upgrade - the deprecated option is still read and still wins over the SDK's default - so you can move to the factory form on your own schedule.

step →
What changed ▸
Changed

sapccModule accepts refreshToken.refreshTokenMethodFactory. The SDK calls it at request time with its own httpClient, the resolved baseUrl, and the computed config of the failed request, and it returns the refresh function. refreshToken.refreshTokenMethod still works but is deprecated, and the package says it'll be removed in the next major release, dated Q3 2026.

@vsf-enterprise/sapcc-sdk
Bloomreach DiscoveryAction needed5 changes

added The Bloomreach Discovery unified search extension ships out of the box 2.1.2

You no longer write the unified search extension yourself to use Bloomreach Discovery for unified search. The module is opt-in, and nothing changes in a project that doesn't adopt it.

What changed ▸
Changed

The search-bloomreach module configures searchProducts and getProductDetails with defaults for Bloomreach Discovery. @vsf-enterprise/bloomreach-discovery-api also exports createUnifiedExtension, so you can wire the extension by hand - see the Unified Search Extension guide.

@vsf-enterprise/bloomreach-discovery-api

changed Four common Bloomreach request parameters are resolved for every call 2.1.2

A value you pass in a call still overrides the resolved one. You can't turn the resolution off.

What changed ▸
Changed

The integration fills in four parameters on every API call. brUid2 comes from the _br_uid_2 cookie, url from the request headers, and refUrl from Referer. requestId is a generated 13-digit number.

@vsf-enterprise/bloomreach-discovery-api

added A new environment option switches every Bloomreach host to staging 2.1.2

You can point a staging environment at Bloomreach staging with one option. A single basePath URL can only be right for one host and wrong for the other three.

What changed ▸
Changed

The new environment option takes "production" | "staging". With "staging", every Bloomreach host - core, suggest, pathways, and pathways-email - switches to its staging- equivalent.

@vsf-enterprise/bloomreach-discovery-api

deprecated basePath is deprecated, and setting it alongside environment throws on start Action needed 2.1.2

If you add environment to a config that sets basePath, remove basePath in the same edit. With both set, your middleware doesn't start.

step →
What changed ▸
Why

One basePath applies to all four Bloomreach hosts, so pointing it at staging fixed search but broke autosuggest, email widgets, and recommendations.

Changed

basePath still works on its own and logs a deprecation warning on start. If you set both basePath and environment, the middleware throws on start instead of picking one.

@vsf-enterprise/bloomreach-discovery-api

changed The search-bloomreach module source was restructured 2.1.2

If you already adopted the module, nothing rewrites your copy under sf-modules/search-bloomreach/. It keeps working against 7.1.0 with the deprecated basePath. The restructure shows only in the module source.

What changed ▸
Changed

In the search-bloomreach module, extensions/unified/index.ts and extensions/index.ts are gone, and the extension is inlined in config.ts. middleware/index.ts re-exports the unified exports of @vsf-enterprise/bloomreach-discovery-api. The module reads BLOOMREACH_DISCOVERY_ENVIRONMENT instead of BLOOMREACH_DISCOVERY_BASE_PATH.

Patches in 2.1.x

2.1.3

23 Mar 2026 · Patch · 8 of 78 packages moved

A CLI fix and a type fix. Commands that run ni - integration generate above all - no longer stop at an interactive package-manager prompt in a directory with no lockfile, and a newly generated project declares @antfu/ni itself. All five unified-api packages republished their type declarations, which silently became any in your project. Only one of the four core packages moved, so the upgrade command has real work to do and names this release correctly. You move everything else below by hand.

integration generate no longer stops to ask which package manager you use

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

When a command ran ni in a directory with no lockfile, ni stopped at an interactive prompt asking which package manager you use. integration generate hit it, because it scaffolds in a temporary directory, and a non-interactive run can't answer the prompt.

@alokai/cli 2.4.2 detects your package manager from the project root and passes it to every command it runs through ni, so the prompt can't appear.

A project generated at 2.1.3 also declares "@antfu/ni": "^28.0.0" in the root package.json devDependencies. The binary is then a dependency your project declares, not one it inherits from @alokai/cli's own dependency tree.

For you:

The prompt fix arrives with the version bump and needs nothing from you. The @antfu/ni declaration doesn't: no upgrade rewrites your root package.json, so your project has no @antfu/ni line unless you add it.

On a yarn workspace nothing is broken today. @alokai/cli declares @antfu/ni itself, yarn hoists it, and node_modules/.bin/ni is already there at 28.3.0. Declaring it yourself stops the resolution from depending on hoisting. Add it with a pinned range rather than a bare yarn add.

The CLI fix doesn't touch the Command "ni" not found failure, which comes from a separate check. If you've seen that error, adding the declaration is the repair.

See the step in the upgrade guide →

2.1.2

19 Mar 2026 · Patch · 3 of 78 packages moved

A security fix restores the X-Frame-Options header in Next.js storefronts generated at 2.0.0 through 2.1.1, alongside a Cloudinary image fix and a typing fix for getTypedApiClient. All three land in files your project owns, so the version bump doesn't deliver them - you apply the ones your project needs by hand. On the packages side only Bloomreach Discovery changed. None of the four core packages moved, so the upgrade command can't tell 2.1.2 apart from 2.1.1 and will offer to move you past this release.

The X-Frame-Options header is sent again by default

Action neededStorefront2.1.2
Why:

A vulnerability in what the shipped storefront proxy sends has been identified and fixed. Whether your own proxy.ts has it depends on how your project reached this release.

In apps/storefront-unified-nextjs/proxy.ts, the guard on the X-Frame-Options: DENY header changes from env('NEXT_PUBLIC_DISABLE_X_FRAME_OPTIONS_HEADER') !== 'false' to !== 'true'. The shipped .env.example has always set NEXT_PUBLIC_DISABLE_X_FRAME_OPTIONS_HEADER=false, so the old condition dropped the header from every response. true is now the only value that turns the header off.

The shipped .env.example also gets a comment that explains the variable, and its value stays false. The comment reaches new projects only, because .env.example is yours. Nothing asks you to add it.

For you:

proxy.ts is yours, so what it holds depends on how you got to 2.1.1. A project generated at 2.0.0, 2.0.1, 2.0.2, 2.0.3, 2.1.0 or 2.1.1 received the inverted condition and has been served without the header since. A project that upgraded into 2.0.0 most likely still has the !== 'true' it has had since 1.2.2 and was never exposed. No Alokai release asked you to adopt the shipped proxy.ts, and the Next.js 16 middleware.ts rename carries your contents across.

A blind edit would take the header off rather than restore it, so the step starts with a check on your own file. If you run CMS live preview - SmartEdit, Contentful - the same step tells you to set the variable to true.

See the step in the upgrade guide →

Cloudinary images with paths over 255 characters render again

Action neededStorefront2.1.2
Why:

If you use the Cloudinary image loader, any image with a source path over 255 characters came back as a 400 and rendered nothing. Cloudinary caps public_id at 255 characters.

apps/storefront-unified-nextjs/config/image-loaders/cloudinary/cloudinary.ts gains a guard. When src.length > 255, the loader logs a warning and returns src unchanged instead of building an upload URL. The public_id is also the address Cloudinary fetches the original image from, so it can't be hashed or truncated.

For you:

If you use the Cloudinary image loader, images whose source path is over 255 characters now render unoptimized, at full size, instead of not at all. A warning names each offending src through the storefront's logger from @/sdk/logger, which the file already imports. The loader file is yours, and the upgrade doesn't rewrite it.

See the step in the upgrade guide →

getTypedApiClient accepts a second integration's context

Action neededStorefront2.1.2
Why:

The helper typed its context parameter against the commerce integration's own context. So a call from any other integration's method failed typecheck, with nothing wrong behind it.

In apps/storefront-middleware/integrations/typedApiClient.ts, context is typed with the base IntegrationContext from @alokai/connect/middleware instead of the one from @/types. The one from @/types is the commerce integration's own context type. Every integration context extends the base type. Two import lines change and nothing else.

For you:

Calling getTypedApiClient(context, 'commerce') from a second integration's method, such as a SmartEdit or CMS method, now compiles. You have this helper only if your project was generated at 1.4.0 or later, or you added it by hand from 1.4.0's optional migration guide. The upgrade doesn't create it or edit it.

See the step in the upgrade guide →

2.1.1

11 Mar 2026 · Patch · 3 of 78 packages moved

Two changes and two version-only bumps. If you have a Nuxt storefront, add a vite.resolve.alias entry to nuxt.config.ts that gives the browser build an implementation of Node's util. The file is yours, so the upgrade doesn't touch it. On SAP Commerce Cloud, sapccModule gains refreshTokenMethodFactory and deprecates refreshToken.refreshTokenMethod. None of the four packages that version upgrade moves changed in this release, so the command can't tell 2.1.1 apart from 2.1.0 or 2.1.2.

The Nuxt browser build gets an implementation of Node's util

Action neededStorefront2.1.1
Why:

The Nuxt browser build has no implementation of Node's util, yet the logger it bundles imports inspect from util and calls it on a code path meant for the browser.

apps/storefront-unified-nuxt/nuxt.config.ts gains a vite.resolve.alias entry that maps util to unenv/node/util. The browser bundle needs it because @vue-storefront/nuxt generates .nuxt/logger.ts, which imports @alokai/connect/logger, and that logger calls inspect from util in the browser.

Nuxt 4.3.0 aliases Node builtins for the client only when experimental.clientNodeCompat is on. It defaults to false and the storefront doesn't enable it, so without this entry nothing supplies util to the browser build. unenv is already in your tree as a Nuxt dependency, so you don't add it.

For you:

nuxt.config.ts belongs to your project, so no version bump delivers this - you add the alias to the file yourself. The problem isn't new in 2.1.1: @alokai/connect has imported util since well before 2.1.0, so if you have the Nuxt storefront, it already has the problem.

See the step in the upgrade guide →

On this page