Repository navigation
Mercur v2.4.1
A hardening and performance release. Product and store offer lists now run on the Medusa index engine with the Caching Module switched on, a core security audit closes a long list of exposure and ownership gaps, operators get a Products → Inbox for everything stores submit, and Medusa moves to 2.22.3. Plus a batch of fixes around split-order checkout and the dashboard SDK.
⚠️ Before you upgrade
- Run
medusa db:migrate. It hashes member-invite tokens in place (member_invite.token_hash, #1739) and creates the writableoffer_seller/offer_productlink tables, then backfills them for existing offers (#1747). - Run one full index sync (
POST /admin/index/sync) so existing sellers and offers are ingested; sellers created before this release never reached the index because their events were dropped (#1740, #1747). - Caching is on by default.
withMercurnow enables thecachingflag and registers the Medusa Caching Module (opt out withfeatureFlags.caching: false). It uses Redis whenprojectConfig.redisUrlis set and an in-memory store otherwise, so multi-instance deployments should setredisUrl(#1740).@medusajs/indexand@medusajs/caching-redisare direct dependencies of the API app and the basic template now. - Removed or tightened API surface (#1739):
POST /admin/sellers/:idno longer acceptsstatus/status_reason(use the lifecycle endpoints) andis_premiumneedssellers.premium:edit;GET /vendor/sellers/meno longer returns payment or professional details (read them fromGET /vendor/sellers/:idbehindstore:view); the admin payout list no longer returnsdataand storedsource_paymentkeeps onlyidandlatest_charge; admin seller and payout-account defaults droponboarding.data;GET /vendor/feature-flagsreturns an allowlist; the invite token is returned only from create and resend;address_idis gone from vendor stock-location validators; suspended and terminated sellers lose Vendor API access exceptGET /vendor/sellers/me; vendor uploads accept images only. - Medusa 2.22.3 (#1752):
BigNumber/MathBNnow throw on invalid input instead of returningNaN, and a malformedbodyParser.sizeLimitthrows when the route is hit.
✨ Highlights
🔎 Product and offer lists on the Medusa index engine
GET /admin/products, GET /vendor/products, GET /store/products and GET /store/offers go through shared listProducts / listOffers helpers. Filters that need another module (the vendor allowlist, sales channels, seller status and scheduled closures) are answered by query.index; everything else stays on a single query.graph with an exact count. Admin and vendor lists return an exact count on the index path too, and all product lists are cached (store 300s, admin and vendor 60s) with explicit invalidation tags. (#1740, #1747, #1750)
🛡️ Core security hardening
A full audit of @mercurjs/core. Store fields= traversal can no longer reach invite tokens, member emails or bank and tax details; invite tokens are hashed and single-purpose; vendor routes gained ownership checks across sales channels, collections, promotions, shipping options, price lists, returns, claims, exchanges and reservations; vendor order edits ignore client-supplied prices; a second offer for a variant already in the cart is rejected; payouts are capped at the captured net amount and add back every credit line except store credit. Closes GHSA-r7gm-rgf8-5q8m and the remainder of GHSA-mhch-gq7f-v5p7. (#1739)
📥 Products → Inbox for operators
One admin table of everything stores are waiting on: newly proposed products and pending edit or deletion requests, with search, Type / Store / date filters, sorting and pagination, served by the new GET /admin/product-changes and gated by the product_request flag. On the vendor side, the product list and product page show the operator's "Changes requested" message until the store resubmits, edits to draft and proposed products apply immediately instead of waiting for a separate approval, and the product list opens newest-first. (#1751)
4.2.1.mp4
💬 Feedback from the dashboards
Both panels show the Mercur version in the topbar next to a Feedback button that sends a message to the Mercur team. (#1749)
Platform
- Bump Medusa to 2.22.3 (#1752). The order cross-module count fix was upstreamed, so that patch is gone; the four core-flows patches apply unchanged.
🐛 Fixes
- Keep split-order cart completion consistent across crashes: the
order_cartlink marks a completed cart, a leftover order group is reused, and a failed completion cancels or refunds the payment (#1745) - Refund a captured payment when split-order cart completion fails after a
capturedwebhook (#1741) - Dashboard SDK virtual modules import only the files they read, fixing the blank panel in Vite dev when a route imports the
pagesentry (#1744) - Keep the index engine Product sync off the review and pricing graphs, fixing the "Cannot read properties of undefined (reading 'id')" sync error on boot (#1750)
create-mercur-appchecks PostgreSQL and creates the database before scaffolding, and tells you how to fix a server, credential or database-name problem; each telemetry milestone is sent exactly once (#1748)- Seller
created/updatedevents are emitted again, so cached seller reads invalidate and subscribers run (#1740) - Name the product-delete
whenblock inapply-product-change-actions(#1743) - Bump
sanitize-htmlto 2.18.1, andzod,i18next-http-backendandvitestto patched versions (#1742, #1737, #1716)
📚 Docs
- Fix broken links and references to the deleted
newbranch (#1636) - Fix typos in the README contribution section (#1726)
🙌 New contributors
- @RashidMahmood25 made their first contribution in #1726 — thank you!
Full Changelog: v2.4.0...v2.4.1