github vendurehq/vendure v3.8.2

53 minutes ago

Vendure v3.8.2 is a patch release containing a batch of core, dashboard, CLI, @vendure/create and plugin fixes, including a fix for Dashboard extension pages which broke after a redeploy.

If you use RedisCachePlugin, cancel Orders from the ArrangingAdditionalPayment state, serve resized SVG assets, or script vendure auth status or @vendure/create, read Behaviour Changes.

Core

  • Recalculating an unchanged Order gives the same totals every time when an item-level Promotion depends on an order total condition such as minimum_order_amount (#5663, closes #5605). Before, the result could alternate between two values.
  • updatePromotion checks that each action has its required condition, as createPromotion does (#5676, closes #5675). Before, an update could leave buy_x_get_y_free without its condition, and order price calculation then threw Cannot read properties of undefined (reading 'freeItemsPerLine').
  • An Order in ArrangingAdditionalPayment can only move to Cancelled once all of its lines are cancelled, as from every other state (#5672, closes #5671). Before, the check was skipped and allocated stock was not released.
  • The default search index includes every variant passed to updateVariantsById and updateVariants, not only the first 50 (#5674, closes #5673). This showed when a Collection gained more than 50 variants at once: search({ collectionId }) returned 50 of them.
  • A Customer cannot change their email address to one which belongs to another Customer, including a guest Customer with no User (#5680, relates to #5640). The request returns EmailAddressConflictError. Before, two Customers could end up with the same address.
  • authenticate returns InvalidCredentialsError for an empty input or a strategy with null data, instead of an internal error with no error code (#5622, closes #5621).
  • createAssets with translations and no custom fields returns the translated Asset (#5713). Before, selecting name failed with "Cannot return null for non-nullable field Asset.name".
  • Blocking event handlers:
    • A circular dependency between three or more handlers is reported with a Circular dependency detected error which names the handlers, instead of RangeError: Maximum call stack size exceeded (#5632, closes #5630). A handler whose registration was rejected no longer stays registered.
    • Two handlers which declare the same constraint from both sides (A is after B, and B is before A) are ordered instead of throwing a RangeError (#5665, closes #5664).
  • RedisCacheStrategy removes expired entries from its tag sets and gives each tag set an expiry, so tag sets no longer grow without limit (#5683, closes #5682). The session cache tag gained one member per session. invalidateTags now works in batches of 1000 and throws on a command error instead of ignoring it.
  • The polling job queue waits for a job which is being claimed before it stops (#5565, relates to #4949). Before, the application could close while the job was already marked RUNNING, and nothing settled it afterwards.
  • A migration no longer de-duplicates translations in a table which the same migration creates, and logs de-duplication only when it removes rows (#5702). New projects no longer log "The … table does not exist. Skipping de-duplication." for every translation table.

Dashboard

  • Every build gives its JavaScript chunks new file names (#5772, closes #5564). Before, an extension chunk could keep its file name while the entry chunk it imports got a new one. Because /assets is cached as immutable, the browser then ran the old chunk, and extension pages showed "Not Found" or failed with Cannot read properties of null (reading 'useContext') after a redeploy.
  • After logging out and signing in as another user, the Dashboard loads that user's settings (#5669). Before, the new user saw the previous user's settings, and their active Channel was saved into the new user's settings.
  • Dashboard widgets keep the position given in defaultSize.x and defaultSize.y when the user has no saved layout and the position is free (#5658, closes #5616). The built-in widgets have new default positions.
  • Expanded child Collections reload in the new language when you switch the content language (#5706, closes #5704).
  • Changing a line's quantity in Modify order and on the draft order page works when the OrderLine has a relation custom field (#5697, closes #5696). The field was sent by its output name, which the API rejects.
  • The asset picker's select button, the upload toasts and the move Collections dialog use proper plurals in every locale (#5590, relates to #5482).
  • In useExperimentalBundle mode, styles match source mode (#5709). Before, selects could render too narrow and some @vendure-io/ui classes, such as the breadcrumb separator, were missing.

CLI and @vendure/create

  • vendure console link has a new --console-project <id|slug> option which selects the Console Project without the picker (#5685). With --non-interactive it creates the Project Link from the login stored by vendure auth login.
  • vendure auth login and vendure auth status check that the stored login can still be renewed (#5689). Before, a login which could no longer be renewed was reported as valid.
  • vendure console link says when the stored login has expired or was revoked, instead of "No CLI login … is stored on this machine" (#5710).
  • The unknown-command hint names an inactive CLI plugin only when that plugin declares the command, and treats a plugin enabled for the project as active (#5692).
  • @vendure/create no longer hangs when the Docker daemon does not answer (#5693). The daemon check gives up after 10 seconds and docker compose up after 5 minutes.
  • @vendure/create exits with code 1 when it cannot copy the email templates (#5694). Before, it stopped with exit code 0.

Plugins

  • Asset Server Plugin: a resized .svg asset with no format parameter is served as image/png, which is what the response body contains (#5255). Before, it was labelled image/svg+xml, and since 3.7.3 the browser downloaded it instead of displaying it.
  • GraphiQL Plugin: the GraphiQL page sends requests to the server which served it (#5686). Before, a server with apiOptions.hostname set, for example 0.0.0.0 in Docker, sent the page an address the browser could not reach. A custom route now works too.
  • Job Queue Plugin: BullMQJobQueueStrategy waits for its Redis connection to be ready before it subscribes to job cancellations (#5631, closes #5627). Before, the subscription could be lost during startup, and cancelling a running job did nothing.
  • MCP Plugin:
    • adjust_stock locks the stock levels it reads, so concurrent calls no longer overwrite each other (#5653, closes #5652).
    • upload_asset publishes an AssetEvent of type created, as the createAssets mutation does (#5662, closes #5661).
    • An OAuth bearer token resolves on PostgreSQL with UuidIdStrategy (#5705, closes #5701). Before, it failed with operator does not exist: uuid = character varying. Sessions created for MCP clients also record the caller's API type.
    • The Dashboard navigation titles of the plugin are translated, and no longer log "Uncompiled message detected!" (#5660, closes #5641).
  • MCP SDK: idSchema converts an id sent as a string of digits, such as "9", to a number when the id strategy is auto-increment (#5647, closes #5626). Before, adjust_stock, update_variant, update_product and update_customer failed with a database error.

Behaviour Changes

No APIs are removed or renamed.

Redis cache tags. RedisCacheStrategy stores tags in sorted sets under a new key name, <namespace>:ztag:<tag>. The old <namespace>:tag:<tag> sets get no new members, and invalidateTags still empties them. During a rolling deploy, an invalidation on an instance still on the old version does not clear entries tagged by upgraded instances. Those entries expire with their TTL. Tagged writes use EVAL, so a Redis ACL user needs the @scripting permission. The documented minimum is Redis 3.2, or a compatible server such as Valkey.

Cancelling from ArrangingAdditionalPayment. The transition to Cancelled now fails unless every line of the Order is cancelled.

Updating a Promotion. updatePromotion returns the same error as createPromotion when an action's required condition is missing. The check runs only when the update sends conditions or actions, so a Promotion already saved without its condition can still be disabled or renamed.

Resized SVG assets. These are cached under a .png file name and served as image/png.

GraphiQL Plugin. The page no longer uses apiOptions.hostname to build its request URLs.

Dashboard build output. JavaScript file names in the build output change with every build, even when the source is unchanged. Set disablePlugins.chunkHash in the Vite plugin options to turn this off.

CLI exit codes and output. vendure auth status exits with 1 when the stored login cannot be renewed, and its --json output has two new fields, renewable and renewalError. @vendure/create exits with 1 when the email templates cannot be copied or the Docker daemon does not answer.

Migration

No database migrations are required. Upgrade all @vendure/* packages together to 3.8.2.

What's Changed

New Contributors

Full Changelog: v3.8.1...v3.8.2

Don't miss a new vendure release

NewReleases is sending notifications on new releases.