About

Changelog

All notable changes are recorded here. The format follows Keep a Changelog and the project uses Semantic Versioning. Since 1.0 that is a promise rather than an intention: removing or renaming an export, an option or a data-* attribute needs a major version, and a new entry point needs a minor one.

Unreleased #

The freeze. 1.0 says what the next version number will mean: removing or renaming an export, an option or a data-* attribute needs a major version, a new entry point needs a minor one, and a patch changes behaviour only where the behaviour was a bug. Nothing new is added here. What lands is the other half of the September audit (#62): the seven aliases 0.9 introduced beside the names it settled on are removed, the server validators and toMarkdown leave the browser entry, and the eleven sinks agree on one shape for the picture address.

The whole public surface — every export of all twenty entry points — is generated from the build into docs/api-audit-1.0.md by node scripts/api-table.mjs, so a rename is a diff rather than a surprise; tests/exports.test.ts writes the exports map out in full and fails when it, the README's API section and CLAUDE.md stop agreeing; and the seven naming rules in CLAUDE.md are the contract the next name is chosen by rather than a style preference.

Every migration in one table. All of them are mechanical, and nobody has to read a value to make one:

Was Is Where
SendOptions.onFailure SendOptions.onError sendReport
QueueOptions.maxItems QueueOptions.maxEntries createQueue
SLACK_MAX_*, DISCORD_MAX_* (13) MAX_SLACK_*, MAX_DISCORD_* bugbottle/server
rateLimit.rateLimitStore rateLimit.store handleReport
dedupe.dedupeStore dedupe.store handleReport
signature.replayStore signature.store handleReport
SendReportWebhookOptions.url SendReportWebhookOptions.endpoint sendReportWebhook, toWebhook
import { normalise*, toMarkdown } from "bugbottle" … from "bugbottle/server" the core entry
slackSink({ screenshotUrl: (r) => … }) slackSink({ screenshotUrlFrom: (r) => … }) Slack, Discord, Teams
slackSink({ reportUrl: (r) => … }) slackSink({ reportUrlFrom: (r) => … }) Slack, Discord, Teams

The wire format is unchanged: a 0.15 browser and a 1.0 server understand each other in both directions, and so do the schema, the OpenAPI document and the GitHub Action.

Sizes moved by single-digit bytes and no budget moved with them, apart from what #98 cost the queue. Measured against 0.15.0 with the same recipe: bugbottle/react −4, bugbottle/vue −5, bugbottle/svelte −6, bugbottle/solid −5, bugbottle/ui −6, bugbottle/queue 1545 → 1539 → 1565 (the signer seam; the budget stays at 1600), bugbottle/server −2, dist/bugbottle.js −14 then +51 and dist/bugbottle.slim.js −12 then +50, both still inside 25088 and 21504. The core rose three bytes, which is the compressor rather than the code: everything #68 took off the entry was already tree-shaken out of a bundle that never called it, which is why that issue was about what the entry says it is and not about bytes.

Changed

Fixed

Removed

0.15.0 — 2026-09-08 #

The observable release. handleReport says what it decided: onDecision fires once per request with the status, one of eleven reason words, the address the rate limit keyed on and the report's id, routed through the one way out of the handler so no answer can skip it; the inbox example prints an audit line from it and answers /metrics in OpenMetrics text behind its password. Nothing moves under prefers-reduced-motion, and both audits now read every transition and animation duration to prove it. The landing pages caught up with the library: the eleven places a report can land, the queue and its quota story, the privacy checklist, the theme playground and the inbox. No public API changed shape.

Sizes (esbuild, minified + gzipped, without html-to-image): core 1.4 kB, bugbottle/react 5.7 kB, bugbottle/vue 5.8 kB, bugbottle/svelte 5.6 kB, bugbottle/solid 5.7 kB, bugbottle/ui 11.6 kB, bugbottle/annotate 1.4 kB, bugbottle/breadcrumbs 1.3 kB, bugbottle/network 1.2 kB, bugbottle/perf 1.3 kB, bugbottle/queue 1.5 kB, bugbottle/queue-idb 0.7 kB, bugbottle/triggers 1.3 kB, bugbottle/shake 0.7 kB, bugbottle/sign 0.4 kB, bugbottle/rrweb 0.7 kB, bugbottle/locales-extra 4.7 kB, dist/bugbottle.js 24.6 kB, dist/bugbottle.slim.js 21.0 kB, bugbottle/server validators 0.6 kB.

Changed

Added

Documentation

0.14.0 — 2026-09-08 #

The accountable release. The rate limit used to key on the first entry of X-Forwarded-For, which is the one the caller writes, so a fresh header bought a fresh allowance; trustProxy now says which address to believe, the Express adapter and the inbox pass the socket in, and the default trusts no header at all. fileStore gained maxAgeDays and prune(), the inbox runs it hourly from RETENTION_DAYS, and a privacy checklist — in English on the docs and in Danish at /da/privatliv/ — lists every field of a report, whether it is on by default, whether it can hold personal data, the switch that turns it off and where it ends up, with a test that a new field cannot be left off the list. The panel now holds up under Windows High Contrast, proved by two more audit states and a pixel check.

Sizes (esbuild, minified + gzipped, without html-to-image): core 1.4 kB, bugbottle/react 5.7 kB, bugbottle/vue 5.8 kB, bugbottle/svelte 5.6 kB, bugbottle/solid 5.7 kB, bugbottle/ui 11.6 kB, bugbottle/annotate 1.4 kB, bugbottle/breadcrumbs 1.3 kB, bugbottle/network 1.2 kB, bugbottle/perf 1.3 kB, bugbottle/queue 1.5 kB, bugbottle/queue-idb 0.7 kB, bugbottle/triggers 1.3 kB, bugbottle/shake 0.7 kB, bugbottle/sign 0.4 kB, bugbottle/rrweb 0.7 kB, bugbottle/locales-extra 4.7 kB, dist/bugbottle.js 24.6 kB, dist/bugbottle.slim.js 21.0 kB, bugbottle/server validators 0.6 kB.

Changed

Added

Fixed

Documentation

0.13.0 — 2026-09-08 #

The reviewed release. A fresh-context review read everything since 0.9.0 and found six defects, all fixed with tests written first: an SMTP address header that encoded the address itself, a file-store index that two early reports could race, a Teams card that a long picture address pushed over the cap, an inbox preflight that answered 401, a language tag of __proto__ that threw at mount, and a page-script hook that a renamed heading could silently detach. Its follow-ups landed too: requireTls and a write deadline on the SMTP client, the legacy Teams webhook's 200-with-error, clipping on code points, a one-function queue storage seam, versionchange in the IndexedDB storage, fileStore.refresh(). The OpenAPI document now passes a real linter, which runs in CI, and every CORS answer carries Vary: Origin. New since 0.12.0: bugbottle/queue-idb and the queue's quota fallback — a report that does not fit is stored without its picture and says so in notes, rather than being lost — plus the table of eleven sinks and the inbox's notifications.

Sizes (esbuild, minified + gzipped, without html-to-image): core 1.4 kB, bugbottle/react 5.7 kB, bugbottle/vue 5.8 kB, bugbottle/svelte 5.6 kB, bugbottle/solid 5.7 kB, bugbottle/ui 11.5 kB, bugbottle/annotate 1.4 kB, bugbottle/breadcrumbs 1.3 kB, bugbottle/network 1.2 kB, bugbottle/perf 1.3 kB, bugbottle/queue 1.5 kB, bugbottle/queue-idb 0.7 kB, bugbottle/triggers 1.3 kB, bugbottle/shake 0.7 kB, bugbottle/sign 0.4 kB, bugbottle/rrweb 0.7 kB, bugbottle/locales-extra 4.7 kB, dist/bugbottle.js 24.4 kB, dist/bugbottle.slim.js 20.9 kB, bugbottle/server validators 0.6 kB.

Added

Documentation

Changed

Fixed

0.12.0 — 2026-09-08 #

The self-hosted release. Two things that used to need a service now need only what you already have: smtpSink speaks SMTP itself — EHLO, STARTTLS, AUTH PLAIN or LOGIN, one folded and dot-stuffed message, a deadline on every phase — so any mail account is an email sink; and fileStore is the inbox example's storage lifted into bugbottle/server — a JSON file per report with the PNG beside it, atomic writes, ids checked before a path is built, an oldest-first cap — for the deployments that want a directory before they want a database. CI now asserts from both sides that the validator-only server bundle carries neither DOM nor disk. One fix: the site demo imported toMarkdown from the server entry, which the file store made Node-only, and the browser audit in CI caught the broken demo on the merge.

Sizes (esbuild, minified + gzipped, without html-to-image): core 1.4 kB, bugbottle/react 5.7 kB, bugbottle/vue 5.8 kB, bugbottle/svelte 5.6 kB, bugbottle/solid 5.7 kB, bugbottle/ui 11.5 kB, bugbottle/annotate 1.4 kB, bugbottle/breadcrumbs 1.3 kB, bugbottle/network 1.2 kB, bugbottle/perf 1.3 kB, bugbottle/queue 1.3 kB, bugbottle/triggers 1.3 kB, bugbottle/shake 0.7 kB, bugbottle/sign 0.4 kB, bugbottle/rrweb 0.7 kB, bugbottle/locales-extra 4.7 kB, dist/bugbottle.js 24.2 kB, dist/bugbottle.slim.js 20.6 kB, bugbottle/server validators 0.6 kB.

Fixed

Added

0.11.0 — 2026-09-08 #

The tested release. A seeded fuzzer now throws thousands of hostile bodies at the validators, the scrubber, the Markdown and handleReport on every test run, and it earned its keep on the first day: a replay nested a few thousand levels deep overflowed the stack and answered 500, and a __proto__ key in a replay event or a storage snapshot reached the prototype setter. Both are fixed with named regressions. Beside it: a Microsoft Teams sink through a Workflows webhook (the tenth), a JSON Feed and an Atom feed on the inbox example, and three things on the site — the demo draws a picture of itself so the annotator can be tried, a theme playground restyles a live panel and prints the code, and a Danish getting-started page. No library API changed.

Sizes (esbuild, minified + gzipped, without html-to-image): core 1.4 kB, bugbottle/react 5.7 kB, bugbottle/vue 5.8 kB, bugbottle/svelte 5.6 kB, bugbottle/solid 5.7 kB, bugbottle/ui 11.5 kB, bugbottle/annotate 1.4 kB, bugbottle/breadcrumbs 1.3 kB, bugbottle/network 1.2 kB, bugbottle/perf 1.3 kB, bugbottle/queue 1.3 kB, bugbottle/triggers 1.3 kB, bugbottle/shake 0.7 kB, bugbottle/sign 0.4 kB, bugbottle/rrweb 0.7 kB, bugbottle/locales-extra 4.7 kB, dist/bugbottle.js 24.2 kB, dist/bugbottle.slim.js 20.6 kB, bugbottle/server validators 0.6 kB.

Added

Fixed

0.10.0 — 2026-09-08 #

The visible release: the browser audits — axe over the panel and every site page with the security headers served, and the pixel proof that the blur destroys what it covers — now run in CI on every push, so what the two reviewers ran by hand this week runs by itself. The changelog is a page on the site, the version line on both landing pages points at it, and the inbox example ships as a container with a compose file and a Dokploy walk-through. bugbottle/locales-extra adds Italian, Polish, Portuguese, Finnish and Ukrainian as an entry you import on purpose, so the script tags do not grow; and the panel takes the network log and the timings snapshot as options, the same way it takes the annotator and the shake gesture. One contrast fix on the site, found by the audit on its first run.

Sizes (esbuild, minified + gzipped, without html-to-image): core 1.4 kB, bugbottle/react 5.7 kB, bugbottle/vue 5.8 kB, bugbottle/svelte 5.6 kB, bugbottle/solid 5.7 kB, bugbottle/ui 11.5 kB, bugbottle/annotate 1.4 kB, bugbottle/breadcrumbs 1.3 kB, bugbottle/network 1.2 kB, bugbottle/perf 1.3 kB, bugbottle/queue 1.3 kB, bugbottle/triggers 1.3 kB, bugbottle/shake 0.7 kB, bugbottle/sign 0.4 kB, bugbottle/rrweb 0.7 kB, bugbottle/locales-extra 4.7 kB for all five (about 1.1 kB for one), dist/bugbottle.js 24.2 kB, dist/bugbottle.slim.js 20.6 kB, bugbottle/server validators 0.6 kB.

Added

Fixed

0.9.0 — 2026-09-08 #

The consistency release. The whole public API was read once before 1.0 — 412 exported names across eighteen entry points — and the seven naming rules that came out of it are now in CLAUDE.md. Every rename ships as an alias: onError beside onFailure, maxEntries beside maxItems, store beside the three store names, endpoint beside the webhook url, MAX_SLACK_* and MAX_DISCORD_* beside the vendor-first spellings, and every init* returns its stop(). Nothing is removed; the removals are issues #63–#67 for 1.0. Beside it: a Content-Security-Policy on every path of the site, the server bundle asserted in CI against DOM symbols, Jira line breaks as hardBreak nodes, the inbox example indexed and capped, honest result counts in the docs search, and the review fixes to the replay cap, the null-byte strip, the store answers and the contact input.

Sizes (esbuild, minified + gzipped, without html-to-image): core 1.4 kB, bugbottle/react 5.7 kB, bugbottle/vue 5.8 kB, bugbottle/svelte 5.6 kB, bugbottle/solid 5.7 kB, bugbottle/ui 11.4 kB, bugbottle/annotate 1.4 kB, bugbottle/breadcrumbs 1.3 kB, bugbottle/network 1.2 kB, bugbottle/perf 1.3 kB, bugbottle/queue 1.3 kB, bugbottle/triggers 1.3 kB, bugbottle/shake 0.6 kB, bugbottle/sign 0.4 kB, bugbottle/rrweb 0.7 kB, dist/bugbottle.js 24.1 kB, dist/bugbottle.slim.js 20.6 kB, bugbottle/server validators 0.6 kB.

Added

Fixed

Changed

0.8.0 — 2026-09-08 #

The reachable release: the report can carry how to answer the person who wrote it, and it can land in Jira, GitLab, or your own inbox. A contact field, off by default everywhere and reply-to on the email; Jira Cloud and GitLab sinks beside the seven that existed; the rate limit and the dedupe as store seams like the replay cache, so several instances answer as one; the last thirty seconds from the app's own rrweb recorder as an attachment; a slim script-tag build without the optional recorders; examples/inbox, a zero-dependency place for reports to land behind one password; on the site, a search over the documentation, a recipes page with one verified route handler per framework, security headers on every path and dated sitemap entries. One change for an existing panel: the contact input is new markup, off unless asked for. A fresh-context review went in before this tag; its fixes are under Fixed.

Sizes (esbuild, minified + gzipped, without html-to-image): core 1.5 kB, bugbottle/react 5.7 kB, bugbottle/vue 5.8 kB, bugbottle/svelte 5.6 kB, bugbottle/solid 5.7 kB, bugbottle/ui 11.4 kB, bugbottle/annotate 1.4 kB, bugbottle/breadcrumbs 1.3 kB, bugbottle/network 1.2 kB, bugbottle/perf 1.3 kB, bugbottle/queue 1.3 kB, bugbottle/triggers 1.3 kB, bugbottle/shake 0.6 kB, bugbottle/sign 0.4 kB, bugbottle/rrweb 0.7 kB, dist/bugbottle.js 24.0 kB, dist/bugbottle.slim.js 20.5 kB, bugbottle/server validators 0.6 kB.

Added

Fixed

Changed

0.7.0 — 2026-09-08 #

The evidence release: the reporter can mark the picture before it leaves, a blur that really destroys what it covers, request signing with a replay cache that the key holder cannot empty, timings and a storage snapshot, shake to report on a phone, a Solid adapter, and four more places a report can land — Slack, Discord, Sentry (with GlitchTip and Bugsink) — beside the existing four. The panel now takes the annotator and the shake detector as functions you hand in, so a panel nobody marks a picture in ships neither; that is the one change an existing annotate: true has to make. The site was set in two typefaces of its own and audited page by page. A fresh-context review of the annotator, the signing and the comparison page went in before this tag, with three privacy and security fixes recorded under Fixed.

Sizes (esbuild, minified + gzipped, without html-to-image): core 1.5 kB, bugbottle/react 5.6 kB, bugbottle/vue 5.6 kB, bugbottle/svelte 5.5 kB, bugbottle/solid 5.6 kB, bugbottle/ui 11.1 kB, bugbottle/annotate 1.4 kB, bugbottle/breadcrumbs 1.3 kB, bugbottle/network 1.2 kB, bugbottle/perf 1.2 kB, bugbottle/queue 1.3 kB, bugbottle/triggers 1.3 kB, bugbottle/shake 0.6 kB, bugbottle/sign 0.4 kB, dist/bugbottle.js 23.1 kB, bugbottle/server validators 0.5 kB.

Added

Changed

Fixed

0.6.0 — 2026-09-07 #

The adoptable release: one form state shared by React, Vue and Svelte; a panel that a keyboard and a screen reader can use; the offline queue; a keyboard shortcut and an opt-in open-on-error; stack frames and a wider page context on every report; the Linear sink and a JSON Schema for the payload; documentation generated from this README at bugbottle.dev/docs. No breaking changes for the ESM entries; the script-tag build grew from 13.7 kB to 18.1 kB gzipped because it carries every default in eight languages.

Sizes (esbuild, minified + gzipped, without html-to-image): core 1.3 kB, bugbottle/react 5.5 kB, bugbottle/vue 5.6 kB, bugbottle/svelte 5.4 kB, bugbottle/ui 10.1 kB, bugbottle/breadcrumbs 1.3 kB, bugbottle/network 1.2 kB, bugbottle/queue 1.3 kB, bugbottle/triggers 1.3 kB, dist/bugbottle.js 18.1 kB, bugbottle/server validators 0.5 kB.

Added

Changed

Changed

Fixed

0.5.0 #

The receiving release: one function that takes any web Request and turns it into a validated, scrubbed, delivered report; the network log; masking on by default in screenshots; and the landing page in its own voice at bugbottle.dev. No breaking changes.

Sizes (esbuild, minified + gzipped, without html-to-image): core 0.9 kB, bugbottle/react 5.0 kB, bugbottle/ui 8.0 kB, bugbottle/breadcrumbs 1.2 kB, bugbottle/network 1.2 kB, dist/bugbottle.js 13.7 kB, bugbottle/server validators 0.8 kB.

Added

Changed

Fixed

0.4.0 #

The evidence release: what happened before, where it went, and what must never leave the browser. One breaking change: Locale now requires an email key (every bundled locale has it; a hand-written one needs the two strings).

Sizes (esbuild, minified + gzipped, without html-to-image): core 0.8 kB, bugbottle/react 3.9 kB, bugbottle/ui 6.9 kB, bugbottle/breadcrumbs 1.2 kB, dist/bugbottle.js 11.6 kB, bugbottle/server 0.3 kB (validators only; sinks and toMarkdown are tree-shaken when unused).

Added

Fixed

0.3.1 #

Added

First release published from CI through npm Trusted Publishing.

0.3.0 #

First npm release. The API changed from 0.2 in two places: captureScreenshot takes a renderer as its first argument, and useBugReport needs screenshot: htmlToImage (from bugbottle/html-to-image) to take pictures. Everything else is additive.

Changed

Added

Fixed

Sizes (esbuild, minified + gzipped, without html-to-image): bugbottle core 0.6 kB, bugbottle/react 3.4 kB (React external, element picker included), bugbottle/ui 6.4 kB, one locale 0.5 kB, bugbottle/server 0.8 kB.

0.2.4, 0.2.3, 0.2.2, 0.2.1 #

Tags only, no npm release. A GitHub Action (mahope/bugbottle@v0) that validates exported JSON reports in CI, with its entry point and absent-context handling fixed across the patch tags; dist/ committed so the package installs from GitHub and serves from jsDelivr without npm.

0.2.0 #

0.1.0 #

First cut. Extracted from the feedback bubble in two production apps.

Added

Design notes