github medusajs/medusa v2.10.2

9 hours ago

Highlights

Indexing of core entities

Medusa Index was built to improve the developer experience of filtering data across modules while improving performance, especially for large data sets.

With this release, all entities in the core Medusa modules are now ingestible into Medusa Index. This unlocks cross-module filtering for all core and custom entities. The ingestion happens automatically, provided a link is defined between the entities, as described in our documentation.

For example, filtering Products by Sales Channels used to require the following steps:

// 🔴 BEFORE

const query = container.resolve("query")

// Sales Channels to filter by
const salesChannels = ["sc_1234"]

// Query the Sales Channel <> Product link table for matching links
const { data: links } = await query.graph({
  entity: "product_sales_channel",
  fields: ["product_id"],
  filters: {
    sales_channel_id: salesChannels
  }
})

// Construct the products filter using the matched links
const productFilters = {
  id: links.map(link => link.product_id)
}

// Finally query the products with the filters
const { data: products } = await query.graph({
  entity: "product",
  fields: ["id"],
  filters: productFilters
})

With Index, the same example from above can be done with a single query:

// 🟢 NOW

const query = container.resolve("query")

// Sales Channels to filter by
const salesChannels = ["sc_1234"]

// Query the products with the sales channel filter
const { data: products } = await query.index({
  entity: "product",
  fields: ["id"],
  filters: { sales_channels: { id: salesChannels } },
})

Note that in the second code snippet, we use query.index instead of query.graph to query Medusa Index.

For setup and usage details of Medusa Index, see our documentation.

Locking all cart operations

All cart workflows in Medusa's core are now locking the cart during execution to eliminate the risk of concurrent changes.

We would recommend that you introduce the same locking mechanism to your own custom cart workflows.

Here's how you would do it:

export const myCustomAddToCartWorkflow = createWorkflow("my-custom-add-to-cart-workflow",
  (input) => {
    // Acquire a lock on the cart ID as the first step in the workflow
    acquireLockStep({
      key: input.cart_id,
      timeout: 2, // Attempt to acquire the lock for two seconds before timing out
      ttl: 10, // Lock is only held for a maximum of ten seconds
    })

   // Run all regular cart operations

    // Release the lock on the cart ID as the last step in the workflow
    releaseLockStep({
      key: cart.id,
    })

    return new WorkflowResponse({ ... })
  }
)

Features

  • feat(promotion): Allow buyget promotion to apply multiple times on cart by @riqwan in #13305
  • feat(admin): add view configuration client infrastructure by @srindom in #13186
  • Feat/datatable core enhancements by @srindom in #13193
  • feat(ui): add column visibility and drag-and-drop reordering support by @srindom in #13198
  • feat(admin): add configurable order views by @srindom in #13211
  • feat(dashboard,cart,types,utils): refine order details summary by @willbouch in #13313
  • chore(orchestration): add support for autoRetry, maxAwaitingRetries, retryStep by @adrien2p in #13391

Bugs

Documentation

Chores

Other Changes

New Contributors

Full Changelog: v2.10.1...v2.10.2

Don't miss a new medusa release

NewReleases is sending notifications on new releases.