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

pleasenobugs

v0.2.0

Published

A feedback board for Nimiq mini apps: bugs and ideas, straight from your users. One tag, or a headless client.

Readme

pleasenobugs

The PleaseNoBugs widget: a feedback board in one tag, plus the headless client it is built on. Inside Nimiq Pay it signs with the user's wallet by itself; everywhere else it reads, and your app can hand it a signer.

One line, a button in the corner

<script src="https://unpkg.com/pleasenobugs"></script>
<please-no-bugs project="YOUR_PROJECT_ID" server="https://YOUR_SERVER" mode="floating"></please-no-bugs>

Three ways to show it

| mode | What it does | |---|---| | inline (default) | Fills the element. Give it a height, or it grows with its posts. | | floating | A round button in the corner. It opens on the tiles (bug, idea, review), with the board one tap under them. | | overlay | The board, right now. |

floating and overlay cover the whole screen on a phone. From 640 pixels wide they are a panel in the bottom-right corner instead, 375 wide and up to 640 tall, over a dimmed page; a click beside it or Escape closes it.

From a button of your own:

import { open } from 'pleasenobugs';
menuItem.onclick = () => open({ project: 'YOUR_PROJECT_ID', server: 'https://YOUR_SERVER' });

Attributes, properties and events

| Attribute | | |---|---| | project, server | Required. | | mode | inline, floating or overlay. | | lang | en, nl, de, or any code you supply strings for. Defaults to Nimiq Pay's language, then the page's. | | theme | auto (follows the phone), light, dark, pleasenobugs (dark purple, the website's look), nimiq (gradient tiles and buttons, light only). Every theme has the same shapes: painted tiles with a white glyph, the same badges; only the colours differ. shitti is the old name of pleasenobugs and still works. | | accent | One colour, e.g. #e84a5f. The text on it picks black or white by itself. | | app-name | What answers are signed with ("Shitti says"). Defaults to the project's name. | | name | A display name you already know, offered when the user chooses to show theirs. | | kinds | Which kinds to offer, of the ones your project takes: bug,idea,review by default. kinds="bug,idea" leaves reviews off the tiles and out of the list. | | screenshots | Who sees screenshots on bugs and ideas. On the board for everyone by default, each one only after its author ticks that everyone may see it. owners keeps them for your eyes only; off leaves the "Add a screenshot" button out. An unknown value counts as owners. The project's own rule (PNB_PROJECT_SCREENSHOTS on the server) wins when it is stricter. | | names | off leaves out "Show my name", so every post is anonymous. For a board on a public page. | | readonly | The board to read and scroll through, nothing else: no +, no votes (the count still shows), no "Sign in", and it never asks a wallet or sends a proof, not even inside Nimiq Pay. Every post shows as anonymous and without its screenshot, whatever its author chose, because a read-only board is usually shown somewhere other than the app its authors wrote for. | | demo | A board of sample posts in the page's memory, with no server: <please-no-bugs demo>. Voting and writing work, nothing is sent or stored, and a reload starts over. For trying the widget, or showing it off. | | screen | With demo only: hold one screen in view, button, tiles, board, write or sent. What the website's configurator uses to show the part you are changing. |

| Property | | |---|---| | signer | How to sign outside Nimiq Pay (below). | | appLogin | Your app's own login signature, so nobody signs twice (below). | | context | Sent with every bug report, to owners only: { version: '1.4.0' }. | | noise | Words common in your app, so "said already?" ignores them: ['nim', 'wallet']. | | strings | Override any text: { 'board.title': 'Ideas box' }. Keys are in src/i18n.ts. |

Events: pleasenobugs:posted (detail: { id, kind }) and pleasenobugs:close.

What your users see

Tapping + opens three tiles: Report a bug, Share an idea and Write a review. A review is one to five stars and a few words, shown on the board with the average on top, so people can see what others like about your app. One review per wallet.

A bug or an idea can carry a screenshot, shown on the board under the post, so everybody can see what is meant. Before picking one the user reads that everyone will see it and should check it for a balance, an address or a name; after picking, nothing is sent until they tick "I checked it: everyone may see this screenshot" under the picture. The widget redraws it as a JPEG before sending, which leaves the photo's location and camera details behind.

You see every screenshot in the sheet where you answer a post, and can take one off the board there while the post stays up, or hide the whole post. A screenshot is deleted by itself when you mark the post Done or Not doing, or when the post is thrown away. Taking one off stops it being shown; it cannot take it back from anybody who already saved it.

Approving first. On a project made with PNB_PROJECT_APPROVE=on, a new post waits until an owner approves it. Its author sees it on the board marked "Waiting for approval", and "Feedback sent!" says it shows once approved; nobody else sees it yet. Owners see it too, and approve it in the sheet where they answer it. Your own posts as an owner never wait.

With screenshots="owners" they stay yours alone, never the board and not even their author: the warning says so instead, and there is nothing to tick. Any screenshot sent without that tick keeps that promise, whatever you change later.

If your page has a Content Security Policy, screenshots on the board load as plain images from your server, so img-src needs your server next to connect-src.

Theming

The widget lives in a shadow root, so your CSS cannot break it. These custom properties cross that boundary on purpose and are the theming API:

please-no-bugs {
  --pnb-bg: #fff;            /* the page */
  --pnb-surface: #f4f4f7;    /* a card */
  --pnb-surface-2: #e8e8ef;  /* a chip or field inside a card */
  --pnb-sunken: #e8e8ef;     /* the Top/New trough */
  --pnb-line: #dcdce5;
  --pnb-text: #1b1b24;
  --pnb-text-quiet: #5a5a6b;
  --pnb-accent: #2563eb;
  --pnb-accent-fill: var(--pnb-accent);  /* what buttons are painted with; may be a gradient */
  --pnb-on-accent: #fff;
  --pnb-danger: #d23b2f;
  --pnb-bug: #e5484d;  --pnb-idea: #8b5cf6;  --pnb-review: #e9a00b;
  --pnb-planned: #8a8fb8;  --pnb-done: #21bca5;  --pnb-declined: #8a8fb8;
  --pnb-star: #f5a524;
  --pnb-tile-bug: var(--pnb-bug);        /* the three tiles; may be gradients */
  --pnb-tile-idea: var(--pnb-idea);
  --pnb-tile-review: var(--pnb-review);
  --pnb-tile-ink: #fff;                  /* the words on them */
  --pnb-sent: var(--pnb-bg);             /* behind "Feedback sent!" */
  --pnb-fab: var(--pnb-accent-fill);     /* the round floating button */
  --pnb-on-fab: var(--pnb-on-accent);    /* its glyph */
  --pnb-radius-panel: 16px;              /* the panel on a wide screen */
  --pnb-radius: 8px;
  --pnb-radius-sheet: 16px;
  --pnb-font: inherit;       /* your app's font */
  --pnb-z: 2147483000;       /* overlay and floating button */
  --pnb-inset-top: env(safe-area-inset-top, 0px);       /* what covers the screen's top */
  --pnb-inset-bottom: env(safe-area-inset-bottom, 0px); /* and its bottom */
}

Inside Nimiq Pay, set the two insets yourself if you measure Pay's bar. Pay draws its own bar over the page and env() cannot see it, so a full-screen board can end up underneath it. Only the overlay and the floating button use them; an inline board ignores both.

Reusing your app's own login

If your app already has users sign a fixed login message, hand that signature to the widget and nobody signs twice:

board.appLogin = { address, publicKey, signature, message: 'Sign in to My app' };

The project has to list that exact message first (loginMessages, through the dashboard or create-project --login-message). Set appLogin to null when the user logs out of your app.

Signing outside Nimiq Pay

Give the element a function that signs a message and says which address did. With the Nimiq Hub:

import HubApi from '@nimiq/hub-api';
const hub = new HubApi('https://hub.nimiq.com');
const hex = (b) => Array.from(b, (x) => x.toString(16).padStart(2, '0')).join('');

document.querySelector('please-no-bugs').signer = async (message) => {
  const r = await hub.signMessage({ appName: 'My app', message });
  return { address: r.signer, publicKey: hex(r.signerPublicKey), signature: hex(r.signature) };
};

Without a signer outside Nimiq Pay, the board is read-only and says so when somebody tries to post.

Headless

Everything the widget does goes through a client you can use directly, with no UI and no Preact:

import { createClient, sortPosts, createMatcher } from 'pleasenobugs/client';

const client = createClient({ server: 'https://YOUR_SERVER', project: 'YOUR_PROJECT_ID' });
const board = await client.board();          // never asks the wallet
if (board.ok) render(sortPosts(board.data.posts, 'top'));
await client.post({ id: crypto.randomUUID(), kind: 'idea', text: 'Dark mode' });   // asks once, then remembers
await client.post({ id: crypto.randomUUID(), kind: 'review', text: 'Love it', rating: 5 });
const shot = await client.shot(postId);      // the screenshot as a Blob: on the board, or yours as an owner
const src = client.shotUrl(postId);          // a board screenshot's address, for an <img>

Every call answers { ok: true, data } or { ok: false, status, error }, and never throws.

Try it

npm run build && npm run demo -w pleasenobugs

Opens a demo on http://localhost:5180 with a seeded board and three fake wallets to switch between. The demo server signs for them; nothing in the package does.