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/web

v1.22.3

Published

Mushi Mushi browser SDK — embeddable bug reporting widget with Shadow DOM isolation

Readme

@mushi-mushi/web

Your AI wrote it. Mushi tells you why it broke.

Framework-agnostic browser SDK for Mushi Mushi — an embeddable bug-reporting widget that captures a screenshot, the route, the user's note, and the last few seconds of console + network activity, then hands you a plain-English diagnosis in your editor. Renders inside a Shadow DOM, so your CSS never leaks in or out.

One-command setup: npx mushi-mushi installs this package for vanilla-JS apps (or alongside a framework SDK).

Framework SDKs: @mushi-mushi/react (Next.js / React) · @mushi-mushi/vue · @mushi-mushi/svelte · @mushi-mushi/angular · @mushi-mushi/react-native · @mushi-mushi/capacitor

Install

npm install @mushi-mushi/web
# or: npx mushi-mushi

Quick start

import { Mushi } from '@mushi-mushi/web';

Mushi.init({
  projectId: 'proj_xxx', // UUID from Admin → Projects
  apiKey: 'mushi_xxx',   // report:write key from Admin → Settings → API Keys
  widget: { position: 'bottom-right', theme: 'auto' },
  capture: { console: true, network: true, screenshot: 'on-report' },
});

That's the whole integration. A floating 🐛 launcher appears; a report is one click away.

What you get

  • Shadow-DOM widget — full CSS isolation, light/dark auto-theme, keyboard-first (Esc / ⌘+Enter), honours prefers-reduced-motion.
  • Capture — screenshot, console ring buffer, network (fetch interceptor), Web Vitals, and a repro timeline of routes + clicks.
  • Resilient by default — IndexedDB offline queue with auto-sync, on-device spam pre-filter, client-side rate limiting, and a payload-size guard that degrades gracefully instead of wedging the queue.
  • Never blocks your UI — the host element is zero-sized with pointer-events: none; only the visible controls opt back in. Verify at runtime with Mushi.diagnose().
  • Privacy-first — selector-level screenshot masking/blocking, a one-tap "Remove screenshot" control, and a built-in PII scrubber.

Trigger modes

Choose where and when the launcher shows — auto, edge-tab, attach (bring your own button), manual, or hidden — plus viewport-aware smartHide, route/selector suppression, and anchor CSS that tracks your app shell's tab bars or mini-players.

// Bring your own launcher — Mushi injects no UI of its own.
const mushi = Mushi.init({
  projectId: 'proj_xxx',
  apiKey: 'mushi_xxx',
  widget: { trigger: 'attach', attachToSelector: '[data-mushi-feedback]' },
});
mushi.attachTo('#support-menu-feedback');

→ Full posture matrix in Trigger modes. Coherent defaults via SDK presets (production-calm / beta-loud / internal-debug / manual-only).

Mushi.init({
  projectId: 'proj_xxx',
  apiKey: 'mushi_xxx',
  proactive: {
    rageClick: true,
    longTask: true,
    apiCascade: true,
    errorBoundary: true, // catch global error / unhandledrejection
    cooldown: { maxProactivePerSession: 2, dismissCooldownHours: 24, suppressAfterDismissals: 3 },
  },
});

Each trigger respects its config flag (set rageClick: false to disable). Fatigue prevention (session limits, cooldowns, permanent suppression) is always on.

Mushi.init({
  projectId: 'proj_xxx',
  apiKey: 'mushi_xxx',
  privacy: {
    maskSelectors: ['[data-private]', 'input'],   // painted over before serialisation
    blockSelectors: ['[data-payment]', '[data-auth-token]'], // removed entirely
    allowUserRemoveScreenshot: true,              // one-tap "Remove screenshot" in panel
  },
});

The details step renders the attached screenshot as a visible preview (not just a checkmark) with a Remove control and a configurable privacy caption (widget.screenshotSensitiveHint). A "Mark up" overlay lets reporters highlight / blur / arrow before submitting.

Mushi.init({
  projectId: 'proj_xxx',
  apiKey: 'mushi_xxx',
  capture: {
    // 'rrweb' — full DOM replay (lazy-loaded; text + inputs masked by default)
    // 'lite'  — dependency-free coarse fallback
    // 'sentry'— reuse an installed @sentry/replay session
    // 'off'   — default
    replay: 'rrweb',
  },
});

Records continuously from init (so you capture the moments before the report), trimmed to a rolling window. Already on Sentry Replay? See coexistence.

const mushi = Mushi.init({ projectId: 'proj_xxx', apiKey: 'mushi_xxx' });

mushi.identify('usr_42', { email: '[email protected]', segment: 'beta' });
mushi.setTags({ plan: 'pro', region: 'apac' });
mushi.addBreadcrumb({ category: 'business', message: 'cart.checkout_started', data: { itemCount: 3 } });

try {
  await runCheckout();
} catch (err) {
  // Normalises any throw, attaches breadcrumbs + sticky tags + Sentry context.
  mushi.captureException(err, { level: 'error', tags: { surface: 'checkout' } });
}

