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

@signiflydev/feedback-widget

v0.5.0

Published

Signifly feedback widget — activation-link gated, native screenshot capture, reports into signi-ops

Readme

@signiflydev/feedback-widget

The canonical client-facing feedback capture channel (spec #443, decisions #430/#438/#439). Embedded in Signifly-built sites; files Feedback Reports into signi-ops against the site's Service.

How it works

  • Invisible by default. The widget renders nothing unless the device has been activated. End users never see it.
  • A launcher that keeps out of the way. Once revealed it is a 48px circle carrying the same message-square icon signi-ops uses for Feedback; hovering or focusing it widens that same button back out to the labelled pill, and opening the panel holds it open. There is no hover on a phone, so there it stays a circle — the accessible name is on the button either way. Where it sits is the install's choice: any of the four corners, or a free position in CSS lengths. See Placement below.
  • Activation links. signi-ops issues personal signed links (https://clientsite.com?signifly-feedback=<token>). Opening one signs the reporter in passwordlessly (Supabase session minted server-side), sets a long-lived device cookie, and reveals the widget. Links are revocable per person from signi-ops → Settings → Feedback widget.
  • Real pixels. Desktop capture uses native getDisplayMedia (share-this-tab, preferCurrentTab) — a single real frame of exactly what the reporter sees. DOM-rendering libraries are deliberately not used (#439). Attaching an image file is offered alongside it on every platform, not just mobile: since 0.4.0 a screenshot is required, and a dismissed share dialog, a host page withholding display-capture, or an insecure context would otherwise lock the reporter out of reporting at all.
  • Annotate + describe. Arrow, box, circle, freehand and text over the screenshot, with undo/redo and a text mark you can click to retype. On desktop the marks are made in a fullscreen overlay (the inline canvas stays arrow-only — at thumbnail scale a placed mark lands where nobody meant it); below 640px the panel becomes a sheet with a Screenshot tab and a Details tab. Plus kind (bug / feature request), title, and description.
  • Title, description and screenshot are required as of 0.4.0 — enforced in the widget, not at the ingest. Client repos pin an exact version (#438), so postBodySchema must keep accepting everything every deployed widget can send; tightening it would 400 un-bumped sites with a failure that looks like an outage. See signi-ops ADR-0040.
  • Authenticated ingest. Reports submit through the reporter's Supabase session against the signi-ops feedback ingest (ADR-0006 / ADR-0007). The public site key does two jobs only: routes the report to its Service and gates the request origin. Without a session, a site-key-only fallback still accepts the report, flagged unverified.
  • Browser metadata (user agent, viewport, locale, timezone, page URL/title, widget version) is captured automatically, including recent console.warn/console.error output and uncaught errors.

Install

Public npm (root ADR-049). No registry configuration, no token, nothing to arrange:

pnpm add @signiflydev/[email protected]

Client repos pin an exact version — each release rolls out as a bump PR gated by that repo's CI and Vercel preview, and there is deliberately no CDN-latest (decision #438).

Inside this monorepo the dependency is workspace:* instead, so changes to the widget are picked up without a release and no registry is involved at all.

import { initFeedbackWidget } from "@signiflydev/feedback-widget"

initFeedbackWidget({
  siteKey: "sfk_…", // from signi-ops → Settings → Feedback widget
  apiBase: "https://ops.signifly.com",
})

Or as a script tag (IIFE build):

<script
  src="/vendor/feedback-widget.iife.js"
  data-site-key="sfk_…"
  data-api-base="https://ops.signifly.com"
  defer
></script>

Pin an exact version in client repos. Releases roll out as automated version-bump PRs gated by each repo's CI and preview — never CDN-latest (#438).

Placement

placement says where the launcher sits. It defaults to "bottom-right", which is where every install had it before the option existed, so leaving it out changes nothing.

initFeedbackWidget({
  siteKey: "sfk_…",
  apiBase: "https://ops.signifly.com",
  placement: "top-left", // or bottom-left, top-right, bottom-right
})

For a site whose own furniture is already in all four corners, pass CSS lengths instead — plain numbers are pixels, and anything CSS accepts as a length (%, rem, vh, calc()) is passed through:

initFeedbackWidget({
  siteKey: "sfk_…",
  apiBase: "https://ops.signifly.com",
  placement: { bottom: "50%", left: 24 },
})

Only one side of each pair survives — top beats bottom, left beats right — because the launcher has no width of its own and naming both would stretch it across the viewport. A length in a unit the widget will not vouch for is refused rather than escaped, and the launcher falls back to the default corner: it goes into a stylesheet inside the shadow root, and a launcher nobody can find is worse than one in the wrong place.

The panel is anchored to the launcher wherever that ends up — it takes the launcher's nearer horizontal edge and opens away from the nearer vertical one, so a top placement drops down and a bottom one rises. Below 640px it is still a full-screen sheet regardless.

The script tag takes the same choice as data-placement, or as named sides for a free position (data-top, data-right, data-bottom, data-left). A named side wins over a corner:

<script
  src="/vendor/feedback-widget.iife.js"
  data-site-key="sfk_…"
  data-api-base="https://ops.signifly.com"
  data-placement="bottom-left"
  defer
></script>

signi-ops asks for the corner when it opens the install PR (Feedback → Roll out), stores it on the Service, and writes it into the generated signifly-feedback.ts — so a re-run of that PR does not quietly move the launcher back.

Registry

Published to the public npm registry as @signiflydev/feedback-widget (root ADR-049, superseding ADR-048).

Releasing is merging. Bump version here and WIDGET_VERSION in apps/signi-ops/lib/onboarding/widget-release.ts — a test asserts they match — and .github/workflows/feedback-widget-release.yml publishes once that lands on main. It skips versions npm already has, so a README fix does not try to republish. There is no NPM_TOKEN: CI authenticates by OIDC trusted publishing, which also attaches a provenance attestation naming the commit that built the tarball.

Publishing by hand needs an npm account with publish rights on the scope, and should be a recovery path rather than the route:

pnpm --filter @signiflydev/feedback-widget build
cd packages/feedback-widget && npm publish --otp=<code>

The package contains no secrets. The site key is public by design, and files limits the published tarball to dist — the same compiled JavaScript already bundled into the public JS of every site that embeds the widget. The TypeScript source stays in this repository, which is private.

Development

pnpm --filter @signiflydev/feedback-widget test        # vitest (pure seams)
pnpm --filter @signiflydev/feedback-widget typecheck
pnpm --filter @signiflydev/feedback-widget build       # esbuild ESM + IIFE, d.ts via tsc