Vendure v3.8.1 is a patch release containing fixes for three reported vulnerabilities (one high, two low), along with a batch of core, dashboard, job queue and @vendure/create fixes.
If you read job data through the Admin API, or you parse server logs or GraphQL error responses, read Behaviour Changes.
Security
Fixes for the following reported vulnerabilities are in 3.8.1. If you are on an earlier version, upgrade.
| Severity | Vulnerability | Advisory |
|---|---|---|
| High | Credentials in Admin API job data: the job, jobs and jobsById queries returned job data as it was stored, including email verification, password-reset and email-change tokens and other credential-like values. The telemetry plugin recorded the same data in the job.data span attribute
| GHSA-hxvp-ff3g-qcj7 |
| Low | Stack traces in GraphQL error responses: when NODE_ENV was not production, requests rejected before GraphQL execution got an error response with a stack trace, which exposed server file paths
| GHSA-qmrg-wpxj-c482 |
| Low | GraphiQL plugin asset paths: the asset server answered differently for existing and missing files outside its assets directory, so it showed whether a file existed on the server | GHSA-fw8w-3xpv-rg9p |
The advisory for GHSA-hxvp-ff3g-qcj7 lists what to do after upgrading. Our thanks to the researchers who reported these responsibly.
Core
- Updating the Assets of a Product, ProductVariant or Collection no longer removes its Assets in other Channels, or clears a featured Asset which belongs to another Channel (#5639, closes #5629).
- Channels are looked up by token and cached per token, instead of loading and refreshing every Channel in every process (#5248, relates to #988). Installs with many Channels use less memory and run smaller queries.
- The inverse sides of many-to-many relations declare their foreign key rules explicitly (#5597, closes #5594). TypeORM 1.1.1 changed the default for these rules, so on TypeORM 1.1.2
runMigrationsreported 21 core junction-table foreign keys as out of sync. The schema does not change. - Only one root Collection is created, in the default Channel. Before, if the first request after a process start came from another Channel, a second root Collection could be created there (#5587, closes #5584).
CollectionService.delete()removes the Collection's variant links inside the request transaction, and unlinks the variants of each descendant from that descendant rather than from the root (#5554, closes #5553).- Order totals are calculated from freshly loaded surcharges, so a surcharge added or removed by a blocking event handler is included (#5370, closes #5332).
assignProductVariantsToChannelalso assigns the variants' ProductOptions and ProductOptionGroups, soProductOption.groupresolves in the target Channel (#5557, closes #5556).- Soft-deleted ProductOptions are skipped when assigning a Product to a Channel (#5493), and are rejected as variant option ids by
createProductVariantsandupdateProductVariants(#5613, closes #5602). - Customers created by external authentication have their email address normalized, like every other way of creating a Customer (#5583, closes #5559).
createFacetValueandcreateFacetValuesno longer load every existing value of the Facet, so creating a value no longer gets slower as the Facet grows (#5506, closes #5497).- Relation custom fields set by their input key (
<name>Idor<name>Ids) no longer log a false "Custom field not found" warning (#5563, closes #5543). - The
validatefunction of list custom fields is typed with itsinjectorandctxarguments (#5578, closes #5575). - No
ERR_HTTP_HEADERS_SENTerror when an authorization guard finishes after the response was sent (#5520, closes #5519). - The Admin API
job,jobsByIdandcancelJoboperations find BullMQ jobs with custom ids (#5577, closes #5558).
Dashboard
- Signing in from the login page, or after a session has expired, no longer overwrites your stored user settings with the defaults (#5644, closes #5595).
- List tables select the fields of every visible column, so a column which is hidden by default, such as SKU in the variants table, shows its values when you turn it on (#5645, closes #5619).
- An Administrator whose roles give access to no Channel gets an error message instead of an endless loading screen (#5620, closes #5617).
- After switching user, the navigation shows the new user's permitted entries without a reload (#5624, closes #5623).
- Extension pages no longer fail with "useChannel must be used within a ChannelProvider" in
useExperimentalBundlemode (#5643). - A relative build
outDiris resolved against your Viteroot, so builds started from another directory, as NX does, land in the right place (#5410, closes #4053). - Messages with counts use proper plurals in every locale (#5483, closes #5482).
- The "Explore Platform & Cloud" user menu entry is renamed "Plans" (#5582).
CLI and @vendure/create
- Projects created with npm 12 allowlist the install scripts of their native dependencies, so
bcrypt,better-sqlite3,esbuildandre2build (#5566). - Scaffolded projects enable EmailPlugin
devModeonly whenAPP_ENVisdev..envis added to.gitignoreand to a new.dockerignore, and the Dockerfile setsNODE_ENV=production(#5498). EmailPlugin logs a warning at startup whendevModeis on andNODE_ENVisproduction. - The scaffolded Dockerfile uses
node:24, as Node.js 20 is end-of-life (#5637). vendure addhas a new first entry, and@vendure/createa new question, for starting a Vendure Platform trial (#5608).vendure add --platformstarts the same flow.@vendure/create, andvendure devin a project which is not linked to Console, print one line pointing to Vendure pricing andvendure console link(#5580).vendure console linksends the telemetry installation id to Console when telemetry is on, so Console can attribute the installation's telemetry to the linked Project (#5581).
Plugins
- Job Queue Plugin:
BullMQJobQueueStrategyuses aRedisorClusterinstance passed asconnection, instead of treating it as options (#5612, closes #5603).- Cancelling a job is scoped to the queue prefix, so instances which share a Redis server with different prefixes no longer cancel each other's jobs (#5524, closes #5518).
BullMQJobQueueStrategy(#5526, closes #5525) andRedisJobBufferStorageStrategy(#5610, closes #5601) close the Redis connections they opened when they are destroyed. A connection you passed in is left open.
- Asset Server Plugin: a newly generated image is sent with the configured
Cache-Controlheader (#5573). - Email Plugin: the raw file transport writes its output without crashing the process running the
send-emailqueue (#5574, closes #5571).
Behaviour Changes
No APIs are removed or renamed.
Job data in the Admin API. Job.data, Job.result and Job.error return a redacted copy. Email template variables and credential values show [redacted], and email attachments show only filename and contentType. The telemetry plugin's job.data span attribute holds only the key names of the job data.
Stack traces. GraphQL error responses never include stack traces, whatever NODE_ENV is set to. The adminApiDebug and shopApiDebug options were already deprecated no-ops in 3.8.0.
Startup output. The server and the worker print a Vendure Platform banner at the end of startup (#5606). In an interactive terminal with the default logger it is a box. Without a TTY, in CI, or with a custom logger such as a JSON logger, it is one Logger.info line on every start.
Migration
No database migrations are required. Upgrade all @vendure/* packages together to 3.8.1.
What's Changed
- chore(repo): normalize repository.url in package manifests by @michaelbromley in #5550
- chore(dev-server): disable the reviews example plugin by default by @michaelbromley in #5549
- test(core): read variant prices from the catalog in the price calculation strategy spec by @michaelbromley in #5551
- docs: rewrite the readme intro for the plans launch by @Itsayaboi in #5480
- docs: add a header row to the readme feature table by @Itsayaboi in #5560
- docs: add secret fields guide to the docs navigation by @michaelbromley in #5561
- fix(core): delete collection variant links inside the request transaction by @brmk in #5554
- fix(dashboard): resolve relative build outDir against the user's vite root (#4053) by @wakqasahmed in #5410
- fix(create): allowlist native dependency install scripts for npm 12 by @michaelbromley in #5566
- chore(repo): include multi-scope and re-applied commits in the changelog by @michaelbromley in #5552
- chore: remove temporary OpenTelemetry minimumReleaseAge exclusions by @michaelbromley in #5567
- fix(core): look up channels by token instead of caching every channel by @rafabernad in #5248
- feat(dashboard): rename the pricing menu entry to Plans by @dlhck in #5582
- feat(create): print one pricing hint after install by @dlhck in #5580
- feat(cli): attribute Core telemetry to the Console Project on console link by @dlhck in #5581
- fix(core,job-queue-plugin): find BullMQ jobs with custom ids in the A… by @Ryrahul in #5577
- fix(core): don't load a facet's existing values when creating a facet value by @AyeshaWaseemAhmad in #5506
- fix(core): skip session header writes after response headers are sent by @allanmongej in #5520
- fix(core): skip soft-deleted options when assigning a product to a channel by @casperiv0 in #5493
- fix(core): type the injector and ctx args of validate on list custom … by @Ryrahul in #5578
- fix(core): accept relation custom field input keys in CustomFieldsValidationSubscriber by @Haridass30 in #5563
- fix(email-plugin): write raw file transport output from the returned buffer by @Haridass30 in #5574
- fix(asset-server-plugin): apply Cache-Control to newly generated images by @Hen2609 in #5573
- fix(dashboard): use ICU plurals for counted messages by @theluckystrike in #5483
- fix(core): normalize the email address of customers created by extern… by @Ryrahul in #5583
- docs: correct how requiresPermission applies in the Shop API by @gabriellbui in #5570
- docs: rename Vendure Core to Vendure Framework by @dlhck in #5593
- test(cli): cover login isolation between config directories by @oliverstreissi in #5591
- docs: rename Vendure Core to Vendure Framework in core concepts title by @dlhck in #5599
- fix(core): assign variant options and option groups in assignProductVariantsToChannel by @Haridass30 in #5557
- fix(job-queue-plugin): close the redis connections the bullmq strategy opens on destroy by @AyeshaWaseemAhmad in #5526
- fix(core): resolve the root collection in the default channel by @Haridass30 in #5587
- fix(core): declare inverse junction FK rules explicitly on many-to-many relations by @michaelbromley in #5597
- feat(cli): add a Vendure Platform trial entry to vendure add and @vendure/create by @dlhck in #5608
- fix(core): reload surcharges before recalculating order totals by @Ismatulla in #5370
- feat(dashboard): add a build-time Platform catalog data layer by @dlhck in #5607
- fix(job-queue-plugin): scope bullmq job cancellation to the queue prefix by @AyeshaWaseemAhmad in #5524
- fix(create): enable email devMode only in development by @HouseinIsProgramming in #5498
- fix(job-queue-plugin): close the redis connection of the job buffer storage strategy on destroy by @AyeshaWaseemAhmad in #5610
- fix(job-queue-plugin): use a Redis or Cluster instance passed as connection by @AyeshaWaseemAhmad in #5612
- fix(dashboard): show the permitted navigation after switching user without a reload by @Ryrahul in #5624
- fix(core): ignore deleted product options when validating variant option ids by @AyeshaWaseemAhmad in #5613
- revert(dashboard): move the Platform catalog data layer to the next minor by @dlhck in #5633
- feat(core): show a Vendure Platform banner after server and worker startup by @dlhck in #5606
- ci: resolve back-merge conflicts in the generated docs manifest automatically by @dlhck in #5636
- fix(create): use Node 24 in the scaffolded Dockerfile by @michaelbromley in #5637
- fix(graphiql-plugin): call vite directly in the build script by @michaelbromley in #5638
- fix(core): keep the assets of other channels when updating the assets… by @Ryrahul in #5639
- fix(dashboard): prevent duplicate module instances in experimental bundle mode by @michaelbromley in #5643
- fix(dashboard): keep stored user settings when signing in from a signed-out page by @michaelbromley in #5644
- fix(dashboard): select list query fields from the table's live column visibility by @michaelbromley in #5645
- docs: list Node.js 22, 24 and 26 as supported and mark Node.js 20 as end-of-life by @michaelbromley in #5648
- fix(dashboard): show an error instead of an endless loading screen fo… by @Ryrahul in #5620
New Contributors
- @Itsayaboi made their first contribution in #5480
- @rafabernad made their first contribution in #5248
- @AyeshaWaseemAhmad made their first contribution in #5506
- @allanmongej made their first contribution in #5520
- @Haridass30 made their first contribution in #5563
- @theluckystrike made their first contribution in #5483
Full Changelog: v3.8.0...v3.8.1