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

@groo.dev/feedback-sdk

v0.5.0

Published

React widget components and Hono proxy middleware for integrating the feedback system.

Readme

@groo.dev/feedback-sdk

Embed a feedback widget into any React application. Users can submit bug reports, feature requests, and general feedback — then track their submissions and see admin responses.

Pairs with a Hono route handler that keeps your API key server-side, handles auth, and injects user identity automatically.

Install

npm install @groo.dev/feedback-sdk

Quick Start

1. Add the proxy route to your Hono API worker

import { feedbackRoute } from '@groo.dev/feedback-sdk/hono'
import { createAuth } from './auth' // your auth

app.route('/api/@groo.dev/feedback', feedbackRoute({
  apiBase: 'https://feedback.miranet.work/v1/sdk',
  getApiKey: (env) => env.FEEDBACK_API_KEY,
  getUser: async (c) => {
    const session = await getSession(c) // your auth logic
    if (!session) return null
    return { id: session.user.id, name: session.user.name, email: session.user.email }
  },
}))

Add FEEDBACK_API_KEY to your .dev.vars (local) and worker secrets (production).

2. Add a widget to your React app

import { FeedbackFloating } from '@groo.dev/feedback-sdk/react'

function App() {
  return (
    <>
      {/* your app */}
      <FeedbackFloating apiBase="/api/@groo.dev/feedback" />
    </>
  )
}

That's it. A floating button appears in the bottom-right corner. Users can submit feedback and view their past submissions.

Proxy Route

feedbackRoute() creates a complete Hono sub-app that handles auth, user identity injection, and request forwarding. You provide three things:

import { feedbackRoute } from '@groo.dev/feedback-sdk/hono'

app.route('/api/@groo.dev/feedback', feedbackRoute({
  apiBase: 'https://feedback.miranet.work/v1/sdk',
  getApiKey: (env) => env.FEEDBACK_API_KEY,
  getUser: async (c) => { ... },
}))

| Option | Type | Description | |--------|------|-------------| | apiBase | string | Feedback API URL | | getApiKey | (env) => string | Extracts API key from worker env | | getUser | (c) => Promise<User \| null> | Extracts authenticated user from request. Return null to reject. |

The User object must have id, name, and email fields.

Routes handled

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /health | No | Health check — verifies proxy is mounted | | POST | /feedback | Yes | Submit feedback | | GET | /feedback | Yes | List user's own feedback | | GET | /feedback/:id | Yes | Feedback detail with comments | | POST | /attachments | Yes | Upload file attachment | | GET | /attachments/:id | Yes | Download attachment |

How it works

  1. getUser is called on every request (except /health)
  2. If it returns null, the request is rejected with 401
  3. The user's identity is injected into the request (body or query param)
  4. The request is forwarded to the feedback API with your API key
  5. The React components never see user identity or the API key

React Components

All components accept a shared apiBase prop (the proxy URL) and an optional prefill for pre-populating the form.

type FeedbackProps = {
  apiBase: string
  prefill?: {
    type?: 'bug' | 'feature' | 'general'
    title?: string
    description?: string
  }
}

<FeedbackFloating />

Fixed floating button in the bottom-right corner. Opens a modal on click. Drop it in your root layout — visible on every page.

<FeedbackFloating apiBase="/api/@groo.dev/feedback" />

// With prefill
<FeedbackFloating
  apiBase="/api/@groo.dev/feedback"
  prefill={{ type: 'bug' }}
/>

<FeedbackButton />

An inline button you place anywhere — nav bar, help menu, footer. Renders children as the button content.

<FeedbackButton
  apiBase="/api/@groo.dev/feedback"
  className="btn btn-secondary"
>
  Report an Issue
</FeedbackButton>

<FeedbackContextual />

Controlled modal for programmatic triggers. Useful in error boundaries or catch blocks.

const [open, setOpen] = useState(false)

<FeedbackContextual
  apiBase="/api/@groo.dev/feedback"
  prefill={{
    type: 'bug',
    title: `Error on ${window.location.pathname}`,
    description: error.message,
  }}
  open={open}
  onClose={() => setOpen(false)}
/>

<FeedbackModal />

Headless controlled modal. You manage the open/close state entirely.

const [open, setOpen] = useState(false)

<button onClick={() => setOpen(true)}>Feedback</button>
<FeedbackModal
  apiBase="/api/@groo.dev/feedback"
  open={open}
  onOpenChange={setOpen}
/>

Auth Examples

Clerk

import { getAuth, clerkClient } from '@clerk/backend'

app.route('/api/@groo.dev/feedback', feedbackRoute({
  apiBase: 'https://feedback.miranet.work/v1/sdk',
  getApiKey: (env) => env.FEEDBACK_API_KEY,
  getUser: async (c) => {
    const auth = getAuth(c)
    if (!auth.userId) return null
    const user = await clerkClient(c.env).users.getUser(auth.userId)
    return {
      id: auth.userId,
      name: [user.firstName, user.lastName].filter(Boolean).join(' '),
      email: user.emailAddresses[0]?.emailAddress ?? '',
    }
  },
}))

Better Auth

import { createAuth } from './auth'

app.route('/api/@groo.dev/feedback', feedbackRoute({
  apiBase: 'https://feedback.miranet.work/v1/sdk',
  getApiKey: (env) => env.FEEDBACK_API_KEY,
  getUser: async (c) => {
    const auth = createAuth(c.env)
    const session = await auth.api.getSession({ headers: c.req.raw.headers })
    if (!session) return null
    return { id: session.user.id, name: session.user.name, email: session.user.email }
  },
}))

Theming

The widget uses CSS custom properties with a --fbk- prefix. Override any variable in your app's CSS to customize the look:

:root {
  --fbk-accent: #6366f1;       /* primary color (buttons, active states) */
  --fbk-accentHover: #818cf8;  /* primary hover */
  --fbk-bg: #0f0f12;           /* panel background */
  --fbk-surface: #1a1a1e;      /* elevated surface (comments, chips) */
  --fbk-text: #f0f0f0;         /* primary text */
  --fbk-muted: #888;           /* secondary text */
  --fbk-dim: #555;             /* placeholder text */
  --fbk-border: rgba(255,255,255,0.1);
  --fbk-error: #ef4444;
  --fbk-success: #22c55e;
  --fbk-radius: 4px;           /* border radius */
  --fbk-fontBody: 'Inter', sans-serif;
  --fbk-fontMono: 'JetBrains Mono', monospace;
}

All variables have sensible defaults (warm dark theme). You only need to override what you want to change.

Status colors

:root {
  --fbk-statusNew: #e8a849;
  --fbk-statusAcknowledged: #5b9bd5;
  --fbk-statusInProgress: #9b7ed8;
  --fbk-statusResolved: #5cb870;
  --fbk-statusClosed: #4a4e56;
}

License

MIT