Skip to content

Releases

v2.4.1

Choose a tag to compare

@github-actions github-actions released this 04 Nov 16:03
fd4e5a3

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 writable offer_seller / offer_product link 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. withMercur now enables the caching flag and registers the Medusa Caching Module (opt out with featureFlags.caching: false). It uses Redis when projectConfig.redisUrl is set and an in-memory store otherwise, so multi-instance deployments should set redisUrl (#1740). @medusajs/index and @medusajs/caching-redis are direct dependencies of the API app and the basic template now.
  • Removed or tightened API surface (#1739): POST /admin/sellers/:id no longer accepts status / status_reason (use the lifecycle endpoints) and is_premium needs sellers.premium:edit; GET /vendor/sellers/me no longer returns payment or professional details (read them from GET /vendor/sellers/:id behind store:view); the admin payout list no longer returns data and stored source_payment keeps only id and latest_charge; admin seller and payout-account defaults drop onboarding.data; GET /vendor/feature-flags returns an allowlist; the invite token is returned only from create and resend; address_id is gone from vendor stock-location validators; suspended and terminated sellers lose Vendor API access except GET /vendor/sellers/me; vendor uploads accept images only.
  • Medusa 2.22.3 (#1752): BigNumber / MathBN now throw on invalid input instead of returning NaN, and a malformed bodyParser.sizeLimit throws 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_cart link 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 captured webhook (#1741)
  • Dashboard SDK virtual modules import only the files they read, fixing the blank panel in Vite dev when a route imports the pages entry (#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-app checks 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 / updated events are emitted again, so cached seller reads invalidate and subscribers run (#1740)
  • Name the product-delete when block in apply-product-change-actions (#1743)
  • Bump sanitize-html to 2.18.1, and zod, i18next-http-backend and vitest to patched versions (#1742, #1737, #1716)

📚 Docs

  • Fix broken links and references to the deleted new branch (#1636)
  • Fix typos in the README contribution section (#1726)

🙌 New contributors

Full Changelog: v2.4.0...v2.4.1

v2.4.0

Choose a tag to compare

@github-actions github-actions released this 02 Nov 14:16
84fe2e3

Mercur v2.4.0

Mercur now connects to more of the outside world. Payouts move to a thin core
module plus a new Stripe connector plugin, and a new Magento 2 connector lets
an external storefront sell marketplace offers. Operators can assign sellers
to regions, the panels get a layout composer and much deeper extension points,
and checkout and vendor lists get a serious performance pass. We also bumped
Medusa to 2.22.0, which requires Node 22.22+, and fixed a batch of cart, offer
and panel bugs. This release has breaking changes, so please read the section
below first.

⚠️ Before you upgrade

  • Node 22.22+ and Medusa 2.22.0 (#1685). Medusa 2.22.0 drops Node 20. To pick
    up the October 2026 Node.js security releases, we recommend Node 24.22.1+, or
    22.23.4+ if you stay on Node 22.
  • Run migrations. They restructure the payout tables, add the
    region_seller link, order_group.metadata, a new telemetry table and list
    indexes, and make seller.default_leadtime_to_ship nullable.
  • @mercurjs/payout-stripe-connect is removed (#1693). Install
    @mercurjs/stripe-connector-plugin and point the payout module at
    @mercurjs/stripe-connector-plugin/providers/payout-stripe-connect. If you
    also adopt the plugin's payment provider, add pp_stripe-connector_<id> to
    your regions.
  • The payout module API changed (#1693).
    • createPayoutWorkflow is replaced by createOrderPayoutsWorkflow.
    • On IPayoutProvider, createPayoutAccount becomes createAccount, and
      retrieveAccount and reversePayout are now required.
    • PayoutStatus.CANCELED becomes ABORTED; existing rows are migrated.
  • Existing sellers have no regions until you assign them (#1665, #1696).
    GET /vendor/regions now returns assigned regions only,
    GET /vendor/regions/:id returns 404 for the others, and a vendor offer or
    shipping price on an unassigned region returns 400. Set a default region
    under Settings → Store for new sellers, then link existing ones from the
    seller page or with POST /admin/sellers/:id/regions and
    { "add": ["reg_…"] }.
  • New sellers no longer default to a lead time of 2 (#1687, #1730). They
    start at null and use the marketplace default from Settings → Marketplace.
    Existing sellers keep their current value, including 2; clear a store's lead
    time to move it to the marketplace default. If you ran the migration on a
    v2.3.9 canary, it cleared values of 2, so those sellers need them set again.
  • Offers honour the product–seller allowlist (#1697).
    createOffersWorkflow now refuses a product restricted to other sellers or
    rejected by the operator. Products with no link stay open to every seller.
  • Store order groups no longer return orders.items.variant.product (#1727).
    Asking for it explicitly returns 400. Use orders.items.product_handle and
    orders.items.product_title.
  • GET /vendor/payments scopes through the order's payment collection
    (#1678), so shared, uncaptured cart-stage payments are not listed.
  • Storefront on Next 16 (#1713). Catalog prices are fetched anonymously, so
    customer-group price lists no longer show on catalog pages (the cart still
    applies them). Canonical and structured-data URLs now come from
    NEXT_PUBLIC_BASE_URL.
  • Mercur now sends anonymous telemetry from your server (#1718, #1725). It's
    on by default and prints nothing at boot, and it helps us see how many
    installations exist, which versions they run and whether they keep running.
    • Server: a startup event and a daily heartbeat with a random installation
      id, versions, runtime, OS and infrastructure details, feature flags, and
      one-time milestones such as the first approved seller or first paid payout.
      Marketplace counts are sent as range buckets, never exact numbers. Only
      first-party plugins are named; custom ones are just counted. Each event also
      says whether the install was seeded with demo data.
    • CLI: every command now reports its name, flag names, exit code and
      duration, with flag values redacted unless they're a boolean or a fixed
      choice. It stops sending blocks.json contents, aliasPrefix, CPU model and
      email, and the email prompt is gone.
    • Opt out with MERCUR_DISABLE_TELEMETRY, DO_NOT_TRACK or
      withMercur({ projectConfig: { mercur: { telemetry: false } } }). It's also
      off in CI, under NODE_ENV=test and in worker processes. Set
      MERCUR_TELEMETRY_DEBUG=true to print payloads instead of sending them.
      Every event and property is listed on the telemetry docs page.

✨ Highlights

💳 Stripe connector plugin

Core payouts are now shaped like Medusa's payment module: one provider per
marketplace, one payout per seller order, and one payout_reversal per later
refund. An order that isn't ready goes on_hold and is re-decided on the next
run. Core still schedules nothing. @mercurjs/stripe-connector-plugin brings
the operations: seven scheduled jobs, settlements that net payouts, reversals
and adjustments per seller and currency, operator adjustments, capture
validation and failed-operation alerts. Operators get Integrations → Stripe and
Settings → Stripe, plus widgets on the seller and order pages. Vendors get their
own Stripe page. (#1693)

🛒 Magento 2 connector

@mercurjs/magento2-connector-plugin lets a Magento 2 storefront sell
marketplace offers while Mercur keeps sellers, split orders, commissions and
payouts. It ships HMAC-signed webhooks with retries and redelivery, and an
external payment provider that authorizes at checkout and captures when Magento
invoices the order. Storefront refunds are mirrored onto the Mercur order, and
there's an admin screen at /settings/magento. The Magento side is the separate
mercurjs/magento2-connector Composer package. (#1683, c5305c2)

🌍 Sellers in regions

Operators decide which regions a seller operates in, from the region page, the
seller page or Create Seller. Vendors see and price only in their assigned
regions, and the offer grids get one column per region. Admin keeps full
visibility of prices across all regions. New sellers get the store's default
region. (#1665)

🧱 Layout composer and deeper panel extensions

Admin product detail and vendor offer detail now render through a
LayoutComposer that uses Medusa's entry ids. Plugins, the Medusa project and
the host app are ordered layers where later wins, and any layer can contribute
routes, widgets, layouts/, _layouts.ts and _navigation.ts (#1674).
Custom-fields configs can also hide, replace or add columns and fields on
embedded tables, spreadsheet grids and built-in form fields, using the existing
list and forms keys (#1701).

🧭 Customizable vendor onboarding

Each onboarding step is now a tab of the seller onboarding form zone, so you
can add, remove, reorder or mark steps optional from a custom-fields config. The
store handle is now required, with a live check against the new
GET /vendor/sellers/handle-availability. Going back after a failed Finish no
longer wipes what the user typed. (#1658)

🏷️ Offer conditions in the panels

Operators manage conditions under Settings → Offer Conditions, and vendors pick
one when creating or editing an offer. (#1657, #1661)

⏱️ Lead time defaults

Lead time gets its UI and a marketplace-wide default, set in Settings →
Marketplace, on the store, and on the offer. GET /store/offers returns
effective_leadtime_to_ship, resolved from offer to store to marketplace.
(#1687)

⚡ Performance

  • Fix checkout lock units: timeouts passed in milliseconds meant a lock wait of
    about 8 hours and a TTL of about 33. Concurrent completion under
    processPaymentWorkflow is now locked too (#1677).
  • Load the commission rate table once per checkout, and add list indexes on
    order groups, offers, payouts, reviews and commission rules (#1677).
  • Push vendor list seller scoping into SQL EXISTS subqueries instead of id IN
    lists that grow with lifetime volume (#1678).

🛍️ Storefront

  • Move to Next 16 with Cache Components: every route has a prerendered shell,
    the default first page of a listing sits in the HTML, and catalog reads are
    cached (#1713).
  • Add a cart drawer that opens instantly, optimistic cart edits, and a quantity
    picker on the product page. Pages no longer wait on the cart (#1711).

🧩 More extension points

  • offerPricesUpserted hook, plus previous values, snapshots and updated_by
    on the other offer hooks (#1654).
  • getStatistics on the seller and offer modules, with
    GET /admin/sellers/statistics and GET /admin/offers/statistics (#1659).
  • deleted_at filter and with_deleted on admin offers and sellers, so a delta
    sync can see removals (#1683).
  • order_group.metadata, copied from cart.metadata (#1683).
  • POST /store/carts/:id/complete now returns the seller orders (#1697).
  • is_replay on the paymentRefunded hook (#1685).

Platform

  • Bump Medusa to 2.22.0 (#1685).

🐛 Fixes

  • Allocate cart credit lines across split orders, so the credit-covered part no
    longer shows as owed. Fully credit-covered orders still stay on hold for
    payout (#1728).
  • Compensate commission lines, payment captures and links when checkout is
    canceled after completion, so no marketplace records stay behind (#1729).
  • Confirm offer stock against the cart's total demand per inventory item, so
    buyers learn at add-to-cart rather than at checkout (#1668).
  • Subtract reserved stock from availability on GET /store/offers (#1669).
  • Stop Edit prices on a vendor offer from wiping every price when saved before
    regions loaded (#1673).
  • Fix in-place updates of quantity-tiered offer prices never completing (#1654).
  • Return items.offer and items.offer.seller on store cart routes, so carts
    group by the right seller (#1712).
  • Stop GET /store/order-groups returning 400 without fields, which crashed
    the storefront's order page (#1727)...
Read more

v2.3.7

Choose a tag to compare

@github-actions github-actions released this 08 Oct 15:51
57fa9cf

Mercur v2.3.7

A smaller release with one new building block and a batch of fixes. Offers
learn about conditions, so operators can define "new", "refurbished" or "used"
and sellers pick one per listing. The admin order list gets a payment status
filter, server-side search in its filters and smarter search by order number.
Two security fixes close cross-seller gaps in the vendor API and in cart
promotions, and payouts no longer call the provider before a row is written.

⚠️ Before you upgrade

  • Run migrations — the offer module adds an offer_condition table and
    offer.condition_id (seeded with a default new condition), and the payout
    module widens the payout.status check constraint to accept processing
    (#1645, #1641).
  • Payouts are briefly pending. createPayouts now inserts the row
    before calling the provider, so payout.created fires for a pending row and
    readers that assumed every row is already sent should check status (#1641).
  • Seller promotions are scoped on every cart refresh. A vendor promotion
    without seller-specific target rules, or an automatic one, no longer
    discounts other sellers' items. If your storefront relied on that, it was a
    bug (#1648).

✨ Highlights

🏷️ Offer conditions

Operators define the physical conditions an offer may be listed under through
/admin/offer-conditions (code, label, is_active, rank), and sellers pick
an active one via condition_id when creating or updating an offer. Admin,
vendor and store offer responses expose condition.{id,code,label} and filter
on condition_id. Deleting a condition in use is refused; deactivating keeps
existing offers but blocks new assignments. API only for now, with
createOfferConditionsWorkflow / update / delete hooks and
offer_condition.* events. (#1645)

📋 Admin order list

  • Filter order groups by payment status. The status is computed from
    payment collections, so GET /admin/order-groups?payment_status=captured
    matches exactly what the list shows (#1639).
  • Search by the numbers operators actually see: 264, #264 or #G258 now
    match the group's display id or any child order's display id (#1638).
  • Customer, Store and Sales channel filters search on the server, so stores
    with more than 1000 customers or sellers can select any of them (#1640).

🔒 Security

Both issues below were reported privately by @gregbarajas, with clean
end-to-end reproductions on a v2.3.6 starter that made the fixes
straightforward. Thank you, Greg!

  • Close cross-seller authorization gaps in the vendor API: fields traversal
    into other sellers' members, payment details and invite tokens, product
    detail routes on another seller's drafts, capture of shared cart payments,
    and offer / inventory body ids pointing at another seller's items or
    locations (GHSA-mhch-gq7f-v5p7, #1649).
  • Keep seller promotions scoped to the seller's own items on every cart
    refresh, not only when applied through POST /store/carts/:id/promotions
    (GHSA-w4vq-6jvh-cfpg, #1648).

🐛 Fixes

  • Insert the payout row before calling the provider, use the payout id as the
    default idempotency_key, and accept the processing status in the
    database (#1641).
  • Intersect id and seller_id filters on GET /admin/order-groups instead
    of returning every group (#1637).
  • Rebuild the Variants table on every attribute change in Products → Create in
    both panels, and surface create errors as a toast instead of a silent 400
    (#1650).

Full Changelog: v2.3.6...v2.3.7

v2.3.6

Choose a tag to compare

@github-actions github-actions released this 06 Oct 11:11
f973281

Mercur v2.3.6

A big one. Split orders finally get payments of their own, so refunds and
cancellations work through the stock Medusa routes. Product descriptions get
a rich text editor, and the sidebar collapses to an icon rail. We bumped
Medusa to 2.21.2 and moved to zod 4 — plus a long list of new extension
points and fixes.

⚠️ Before you upgrade

  • Medusa 2.21 and zod 4 (#1554, #1614). Every @medusajs/* pin moves to
    2.21.2 and the workspace runs on zod 4. In your own validators, rewrite
    single-argument z.record(value) to z.record(key, value).
  • The built-in notifications bell is gone (#1572). Notifications is no
    longer exported from @mercurjs/admin or @mercurjs/vendor, and the
    Cmd/Ctrl+N shortcut is removed. Register your own widget on the new
    topbar.after zone instead.
  • Panels sign in with bearer tokens (#1631). Both panels drop the cookie
    session, so everyone is logged out once after upgrading. Custom page
    clients should send getAuthHeaders() from @mercurjs/admin /
    @mercurjs/vendor instead of credentials: 'include'.
  • Admin product delete goes through the change pipeline (#1583).
    DELETE /admin/products/:id now returns an error when the product has a
    pending product change.
  • Run migrations — PayoutAccount.data gets a default (#1582).

✨ Highlights

💳 Per-order payments for split orders

When a cart's payment is captured, it is now split: every seller order gets
its own payment collection with a captured payment for its share, pointing at
the same charge. Refunding and canceling a split order work through the stock
Medusa routes and workflows, capped at the order's share. Canceling before
capture leaves the authorization for the cart's other orders. Orders captured
before this release are not split retroactively. (#1627)

✍️ Rich text product descriptions

Product descriptions can mix formatted text and images. RichTextEditor and
the RichText renderer ship in @mercurjs/dashboard-shared and are used
across product create, edit and detail in both panels. Descriptions are
sanitized on write and on the storefront; existing plain-text descriptions
keep working, and there is no migration. (#1584)

🧭 Sidebar: icon rail and nav groups

The sidebar collapses to an icon rail with tooltips instead of disappearing,
and useSidebar / useCollapsedSidebar let a page drive it. _navigation.ts
gains a groups API, so you can declare groups and assign items to them in
both the main and settings sidebars. (#1559, #1586, #1621, #1629)

📝 Extendable registration and invitation

A plugin can add fields to the vendor register and invite forms and act on
them on the server: createSellerAccountWorkflow gets a validate hook,
and acceptMemberInviteWorkflow gets validate and memberInviteAccepted,
with additional_data accepted on invite acceptance. Plugin vendor routes
exporting AUTHENTICATE = false now skip vendor auth. (#1591, #1613)

🧩 More extension points

  • paymentCaptured and paymentRefunded hooks on the capture and refund
    workflows, plus returnReceived and commissionLinesUpserted (#1558).
  • payoutCreated hook on createPayoutWorkflow (#1580).
  • fulfillmentDelivered hook on markOrderFulfillmentAsDeliveredWorkflow
    (#1607).
  • topbar.before / topbar.after widget zones in both panels (#1572).
  • Extensions can add tabs to the admin store detail page via
    stores.detail.tabs.* and a label on defineWidgetConfig (#1609).
  • Per-card locations.list.item widget zone on the locations list (#1620).
  • Custom-fields list filters can replace or remove built-in filters (#1634).
  • Deleting a product now soft-deletes its seller offers (#1583).
  • Offer inventory items inherit the variant's shipping and customs
    attributes (#1624).

Platform

  • Bump Medusa to 2.21.2 and move the workspace to zod 4 (#1554, #1614).

🐛 Fixes

  • Keep admin and vendor logins independent when both panels share one API
    host (#1631).
  • Return the existing order group when a cart is completed again, instead of
    placing duplicate orders (#1603).
  • Preserve other sellers' prices when one seller updates an offer price
    (#1550).
  • Restore Medusa middlewares on product routes Mercur does not override —
    fixes 500s on variant batch, options and product-variant routes (#1553).
  • Stop showing a published, allowlisted product to its creator once it is
    restricted to other stores (#1552).
  • Keep order group seller_count and total independent of list filters
    (#1632), and make sorting by display_id work (#1633).
  • Forward order list filters to the API in the vendor panel (#1556).
  • Apply Medusa patches on import, so blocks imported in medusa-config.ts
    see the patched workflows (#1573).
  • Return a proper 400 instead of a 500 when a payout account is created
    without data (#1582).
  • Scaffold new projects from the template of the pinned release tag, so
    create-mercur-app no longer produces projects that fail to boot (#1623).
  • Resolve the local CLI directly for codegen — no more slow npx on every
    boot in monorepos (#1619).
  • Detect Medusa's Stripe card provider on the storefront (#1581) and
    self-host the Funnel Display font (#1611).
  • Restore dropped placeholders and Trans tags in admin and vendor locales
    (#1612).
  • Use the outline star for the vendor reviews sidebar item (#1608).
  • Resolve the repository root dynamically in the dev scripts (#1618).
  • Bump sanitize-html to 2.17.7 (#1625).

🙌 New contributors

Full Changelog: v2.3.5...v2.3.6

v2.3.5

Choose a tag to compare

@github-actions github-actions released this 17 Sep 11:08
09bb710

Mercur v2.3.5

A patch release focused on security. We closed three authorization gaps in the
Store and Vendor APIs and patched critical Next.js advisories in the
storefront. Plugins also get new seams on the order detail page, plus a fix for
the vendor onboarding currency select.

⚠️ Before you upgrade

  • POST /store/carts/:id/line-items no longer accepts unit_price or
    compare_at_unit_price
    (#1546). Requests that send either field now get a
    400. Line prices always come from the offer, so remove these fields from
    any storefront or integration that sends them.

🔒 Security issues addressed

  • Client-supplied cart prices. A shopper could set unit_price when adding
    a line item. The price was treated as custom, skipped recalculation and
    carried into the order and payment authorization. These fields are now
    rejected. (#1546)
  • Cross-product variant edits. POST and DELETE /vendor/products/:id/variants/:variant_id didn't check that the variant
    belonged to the product in the path. A change request could update or delete
    a variant (including its images) on a different product. Both routes now
    return 404 when the variant isn't on that product. (#1545)
  • Customer group membership. POST /vendor/customer-groups/:id/customers
    checked that the seller owned the group but not the customers. A vendor could
    add or remove any customer on the platform, including other sellers'
    customers. Every add and remove ID is now checked, and the route returns
    404 if any customer isn't linked to the seller. (#1544)
  • Next.js RCE advisories in the storefront. Bumped next to 15.5.24 in
    apps/storefront. This resolves GHSA-2xp9-vwfh-vxw4 (unauthenticated RCE in
    the Image Optimization API with AVIF files) and GHSA-p293-qw3h-jr36
    (unauthenticated RCE on Windows-hosted servers). If your storefront is based
    on ours, bump next there too. (#1542)

We recommend all marketplaces upgrade.

✨ Highlights

🧩 Order detail extension points

Plugins such as disputes can now act on an order without forking its sections.
This works in both panels. (#1530)

  • Action locks. actionLocks in defineCustomFieldsConfig can disable
    Edit order, Return, Exchange and Claim. The string you return becomes
    the disabled action's tooltip.
  • Line-item zone. A new orders.detail.item widget zone on each summary
    row receives { order, item }.
  • Timeline entries. activity adds your own entries to the order activity
    timeline.

Nothing changes unless a plugin configures these.

🐛 Fixes

  • Return supported currencies from GET /vendor/stores, so the vendor
    onboarding Currency select is populated again on Medusa 2.20 (#1543)

Full Changelog: v2.3.4...v2.3.5

v2.3.4

Choose a tag to compare

@github-actions github-actions released this 14 Sep 13:06
bf52fbd

Mercur v2.3.4

This release is all about extensibility. Commissions get pluggable providers,
split orders and product edits get new workflow hooks, and offers learn about
handling time. Shipping profiles become operator-owned, RBAC is now fully
opt-in, and we bumped Medusa to 2.20.1 — plus a batch of fixes across offers,
the panels and the client.

⚠️ Before you upgrade

  • Shipping profiles are now operator-owned (#1498). Only the marketplace
    operator defines shipping profiles; vendors can still read and select them.
    POST / DELETE on /vendor/shipping-profiles are removed, along with the
    seller_id filter on GET /admin/shipping-profiles and the
    shipping-profile-seller-link.
  • Run migrations — new columns on offers, sellers and commission lines.
  • RBAC is opt-in (#1521). If you use seller roles and permissions, enable
    it with withMercur({ featureFlags: { rbac: true } }).

✨ Highlights

💸 Commission providers

The commission module now has a provider seam, just like payouts. Implement
ICommissionProvider to plug in your own commission logic, and pass extra
context through the new setCommissionContext hook. The existing calculation
ships as the default system provider, so nothing changes unless you
configure one. (#1509)

📦 Order acceptance flows

A new setOrderStatus hook on completeCartWithSplitOrdersWorkflow lets a
plugin set each seller order's initial status — for example requires_action
for marketplaces where sellers accept orders first. Both panels now lock
fulfil, edit, return, exchange, claim, capture and refund on those orders, and
order tables get a status filter. (#1513)

🚚 Handling time on offers

Offers accept leadtime_to_ship — business days until the parcel is handed to
the carrier — falling back to the seller's default_leadtime_to_ship
(default 2). The building block for shipping deadlines and delivery
estimates. (#1491)

🧩 More extension points

  • validate hook on the vendor product-edit workflows (#1484).
  • value_ids accepted on product attribute batch update (#1481).
  • ClientError keeps the API error code, so your storefront can react to a
    specific refusal instead of matching on the message (#1477).

Platform

  • Bump Medusa to 2.20.1 (#1489).

🐛 Fixes

  • Reject offer prices of 0 or less, and skip unpriced variants in the vendor
    Create offers form (#1522).
  • Accept a decimal comma in offer price fields (#1520).
  • Stop marking unhandled product-change actions as applied (#1463).
  • Tolerate dangling price links in updateOffersWorkflow (#1482).
  • Merge plugin i18n into the panels and keep parent breadcrumbs on file-based
    routes (#1511).
  • Use valid BCP 47 tags for Chinese and Portuguese (#1519).
  • Stub virtual:medusa/search-entities in the dashboard SDK (#1495).
  • Avoid a 4-level field expansion when the storefront retrieves the cart (#1518).

📚 Docs

  • Clarify the Stripe webhook events needed for split-order checkout (#1523).

🙌 New contributors

Full Changelog: v2.3.3...v2.3.4

v2.3.3

Choose a tag to compare

@github-actions github-actions released this 01 Sep 10:17
4e91ae1

   🐞 Bug Fixes

    View changes on GitHub

v2.3.2

Choose a tag to compare

@github-actions github-actions released this 31 Aug 16:08
80bd554

v2.3.2

A security and hardening release. All marketplaces running 2.3.1 or earlier should upgrade.

🔒 Security

This release fixes a critical broken-access-control (BOLA/IDOR) vulnerability in the vendor API, privately reported by @hackchang under coordinated disclosure. Thank you.

The issue: the /vendor/sellers/:id route subtree operated on the URL id parameter without binding it to the authenticated seller. Any authenticated vendor could target another seller's id to read that store's full record (profile, payment details, professional/tax details), overwrite its profile, and manage its team members — invite themselves in, change roles, remove members. In effect, full account takeover of any other vendor's store.

Weakness: CWE-639 / CWE-862 · Severity: Critical (CVSS 3.1 ~9.3, AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H)

What changed:

  • Every /vendor/sellers/:id handler is now scoped to the authenticated seller; a mismatched id no longer resolves (#1449)
  • Member-management routes bind member_id to the caller's own seller
  • GET /vendor/stores now requires member authentication (#1450)
  • The vendor stores query has its selectable fields restricted (#1453)

A GitHub Security Advisory with a CVE request is being published from the repository's Security tab, with @hackchang credited as reporter.

✨ Features

  • Attribute edits now go through the product-change diff pipeline, the same way product edits do (#1444)
  • CLI builds admin dashboard extensions, and a package can ship its own entry point (#1424)
  • create-mercur-app pins generated projects to the CLI's release channel (#1459) — scaffolding with @rc no longer mixes in latest packages

🐛 Fixes

Checkout & orders

  • Core owns the payment webhook so carts complete as split orders (#1418)
  • Split-order payment status is reported correctly on the admin and store order routes (#1458)
  • Payment statuses are no longer double-counted (#1399) — thanks @shin4141
  • Cart shipping profiles are validated against the offer (#1417), and shipping-method cleanup is derived from offers rather than products (#1455)

Offers & attributes

  • Created offer prices are attributed by rule instead of position (#1397)
  • New scoped-axis option values are associated with their product (#1454)
  • Attribute possible-values pagination fixed (#1447) — thanks @adeaviladev01
  • The pending product-change guard is actor-scoped (#1443)

Dashboards

  • RouteDrawer dialogs have an accessible title (#1415)
  • The admin invite form carries the roles field, so invited admins aren't locked out (#1420)
  • DataGrid column resizing works (#1452)
  • The NoRecords empty state grows instead of overflowing (#1456)
  • react-router-dom is a peer dependency (#1426)
  • dashboard-sdk resolves plugin roots via Node and no longer emits top-level await (#1429)
  • plugin:build no longer races itself for src/admin/index.mjs (#1427)

Other

  • Algolia block: the five dead algolia.intermediate.* subscribers removed (#1416) — thanks @Roshan931
  • Storefront drops the unused next-intl dependency (#1457)
  • Architecture docs rewritten around layers and extension zones (#1412)

📦 Upgrading

npm install @mercurjs/core@2.3.2

Bump every @mercurjs/* package to 2.3.2 together — they are released in lockstep. Newly scaffolded projects from templates/basic pin to 2.3.2 automatically.

New Contributors

Full Changelog: v2.3.1...v2.3.2

v2.3.1

Choose a tag to compare

@github-actions github-actions released this 14 Aug 09:06
bbf1922

v2.3.1

A patch release with bug fixes across the vendor panel, dashboard SDK, storefront, and scaffolding CLI.

Fixes

  • vendor: Split orders now show the authorized payment status correctly (#1390)
  • dashboard-sdk: Register the layouts and cell-renderers virtual modules so they resolve at build time (#1388)
  • storefront: Bump @mercurjs/* deps to the release version to fix hoisted stale types breaking medusa build (#1393)
  • create-mercur-app: Pin packageManager so Turborepo can resolve the workspace in freshly scaffolded projects (#1389)

Chores

  • storefront: Remove vercel.json (#1392)

Full changelog: v2.3.0...v2.3.1

v2.3.0

Choose a tag to compare

@vholik vholik released this 11 Aug 08:56
bce113d

Mercur v2.3.0

This release brings a wave of UI polish across the Admin and Vendor panels, two
brand-new Reviews surfaces, a smarter offer inventory system, fully revamped
documentation, and a bump to Medusa 2.18.0 — plus a batch of fixes reported by
the community.

✨ Highlights

📚 Revamped documentation

Our docs got a major overhaul — restructured into clear Platform, Build,
and Reference sections, with refreshed positioning and new User Guides
to walk you through the platform step by step. Check them out at
https://docs.mercurjs.com. (#1340, #1355)

Reviews

  • Admin reviews panel + core review module — moderate product and seller
    reviews from the operator dashboard, backed by a dedicated review module. (#1309)
  • Vendor reviews — sellers can now see and manage reviews from their own
    panel. (#1308)

Offers & Inventory

  • Manage inventory, inventory kits & backorders for offers — offer-scoped
    inventory management, multi-item kits, and backorder support. (#1336)

Panel redesigns

  • Admin: redesigned Inventory (#1329), Reservations (#1330) and Price Lists (#1331) panels.
  • Vendor: redesigned Inventory (#1332), Reservations (#1334) and Price Lists (#1338) panels.
  • Campaigns: admin Campaigns UI refresh with list filters (#1307); vendor
    Campaigns refresh (#1305) plus detail polish, promotions filters & a filtering
    refactor (#1316).
  • Admin login screen redesigned (#1306).

Platform

  • Bump Medusa to 2.18.0 (#1368).

🐛 Fixes

  • Declare zod as a runtime dependency in core (#1310).
  • Unblock codegen crash from execa Set.prototype.union (#1311).
  • Guard undefined regions in the shipping option pricing form (#1327).
  • Resolve sidebar labels through translationNs (#1369).
  • Make DataGrid columns resizable (#1370).
  • Point storefront hreflang alternates at 200 locale URLs (#1356).
  • Use the built-in password reveal on the login field (#1314).
  • Default campaigns list to created_at order (#1315).

🧰 Internal / Chore

  • Self-contained UI e2e harness (#1312) and fixture lint fix (#1313).
  • Rename storefront package to @mercurjs/storefront (#1301).
  • README star-history snapshot + docs home video tweaks (#1337, #1342, #1343, #1354).

🙌 Thanks to the community

Huge thanks to everyone who reported issues, shared feedback, and tested canary
builds — Mercur gets better because of you.

Welcome and thank you to our new contributor @bansal-ashish-dev, who made
their first contribution in #1327! 🎉

Full Changelog: v2.2.1...v2.3.0