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

@olinux68/bug-report

v0.5.0

Published

Floating 🐞 bug-report widget + optional self-hosted email backend. Drop-in, independent.

Readme

@olinux68/bug-report

Floating 🐞 bug-report button + modal. Zero-dependency, configurable, drop-in.

Adds a small floating button to any page. Clicking it opens a modal where users write what went wrong and optionally attach a screenshot; the report is POSTed to your endpoint. No backend is bundled β€” you point it at your own infra.

Features

  • Zero runtime dependencies β€” vanilla JS, styles injected automatically.
  • Two integration modes β€” modern import or a plain <script> tag.
  • fr / en built-in labels, every label overridable.
  • Themable accent/background/text colors.
  • Optional image β€” attach a file, or capture the screen (getDisplayMedia, desktop; the button auto-hides where unsupported).

Install

npm install @olinux68/bug-report

Usage β€” with a bundler

import { mountBugReport } from '@olinux68/bug-report';

mountBugReport({
  endpoint: 'https://your-site.example/api/bug', // your infra
  lang: 'fr',
});

No CSS to import β€” the widget injects its own styles.

Usage β€” static <script>

Copy bug-report.config.example.js to bug-report.config.js, fill in your endpoint, then include both scripts (config first):

<script>
  window.BUG_REPORT_CONFIG = {
    endpoint: 'https://your-site.example/api/bug',
    lang: 'fr',
  };
</script>
<script src="https://unpkg.com/@olinux68/bug-report"></script>

The widget auto-mounts when window.BUG_REPORT_CONFIG.endpoint is present.

Options

| Option | Type | Default | Purpose | |--------------|-------------------|------------------|---------| | endpoint | string | β€” (required) | URL the report is POSTed to (your infra) | | token | string | '' | Optional; sent as Authorization: Bearer <token> | | lang | 'fr' | 'en' | 'fr' | Built-in label language | | position | string | 'bottom-right' | Button anchor corner | | theme | object | dark theme | Colors: { accent, bg, text } | | texts | object | labels for lang| Override individual labels | | screenshot | boolean | true | Allow attaching an image file | | screenCapture | boolean | true | Show a "capture screen" button where getDisplayMedia is supported (desktop). Hidden on unsupported browsers (most mobiles), which keep the file attach. | | format | 'multipart'|'json' | 'multipart' | Request body format | | fields | object | identity | Rename wire fields: { message, page, userAgent, screenshot } | | extraFields| object | function| β€” | Extra fields merged at send time (function is evaluated then) | | pageValue | 'href'|'pathname' | 'href' | What to send as page | | uaMaxLen | number | null | null | Truncate the user agent | | minLength | number | 1 | Minimum message length | | imageMaxDim| number | 1000 | JSON mode: resize longest side before base64 | | imageQuality| number | 0.7 | JSON mode: JPEG quality |

Precedence: options passed to mountBugReport() win over window.BUG_REPORT_CONFIG, which wins over the built-in defaults.

Adapting to an existing server

By default the widget sends multipart/form-data. To plug it into a server that already expects a specific JSON shape β€” without changing that server β€” use format, fields and extraFields. Example matching a server that expects POST /api/bug-report with JSON { desc, page, ua, image, pseudo }:

mountBugReport({
  endpoint: '/api/bug-report',
  format: 'json',
  fields: { message: 'desc', userAgent: 'ua', screenshot: 'image' },
  pageValue: 'pathname',
  uaMaxLen: 160,
  minLength: 5,
  extraFields: () => {
    try { return { pseudo: JSON.parse(localStorage.getItem('chat_profile') || '{}').pseudo || '' }; }
    catch { return {}; }
  },
});

In JSON mode an attached screenshot is resized and sent as a base64 data URL (the value of the mapped screenshot field).

Server contract

The widget sends POST {endpoint} as multipart/form-data:

| Field | Notes | |--------------|-------| | message | the user's text (required) | | page | current page URL (auto) | | userAgent | browser UA (auto) | | screenshot | file, only when attached |

When token is set, an Authorization: Bearer <token> header is added. Any 2xx response is treated as success. The response body is not inspected β€” your server does whatever it wants.

Self-hosted email backend (independent, no external service)

The same package ships an optional backend so reports land in your inbox, sent by your own server β€” no third-party service, nothing to sign up for. It emails via the machine's local MTA (sendmail/Exim) by default, or SMTP if you set SMTP_*.

Mount it on your existing Express app in one line:

import express from 'express';
import { attachBugReport } from '@olinux68/bug-report/server';

const app = express();
app.use(express.json());
attachBugReport(app, { to: '[email protected]' }); // POST /bug-report β†’ emails you
app.listen(3000);

Point the widget at it (JSON mode):

<script>
  window.BUG_REPORT_CONFIG = { endpoint: '/bug-report', format: 'json' };
</script>
<script src="https://unpkg.com/@olinux68/bug-report"></script>

attachBugReport(app, opts) / createBugReportHandler(opts) options:

| Option | Default | Purpose | |--------|---------|---------| | to | β€” (required) | recipient email | | from | bug-report@localhost | From header | | path | /bug-report | route (attachBugReport only) | | max | 20 | reports per minute per IP | | maxImageBytes | 1500000 | screenshot size cap | | smtp | β€” | {host,port,secure,auth}; else local sendmail |

Email delivery: local MTA first (sendmail), SMTP fallback when smtp (or SMTP_HOST/SMTP_PORT/SMTP_SECURE/SMTP_USER/SMTP_PASS) is set. nodemailer is the only backend dependency; the widget stays dependency-free.

License

MIT