installAutoBreadcrumbs() ships route changes, console.error/warn, and [data-testid] clicks for free. PII is scrubbed before anything leaves the browser. Auto-detects @sentry/browser v7–v9 and captures the active scope into MushiReport.sentryContext, with deep-links both ways.

The widget's "Your reports" tab lets reporters see team replies and respond, signed via HMAC against the public API key (no auth user required): mushi.listMyReports(), mushi.listMyComments(id), mushi.replyToReport(id, text). Call mushi.identify() and add a rewards block to track activity, tiers, and points. See Rewards & contributor identity.

const mushi = Mushi.init({
  projectId: 'proj_xxx',
  apiKey: 'mushi_xxx',
  // 'auto' (default) skips the runtime-config fetch on localhost endpoints;
  // pass `true` to force everywhere, `false` to disable entirely.
  runtimeConfig: 'auto',
  capture: { network: true, ignoreUrls: [/\/api\/internal\//] },
  proactive: { apiCascade: { enabled: true, ignoreUrls: ['https://feature-flags.example.com'] } },
});

mushi.show();
mushi.hide();
mushi.setTrigger('manual');          // switch posture at runtime
mushi.openWith('bug');               // open straight into a category
mushi.attachTo('#support-menu');     // bind the launcher to your element

Internal Mushi requests are tagged X-Mushi-Internal and excluded from network capture + apiCascade, so an unconfigured CSP or a flaky local Supabase stack can never make Mushi report on Mushi. For advanced composition, createProactiveManager() and setupProactiveTriggers() are exported so you can wire friction detection into your own UI.

const mushi = Mushi.init({ /* ... */ });
mushi.setScreen({ name: 'Chat', route: '/chat', feature: 'roleplay' });

The SDK auto-records route changes (pushState / popstate / hashchange), clicks (with selector + text snippet), and screen events into a 120-entry ring buffer, shipped as MushiReport.timeline. The admin renders it as a chronological "what happened before the report" card.

Mushi.init({
  projectId: 'proj_xxx',
  apiKey: 'mushi_xxx',
  widget: {
    trigger: 'banner',
    bannerConfig: {
      variant: 'brand',          // 'neon' | 'brand' | 'subtle'
      position: 'top',
      message: 'Mushi is in beta — spotted something off? Tell us.',
      label: 'Beta',             // pill before the message; `false` hides it
      bugCta: '🐛 Report a bug',
      featureCta: true,
      links: [{ label: 'My submissions', href: 'https://app.example.com/feedback' }],
    },
  },
});

All banner text renders via textContent (never HTML), so CMS-sourced copy can't inject markup. message and label can also be driven remotely per project from the dashboard runtime config — change copy without a deploy.

Mushi.init({
  projectId: 'proj_xxx',
  apiKey: 'mushi_xxx',
  capture: {
    discoverInventory: {
      enabled: true,
      throttleMs: 60_000,
      routeTemplates: ['/practice/[id]', '/lessons/[slug]'],
    },
  },
});

Ships throttled, PII-free observations (route template, page title, [data-testid] values, recent fetch paths, query-param keys only, hashed user/session id) to POST /v1/sdk/discovery. The server aggregates them and drafts a first-pass inventory.yaml you can accept in /inventory ▸ Discovery. See Inventory & gates.

Host pass-through contract

Mushi never blocks your app's UI. The host element (#mushi-mushi-widget) is position: fixed, zero-sized, with pointer-events: none — only the visible controls opt back into pointer-events: auto inside the Shadow DOM. In native WebView shells (iOS WKWebView, some Android Chromium builds) where pointer-events: none isn't always honoured on fixed overlays, use hideOnSelector or Mushi.hide() during fullscreen flows. Verify at runtime:

const health = await Mushi.diagnose();
console.assert(health.widgetHostPointerSafe, 'Mushi host is blocking UI!');

Health check

const health = await Mushi.diagnose();
// → { apiEndpointReachable, cspAllowsEndpoint, widgetMounted, widgetHostPointerSafe, ... }

Runs before Mushi.init() too — call it from a debug console or installer wizard to surface CSP / endpoint problems with zero risk of booting the widget.

Test utilities

Deterministic Playwright / jsdom helpers, published as a separate entry-point so production bundles pay nothing for them:

import { triggerBug, openReport, waitForQueueDrain, expectMushiReady } from '@mushi-mushi/web/test-utils';

Every helper no-ops when Mushi.getInstance() returns null, so cloud-vs-local conditional-wiring tests don't need a branch.

Known limitations

Screenshot capture uses canvas / SVG foreignObject serialization — it does not work with cross-origin iframes, tainted <canvas> elements, or pages with strict CSP. Best-effort on single-origin SPAs.

Bundle size

~7 KB brotli, enforced at 80 KB gzipped (105 KB uncompressed) in CI. Requires @mushi-mushi/core (installed automatically, not bundled inline). The widget's visual system — washi paper, sumi ink, vermillion 朱 accent, system serif — lives in src/styles.ts.

License

MIT


Monorepo scale (June 2026): 51 edge functions · 298 SQL migrations · 13 outbound plugins · 11 inbound adapters · 19 pipeline agents. Canonical counts: docs/stats.md · pnpm docs-stats