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-live-chat

v0.0.2

Published

A starter for Medusa plugins.

Readme

Medusa Live Chat Plugin

medusa-live-chat is a Medusa v2 plugin that provides customer-admin chat with:

  • direct channels between customer and admin users
  • REST APIs for store and admin scopes
  • realtime event gateway abstraction (Socket.IO-ready)
  • unread tracking based on last_read_at
  • offline notification integration via Medusa notification module
  • admin extension page for channel/thread/composer

Compatibility

  • @medusajs/medusa 2.12.x
  • Node >=20

Feature Overview

  • Channel model
    • deterministic direct channel hash (direct:<idA>:<idB>)
    • single channel reused per customer-admin pair
  • Message model
    • supports text, meeting, system types
    • create/read/edit/delete endpoints
  • Read state
    • per-member last_read_at
    • unread counts derived from message timestamps
  • Realtime
    • user room pattern: user:{id}
    • event envelope supports event_id, channel_id, message_id, ts
  • Fallback notifications
    • when recipient is offline, plugin triggers notification module calls
  • Digest job
    • periodic unread summary sender (chat-unread-digest)

Configuration

Use a central src/config.ts and read runtime values from there.

1) Create src/config.ts

export type ChatConfig = {
  chat_v1_enabled: boolean
}

export const chatConfig: ChatConfig = {
  chat_v1_enabled: true,
}

export function setChatConfig(input: Partial<ChatConfig>): void {
  if ("chat_v1_enabled" in input) {
    chatConfig.chat_v1_enabled = input.chat_v1_enabled === false ? false : true
  }
}

2) Register plugin in your Medusa app medusa-config.ts

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

export default defineConfig({
  plugins: [
    {
      resolve: "medusa-live-chat",
    },
  ],
})

3) Update chat config in src/config.ts

Set chat_v1_enabled directly in src/config.ts or call setChatConfig(...).

Behavior:

  • default is true
  • it becomes false only when chat_v1_enabled === false
  • all other values keep it enabled

When chat_v1_enabled is false, chat routes return Chat is disabled.

Data Model

Migration creates:

  • chat_channel
    • id, channel_hash (unique), type, last_message_at, timestamps
  • chat_channel_member
    • id, channel_id, user_id, role, last_read_at, notified_at, timestamps
    • unique (channel_id, user_id)
    • membership tracks customer/guest participants (admins are global operators and are not added by default)
  • chat_message
    • id, channel_id, sender_id, body, message_type, edited_at, deleted_at, timestamps
    • indexes on (channel_id, created_at) and (sender_id, created_at)

API Endpoints

Admin (/admin/chat/*)

  • GET /admin/chat/channels
  • POST /admin/chat/channels
  • PUT /admin/chat/channels/:channelHash/read
  • GET /admin/chat/messages/:channelHash
  • POST /admin/chat/messages/:channelHash
  • PUT /admin/chat/messages/id/:messageId
  • DELETE /admin/chat/messages/id/:messageId
  • GET /admin/chat/messages/unread-count

Auth rule: actor_type must be user.

Admin behavior:

  • any authenticated admin can list all channels from GET /admin/chat/channels
  • any authenticated admin can open any channel thread
  • any authenticated admin can send messages in any channel from POST /admin/chat/messages/:channelHash
  • PUT /admin/chat/channels/:channelHash/read works in admin scope without requiring channel membership
  • GET /admin/chat/messages/unread-count uses shop_staff scope: counts customer/guest messages in all direct channels for the logged-in admin user, using last_read_at on that user’s channel membership when present (membership is created when the admin marks a channel read)

Store (/store/chat/*)

  • GET /store/chat/channels
  • POST /store/chat/channels
  • PUT /store/chat/channels/:channelHash/read
  • GET /store/chat/messages/:channelHash
  • POST /store/chat/messages/:channelHash
  • PUT /store/chat/messages/id/:messageId
  • DELETE /store/chat/messages/id/:messageId
  • GET /store/chat/messages/unread-count

Auth rule:

  • authenticated requests use auth_context.actor_id (customer session)
  • logged-out requests must send guest_id_for_live_chat header
  • if both are absent, route returns unauthorized
  • POST /store/chat/channels accepts optional admin_id; when omitted, a default admin key is used
  • GET /store/chat/channels enriches each channel with admin_id and admin (when user data can be resolved)

Core Service Contracts

Implemented in src/modules/chat/service.ts:

  • getOrCreateDirectChannel(customerId, adminId)
  • sendMessage({ channelId, senderId, body, type })
  • sendMessageAsAdmin({ channelId, senderId, body, type })
  • listUserChannels(userId, { search, limit, offset })
  • listAllChannels({ search, limit, offset })
  • getMessages(channelId, { cursor, direction, limit })
  • markChannelRead(channelId, userId, at?)
  • markChannelReadAsAdmin(channelId, userId, at?)
  • editMessage(messageId, userId, body)
  • deleteMessage(messageId, userId)
  • getUnreadCount(userId, mode?)participant (default, storefront) or shop_staff (admin + digest job)

Business checks:

  • sender must be channel member
  • admin send in admin scope can bypass channel membership
  • admin mark-read creates an admin membership row if needed and persists last_read_at
  • edit/delete allowed only to message author
  • channel search must be at least 3 characters

Realtime Events

Gateway lives at src/modules/chat/realtime/gateway.ts.

Event names:

  • chat.message.created
  • chat.message.updated
  • chat.message.deleted
  • chat.channel.read

Envelope shape:

{
  "event_id": "evt_or_message_id",
  "channel_id": "chat_channel_id",
  "message_id": "optional_message_id",
  "ts": "2026-03-26T12:00:00.000Z",
  "payload": {}
}

Admin UI

Admin extension route:

  • /app/chat

Includes:

  • channel search/list
  • create/open channel by customer ID
  • unread counter
  • thread view
  • mark selected channel as read
  • message composer (send)
  • message edit/delete actions

Jobs

  • src/jobs/chat-unread-digest.ts
    • iterates users
    • checks unread count
    • sends digest via notification module

Development

Install dependencies:

npm install

Build plugin:

npm run build

Run tests:

npm run test

Tests

Table-driven tests are included:

  • src/modules/chat/__tests__/utils.test.ts
  • src/modules/chat/__tests__/service.test.ts
  • src/modules/chat/realtime/__tests__/gateway.test.ts
  • src/api/_shared/__tests__/chat.test.ts
  • src/api/store/chat/channels/__tests__/route.test.ts
  • src/api/store/chat/messages/[channelHash]/__tests__/route.test.ts
  • src/api/admin/chat/channels/__tests__/route.test.ts
  • src/api/admin/chat/channels/[channelHash]/read/__tests__/route.test.ts
  • src/api/admin/chat/messages/[channelHash]/__tests__/route.test.ts
  • src/api/admin/chat/messages/unread-count/__tests__/route.test.ts

Notes

  • Routes are intentionally thin and delegate business logic to module service.
  • Notification sending uses Medusa notification module integration (create / createNotifications).
  • For production rollout, add provider-specific email templates for:
    • chat_unread_message
    • chat_daily_digest