@mushi-mushi/node
The Mushi Mushi server-side SDK for Node.js apps. It forwards unhandled
exceptions, adds HTTP error handlers for Express, Fastify and Hono, and tags
each handler report with the request method, URL and trace context (W3C
traceparent and sentry-trace headers, when present). To attach a user, pass
userId to captureReport().
Install
pnpm add @mushi-mushi/nodeCreate a client
Every handler below takes the same client:
import { MushiNodeClient } from '@mushi-mushi/node'
export const client = new MushiNodeClient({
apiKey: process.env.MUSHI_API_KEY!,
projectId: process.env.MUSHI_PROJECT_ID!,
environment: process.env.NODE_ENV, // optional
release: process.env.GIT_SHA, // optional
})Express
import express from 'express'
import { mushiExpressErrorHandler } from '@mushi-mushi/node/express'
const app = express()
// …all your routes…
app.use(mushiExpressErrorHandler({ client })) // mount LAST so it sees every other routeFastify
import Fastify from 'fastify'
import { mushiFastifyPlugin } from '@mushi-mushi/node/fastify'
const app = Fastify()
mushiFastifyPlugin(app, { client })Hono
Hono’s onError must return a Response, so pass your own handler as the
second argument. Mushi Mushi reports the error, then calls it.
import { Hono } from 'hono'
import { mushiHonoErrorHandler } from '@mushi-mushi/node/hono'
const app = new Hono()
app.onError(mushiHonoErrorHandler({ client }, () => new Response('Server error', { status: 500 })))Process-level fallbacks
Attach uncaughtException + unhandledRejection hooks so nothing escapes:
import { attachUnhandledHook } from '@mushi-mushi/node'
attachUnhandledHook({ client })Programmatic submit
Use the client directly when you want to report outside the request cycle (cron jobs, queue workers, integration failures):
import { MushiNodeClient } from '@mushi-mushi/node'
const mushi = new MushiNodeClient({
apiKey: process.env.MUSHI_API_KEY!,
projectId: process.env.MUSHI_PROJECT_ID!,
environment: 'production',
release: process.env.GIT_SHA,
})
await mushi.captureReport({
description: 'Refund webhook returned 500',
severity: 'high',
component: 'billing',
metadata: { invoiceId, attempt },
})The Node SDK sends to the same API as the web SDK, so server-thrown bugs and user-side bugs land in the same queue.
PII and credential scrubbing
Every description, url, and error.message value is passed through the
core PII scrubber before it leaves the process:
- JWT-shaped tokens (three dot-separated
eyJ…segments, regardless of header scheme) are redacted to[REDACTED_JWT]. - Emails, phone numbers and similar patterns are replaced with
[REDACTED_EMAIL],[REDACTED_PHONE], and friends. - Sensitive query-string keys (
token,api_key,password,secret, …) have their values replaced with[Scrubbed].
This applies to captureReport, mushiExpressErrorHandler, and
mushiTraceMiddleware, with no extra configuration.
If you use Authorization: Token <jwt> (Conduit / RealWorld spec), the JWT in
that header is never captured: the SDK only reads response status codes and
timing from network spans, not request headers.
The following fields are scrubbed before the report leaves the Node process:
| Field | Scrubber applied |
|---|---|
description | PII scrub (emails, phones, JWTs, SSNs, CC-shaped strings) |
environment.url | URL scrub (sensitive query-param keys and value patterns) |
error.message | PII scrub |
error.stack | PII scrub |
request.url (trace middleware) | URL scrub |
userId and host-supplied metadata are left unmodified. The SDK cannot know
which IDs or metadata keys are safe to alter, so the host is responsible for any
additional scrubbing at those sites.