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

@mushi-mushi/plugin-sdk

v0.4.0

Published

TypeScript SDK for building third-party Mushi Mushi plugins (webhook handlers + signature verification + typed events).

Readme

@mushi-mushi/plugin-sdk

Build third-party plugins for Mushi Mushi. Plugins are stand-alone HTTPS services that receive signed event webhooks from the Mushi platform and may optionally call back into the REST API to comment on, re-classify, or transition reports.

Why a webhook model?

A webhook server is a stronger isolation boundary than running plugin code inside the Mushi platform itself:

  • Plugin failures, timeouts, or memory leaks can't take down the host.
  • Plugin authors keep control of their language, deployment, and persistence.
  • The Mushi backend does not need to vet/audit plugin code at install time.
  • A plugin can be migrated, scaled, or rolled back independently of Mushi.

The trade-off is latency: the Mushi pipeline doesn't block on plugin acknowledgement (deliveries are async), so plugins that need synchronous mutation should call the REST API back from the handler.

Install

npm i @mushi-mushi/plugin-sdk

Quick start (Express)

import express from 'express'
import { createPluginHandler, expressMiddleware, createMushiClient } from '@mushi-mushi/plugin-sdk'

const mushi = createMushiClient({
  apiKey: process.env.MUSHI_API_KEY!,
  projectId: process.env.MUSHI_PROJECT_ID!,
})

const handler = createPluginHandler({
  secret: process.env.MUSHI_PLUGIN_SECRET!,
  on: {
    'report.created': async (e) => {
      console.log('New report', e.data)
    },
    'report.classified': async (e) => {
      const { classification } = e.data as { classification: { severity: string } }
      if (classification.severity === 'critical') {
        await mushi.comment((e.data as any).report.id, 'Auto-paged on-call.', { visibleToReporter: false })
      }
    },
  },
})

const app = express()
app.post('/mushi/webhook', expressMiddleware(handler))
app.listen(3000)

Quick start (Hono / Edge)

import { Hono } from 'hono'
import { createPluginHandler, honoHandler } from '@mushi-mushi/plugin-sdk/hono'

const handler = createPluginHandler({
  secret: process.env.MUSHI_PLUGIN_SECRET!,
  on: { '*': async (e) => console.log(e.event, e.deliveryId) },
})

const app = new Hono()
app.post('/mushi/webhook', honoHandler(handler))
export default app

Wire format

| Header | Value | |------------------------|----------------------------------------------------------------------| | X-Mushi-Event | Event name (e.g. report.created) | | X-Mushi-Signature | t=<unix-ms>,v1=<hex> — Stripe-style | | X-Mushi-Project | Project UUID | | X-Mushi-Plugin | Plugin slug (matches the marketplace listing) | | X-Mushi-Delivery | Per-delivery UUID; safe as an idempotency key |

The v1 signature is HMAC_SHA256(secret, "${t}.${rawBody}") in lowercase hex. Tolerance is 5 minutes by default and is verified in constant time.

Outbound HTTP utilities

The SDK ships two zero-dependency helpers used by every reference plugin:

withRetry(fn, opts)

Exponential back-off + bounded-additive jitter for outbound HTTP calls. Retries 429 (honouring Retry-After), 503, 504, other 5xx, and network errors; fails fast on other 4xx. Throw the raw Response object so the wrapper can read status + headers:

import { withRetry } from '@mushi-mushi/plugin-sdk'

const json = await withRetry(async () => {
  const res = await fetch(url, { method: 'POST', body })
  if (!res.ok) throw res                    // expose status + Retry-After
  return res.json()
}, { maxAttempts: 4, idempotencyKey: deliveryId })

assertFields(payload, required) / safeParseInbound(payload, required)

Two type-narrowing guards for inbound webhook payloads. assertFields throws TypeError; safeParseInbound returns { ok, data | error } for use at I/O boundaries.

Marketplace

Once your plugin is ready, submit it to the Mushi marketplace by opening a PR that adds your plugin.json manifest under apps/admin/src/marketplace/. A reviewer will validate the manifest, the public callback URL, and the requested API permissions before listing it.

Reference plugins

The Mushi monorepo ships open-source reference plugins built on this SDK; copy and adapt them as a starting point:

Project management / on-call

Chat / notifications

Error monitoring (mirrored writes)

Workflow

License

MIT