npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

medusa-review-rating

v0.0.38

Published

A starter for Medusa plugins.

Readme

medusa-review-rating

Medusa v2 plugin that adds customer product reviews, rating aggregation, moderation APIs, and admin product review management UI.

Plugin Overview

medusa-review-rating provides a full review/rating layer for Medusa storefronts and admin operations:

  • Customers can create and manage product reviews.
  • Admins can list, moderate (approve/reject), and delete reviews.
  • Product rating aggregates are recalculated from approved reviews and stored on product (total_rating_count, total_rating_sum).
  • Includes workflows and workflow steps for create/update/status/delete review flows.
  • Includes a Medusa Admin widget for product-level review management.

It is built for Medusa v2 (uses @medusajs/framework, module architecture, workflows SDK, and admin SDK).

Installation & Setup

1) Install package

npm install medusa-review-rating
# or
yarn add medusa-review-rating

2) Register plugin/module in medusa-config.ts

import { defineConfig } from "@medusajs/framework/utils"

export default defineConfig({
  modules: {
    reviews: {
      resolve: "medusa-review-rating",
      options: {
        auto_approve: true,
        verify_purchase: false,
        multiple_rating: false,
      },
    },
  },
  plugins: [
    {
      resolve: "medusa-review-rating",
    },
  ],
})

3) Run migrations

npx medusa db:migrate

Migration creates:

  • review table
  • product columns: total_rating_count, total_rating_sum
  • indexes for review and product rating fields

Configuration (config.ts / plugin options)

This plugin does not use a separate config.ts; options are resolved inside src/modules/reviews/service.ts.

| Option | Type | Required | Default | Description | |---|---|---|---|---| | auto_approve | boolean | Optional | true | If true, newly submitted reviews are immediately approved; otherwise created as pending. | | verify_purchase | boolean | Optional | false | If true, customer must have purchased product (completed order) to submit review. | | multiple_rating | boolean | Optional | false | If false, one review per customer/product; if true, allow multiple. | | multipleRating | boolean | Optional | false | CamelCase alias accepted and normalized to multiple_rating. |

Complete example config

{
  modules: {
    reviews: {
      resolve: "medusa-review-rating",
      options: {
        auto_approve: false,
        verify_purchase: true,
        multiple_rating: true,
      },
    },
  },
  plugins: [{ resolve: "medusa-review-rating" }],
}

Environment Variables

No runtime process.env.* reads were found in src plugin code.

| Variable | Used in runtime code | Notes | |---|---|---| | None | No | Configuration is driven by module options, not env lookup. |

⚠️ Note: src/modules/README.md contains a generic process.env.API_KEY documentation example, but it is not runtime logic.

REST APIs / Routes

Store APIs

POST /store/reviews

  • Auth: Customer JWT required
  • Body schema:

| Field | Type | Required | |---|---|---| | product_id | string | Yes | | rating | number (1..5) | Yes | | title | string | No | | description | string | No | | images | string[] | No |

  • Response: workflow result containing created review
  • Notes:
    • Returns 409 when duplicate review is blocked (multiple_rating = false)
    • Enforces purchase verification when verify_purchase = true

GET /store/reviews/:id

  • Auth: optional
  • Access behavior:
    • owner can view own review in any status
    • non-owner can only view approved reviews
  • Response: { review }

PUT /store/reviews/:id

  • Auth: Customer JWT required
  • Body schema:

| Field | Type | Required | |---|---|---| | title | string | No | | description | string | No | | rating | number (1..5) | No |

  • Validation: at least one field required
  • Response: workflow result with updated review

GET /store/reviews/me

  • Auth: Customer JWT required
  • Query params:

| Field | Type | Required | |---|---|---| | product_id | string | No | | status | pending \| approved \| rejected | No |

  • Response:
    • reviews list
    • summary with total_reviews, average_rating, total_rating_sum

GET /store/products/:id/reviews

  • Auth: optional
  • Behavior:
    • unauthenticated: approved reviews only
    • authenticated: own reviews (all statuses) + others’ approved reviews
  • Response: { reviews }

GET /store/products/:id/reviews/me

  • Auth: Customer JWT required
  • Response:
    • reviews for customer+product
    • summary for that product/customer

GET /store/ratings

  • Auth requirement: follows Store API access; handler expects AuthenticatedMedusaRequest
  • Query params:

| Field | Type | Required | Description | |---|---|---|---| | product_id | string or comma-separated list | No | Filter product ids | | limit | integer string | No | Max rows | | offset | integer string | No | Pagination offset |

  • Response: { rating: [{ product_id, average_rating, total_reviews, total_rating_sum }] }

GET /store/plugin

  • Health endpoint, returns HTTP 200.

Admin APIs

GET /admin/reviews

  • Auth: Admin JWT (admin namespace route)
  • Query: passed directly to listReviews
  • Response: { reviews }
  • Note: current implementation uses fixed skip: 0, take: 20 in options.

POST /admin/reviews/:id

  • Auth: Admin JWT
  • Body schema:

| Field | Type | Required | |---|---|---| | status | pending \| approved \| rejected | Yes |

  • Response: workflow result with updated review
  • Triggers conditional product rating recalculation.

DELETE /admin/reviews/:id

  • Auth: Admin JWT
  • Response: { id, object: "review", deleted: true }
  • Triggers product rating recalculation.

GET /admin/plugin

  • Health endpoint, returns HTTP 200.

Important endpoint examples

# Create review (customer)
curl -X POST "http://localhost:9000/store/reviews" \
  -H "Content-Type: application/json" \
  -H "x-publishable-api-key: <PUBLISHABLE_KEY>" \
  -H "Authorization: Bearer <CUSTOMER_JWT>" \
  -d '{
    "product_id": "prod_123",
    "rating": 5,
    "title": "Great product",
    "description": "Highly recommended"
  }'
# List product reviews
curl -X GET "http://localhost:9000/store/products/prod_123/reviews" \
  -H "x-publishable-api-key: <PUBLISHABLE_KEY>"
# Get ratings summary
curl -X GET "http://localhost:9000/store/ratings?product_id=prod_123,prod_456&limit=20" \
  -H "x-publishable-api-key: <PUBLISHABLE_KEY>"
# Admin approve review
curl -X POST "http://localhost:9000/admin/reviews/rev_123" \
  -H "Authorization: Bearer <ADMIN_JWT>" \
  -H "Content-Type: application/json" \
  -d '{ "status": "approved" }'

Services

ReviewModuleService (src/modules/reviews/service.ts)

Manages review persistence, rating calculation, and purchase verification.

Key methods:

  • getOptions()
    • Returns resolved module options.
  • calculateProductRating(productId: string)
    • Recomputes approved-review aggregates and updates product rating columns.
  • verifyPurchase(customerId: string, productId: string)
    • Checks completed customer orders joined to line items for product purchase evidence.

Also inherits CRUD methods from MedusaService for review entity operations (listReviews, retrieveReview, createReviews, updateReviews, deleteReviews).

Workflows & Steps (Medusa v2)

Workflows

create-review

  • Input: customer_id, product_id, rating, optional title, description, images, allow_multiple_reviews
  • Steps:
    • get-review-options
    • validate-single-review
    • verify-purchase
    • create-review
    • calculate-product-rating (only when auto-approved)
  • Output: { review }

update-review

  • Input: id, partial review data (title, description, rating)
  • Steps:
    • retrieve-review
    • update-review
    • calculate-product-rating
  • Output: { review }

update-review-status

  • Input: id, status
  • Steps:
    • retrieve-review
    • update-review
    • determine-rating-recalculation
    • calculate-product-rating
  • Output: { review }

delete-review

  • Input: id
  • Steps:
    • retrieve-review
    • delete-review
    • calculate-product-rating
  • Output: { id, object: "review", deleted: true }

Step summary

  • get-review-options: resolves service/module options.
  • validate-single-review: blocks duplicate product review when multiple disallowed.
  • verify-purchase: enforces optional purchase requirement.
  • create-review: persists review with status derived from auto-approve.
  • retrieve-review: loads review by id.
  • update-review: applies update and returns latest row.
  • delete-review: deletes review by id.
  • determine-rating-recalculation: status-transition-based recalc decision.
  • calculate-product-rating: recalculates/updates product rating metrics.

Subscribers / Event Hooks

No subscribers are defined in this plugin (src/subscribers contains README only).

Admin UI / Widgets

ProductReviewsWidget

  • Placement: product.details.after
  • File: src/admin/widgets/product-reviews-widget.tsx
  • Renders:
    • rating summary for approved reviews
    • filter controls (all, pending, approved, rejected)
    • review list with metadata, stars, images, and moderation controls
  • User interactions:
    • approve/reject/restore review
    • delete review
    • status filtering
  • Data consumed:
    • data.id product id from admin widget context
    • /admin/reviews list API
    • /admin/reviews/:id status update/delete APIs

Models & Entities

review model

| Field | Type | Nullable | |---|---|---| | id | id | No | | product_id | text | No in model intent (migration allows null) | | customer_id | text | No in model intent (migration allows null) | | rating | number | No | | title | text | Yes | | description | text | Yes | | images | json | Yes | | verified_purchase | boolean | No | | status | enum(pending,approved,rejected) | No |

Related core Medusa data:

  • Stores product_id (links to product table by id).
  • Stores customer_id (links to customer record by id).
  • Rating aggregates written to product.total_rating_count and product.total_rating_sum.

Use Cases & Examples

  1. Verified buyers-only reviews

    • Enable verify_purchase: true and use POST /store/reviews for trusted feedback.
  2. Moderated review publishing

    • Set auto_approve: false; admins review queue via widget or /admin/reviews + /admin/reviews/:id.
  3. Single review per customer/product

    • Keep multiple_rating: false; duplicate submission returns 409.
  4. Public storefront ratings summary

    • Use GET /store/ratings to render rating cards for product lists.
  5. Customer review history

    • Use GET /store/reviews/me and GET /store/products/:id/reviews/me to show account-level and product-level review history.

Troubleshooting

401 Unauthorized on store review routes

  • Cause: missing customer auth for protected endpoints (/store/reviews, /store/reviews/me, /store/products/:id/reviews/me).
  • Fix: include customer JWT (or session cookie) and publishable API key where applicable.

409 You have already reviewed this product...

  • Cause: duplicate review with multiple_rating disabled.
  • Fix: enable multiple_rating: true or update existing review via PUT /store/reviews/:id.

You must purchase the product before submitting a review

  • Cause: verify_purchase enabled and no completed order match.
  • Fix: disable verify flag or ensure customer has completed order with that product.

Product rating not updating as expected

  • Cause: only approved reviews affect rating calculation.
  • Fix: approve reviews (POST /admin/reviews/:id) or ensure workflow recalculation step runs for the transition.

Database connection not available

  • Cause: underlying manager/knex unavailable in service calls.
  • Fix: verify module registration and Medusa DB bootstrap; rerun server and check plugin loading.

Missing review table or rating columns

  • Cause: migration not executed.
  • Fix: run npx medusa db:migrate.