Skip to content

release: toolbelt v0.9.0, five new tools and thirteen guides - #425

Merged
anurag629 merged 80 commits into
productionfrom
develop
Oct 30, 2026
Merged

anurag629 merged 80 commits into
productionfrom
develop

Conversation

@anurag629

Copy link
Copy Markdown
Member

Five new tools, thirteen new guides and a long list of features and fixes across the existing tools, almost all of them from this month's contributors.

New tools

Guides

JSON formatter

Other tools

Accessibility

Dependencies

New tools and guides, so this is a minor release (v0.9.0).

Come hang out with us on Discord: https://discord.gg/mpGdJyjaRQ

arxh80 and others added 30 commits October 23, 2026 08:25
Title Case, Sentence case, lowercase and UPPERCASE split words on `.` and
`/` like the identifier styles do, then joined them back with spaces, so
`3.5` became `3 5`, `a/b` became `a b` and sentences lost their full stops.
The prose styles now split only on `_`, `-` and whitespace (plus case
boundaries), so `.` and `/` stay in the word like `,` and `!` already do.
`user_id`, `userId` and `kebab-case-name` still give `User Id` /
`Kebab Case Name` in Title Case, and the identifier styles don't change.

Closes #270


Claude-Session: https://claude.ai/code/session_01STJRQtEaEPSLfiWGMn8Syr

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(guides): add JWT decoding and claims guide (#36)

* docs(guides): correct JWT decoding guide details
* feat(guides): add free professional invoice guide

Adds a guide covering the fields a client expects on an invoice, numbering
and payment terms, general tax guidance, common mistakes, and exporting a
PDF with the Invoice Generator. The entry drives the index card, metadata,
JSON-LD, OG image, and sitemap; the page includes a table that collapses to
two columns on small screens.

Closes #39

* fix(guides): match invoice guide to generator fields

Review feedback from anurag629:
- remove the discount line; the generator has one rate per line and a
  single tax rate, so the guide now says to enter a discounted rate on
  the line
- drop the per-line unit column and describe quantity instead
- explain that nothing is stored until Save, and that saved invoices and
  sender details stay in the browser
- name the Notes field for payment details and terms
Signed-off-by: Anurag Yadav <anuragyadav2787@gmail.com>
Signed-off-by: Anurag Yadav <anuragyadav2787@gmail.com>
useLocalStorage read storage once on mount and wrote its whole value back
on every change, so a tab holding an older list overwrote invoices saved
in another tab. Listen for the window storage event for the hook's key,
adopt newValue (or the initial value when the key is removed), and clean
the listener up on unmount.

Covers the two-tab save from #280 with a client test that fails without
the listener.
* Add binary decimal hexadecimal guide

* Add related guides to number base guide
* docs(guides): add what is base64 guide (#37)

* fix(guides): address base64 guide review feedback (#37)
* feat(uuid-generator): add v4 and v7 UUID tool

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(uuid-generator): show descriptive variant names

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.4.16 to 3.4.17.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](cure53/DOMPurify@3.4.16...3.4.17)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.4.17
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Anurag Yadav <anuragyadav2787@gmail.com>
Paste a cron expression and read it in plain English, field by field,
with the next five run times in UTC or local time. Supports lists,
ranges, steps, month and weekday names and the @daily-style macros.
Follows cron's rule that day-of-month and day-of-week match on either
one when both are restricted.

Closes #86

Co-authored-by: Saif Ullah jafri <saifullahjafri@Saifs-MacBook-Air.local>
formatDelta chose the unit before rounding, so a 59.7-minute exp read (in 60m) and a 23.9-hour nbf read (in 24h). It now carries to 1h/1d after rounding, matching relativeTime (#301), with tests for exp, nbf and iat in both directions.
* fix: reject non-object JWT payloads

* test: cover JWT encoder payload validation

* fix: narrow validated JWT payload type
The decoder parsed the header and payload with JSON.parse, which rounds
numbers past 2^53, so 12345678901234567890 showed as 12345678901234567000
and 9007199254740993 as 9007199254740992. IDs like these are common
(snowflake IDs, database keys), so the decoder could quietly show the
wrong one.

Parse with lossless-json instead, as the JSON formatter does. Numbers a
JS number holds safely stay plain numbers, so exp, nbf and iat checks
work as before; only ones it can't hold are kept as written. The card,
the copy button and the download now write them exactly.

Closes #309

Co-authored-by: Saif Ullah jafri <saifullahjafri@Saifs-MacBook-Air.local>
…#311)

* fix(a11y): add aria attributes and Escape handling to ShortcutsLegend

- Add aria-expanded and aria-controls to the button
- Add role=dialog to the popup
- Close popup on Escape and return focus to the button
- Add test covering open/close, aria attributes, and focus management

Closes #306

* fix(a11y): use stable popup id and label the shortcuts dialog

Server and client each generated a different Math.random() id, so the
hydrated button's aria-controls pointed at nothing. useId() gives the same
id on both sides. The dialog also now takes its accessible name from the
visible heading via aria-labelledby.
* fix: improve disclosure control accessibility (#321)

* fix: restore code literal expand cue
)

* fix(json): name tree toggles after their node and report expansion

Every node toggle announced itself as Expand or Collapse, so three container toggles plus the toolbar's Collapse all were four identical buttons. Each toggle now takes its node's key (root for the root) as its accessible name and exposes aria-expanded; the toolbar buttons are named Expand all and Collapse all. Updates the old tree test and adds name/state assertions.

* fix(json): name array items by their index

Array children carry name=null, so name ?? "root" labelled every item root. Pass the index and use item <n> below the root, with a test for objects and nested arrays.
* feat(tools): add CSV/TSV formatter and validator

- RFC 4180 parser: quoted delimiters, doubled quotes, newlines inside fields
- Delimiter and line-ending detection, BOM stripping, validation with line numbers
- Table preview plus normalised CSV/TSV, JSON, TypeScript, YAML and SQL output
- Unit tests for the parser and converters, component tests for the UI

Closes #299

* fix(csv): keep identifier-like values lossless in SQL, TS and YAML

- SQL emits a number bare only when it round-trips; 02134, 007 and
  +15551234567 now stay quoted instead of being changed
- The TypeScript interface types every field as string, matching the JSON
  output rather than guessing narrower types for text
- YAML quotes keys that a 1.1 parser reads as null or boolean (null, on,
  yes, ...), so 'null' and 'on' stay string keys

Adds regression tests for the reported row plus unit coverage for number
quoting and reserved YAML keys.
* fix: improve JSON formatter toolbar accessibility

* test: assert load example aria label
omisha123 and others added 27 commits October 28, 2026 10:11
* fix: keep UUID v7 batches in ascending order

* move compareUuidBytes out of component, drop duplicate setGenerated
Bumps [lossless-json](https://github.com/josdejong/lossless-json) from 4.3.2 to 4.3.3.
- [Changelog](https://github.com/josdejong/lossless-json/blob/main/CHANGELOG.md)
- [Commits](josdejong/lossless-json@v4.3.2...v4.3.3)

---
updated-dependencies:
- dependency-name: lossless-json
  dependency-version: 4.3.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the next group with 3 updates: [@opennextjs/cloudflare](https://github.com/opennextjs/opennextjs-cloudflare/tree/HEAD/packages/cloudflare), [next](https://github.com/vercel/next.js) and [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next).


Updates `@opennextjs/cloudflare` from 1.20.12 to 1.20.13
- [Release notes](https://github.com/opennextjs/opennextjs-cloudflare/releases)
- [Changelog](https://github.com/opennextjs/opennextjs-cloudflare/blob/main/packages/cloudflare/CHANGELOG.md)
- [Commits](https://github.com/opennextjs/opennextjs-cloudflare/commits/@opennextjs/cloudflare@1.20.13/packages/cloudflare)

Updates `next` from 16.4.2 to 16.4.3
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](vercel/next.js@v16.4.2...v16.4.3)

Updates `eslint-config-next` from 16.4.2 to 16.4.3
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](https://github.com/vercel/next.js/commits/v16.4.3/packages/eslint-config-next)

---
updated-dependencies:
- dependency-name: "@opennextjs/cloudflare"
  dependency-version: 1.20.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: next
- dependency-name: next
  dependency-version: 16.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: next
- dependency-name: eslint-config-next
  dependency-version: 16.4.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: next
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ith 3 updates (#375)

Bumps the dev-dependencies group with 3 updates in the / directory: [@types/dompurify](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/dompurify), [postcss](https://github.com/postcss/postcss) and [wrangler](https://github.com/cloudflare/workers-sdk/tree/HEAD/packages/wrangler).


Updates `@types/dompurify` from 3.0.5 to 3.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/dompurify)

Updates `postcss` from 8.5.30 to 8.5.31
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](postcss/postcss@8.5.30...8.5.31)

Updates `wrangler` from 4.151.1 to 4.152.0
- [Release notes](https://github.com/cloudflare/workers-sdk/releases)
- [Commits](https://github.com/cloudflare/workers-sdk/commits/HEAD/packages/wrangler)

---
updated-dependencies:
- dependency-name: "@types/dompurify"
  dependency-version: 3.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: postcss
  dependency-version: 8.5.31
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: wrangler
  dependency-version: 4.152.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* docs(guides): add UUID v4 vs v7 and how to generate a UUID

Adds a guide on how a UUID is written, where the version and variant sit, how v4 and v7 differ, the nil and max UUIDs and collision odds, with what is specific to the UUID Generator & Inspector. Every UUID in it is produced or read back by lib/uuid.ts in a test. Closes #377

* docs(guides): quote RFC 9562 section 6.9 on collision likelihood

Say that implementations should use a cryptographically secure random number generator so values have a low likelihood of collision, which is what section 6.9 says.

---------

Co-authored-by: Saif Ullah jafri <saifullahjafri@Saifs-MacBook-Air.local>
)

* docs(guides): add how to validate a CSV file and fix common errors

Adds a guide on how a CSV file is put together, when a field needs quotes, which delimiter to use, the errors and warnings the validator reports and how to fix each, and converting to JSON, YAML or SQL, with what is specific to the CSV/TSV Formatter & Validator. Every file, message and conversion in it is produced by lib/csv-utils.ts in a test. Closes #381

* test(guides): write the byte-order mark as an escape in the CSV guide tests

Literal U+FEFF characters in the test strings fail the CI check for a byte-order mark. The tests use the same value as the \uFEFF escape.

---------

Co-authored-by: Saif Ullah jafri <saifullahjafri@Saifs-MacBook-Air.local>
* feat(markdown-preview): download standalone html

* fix(markdown-preview): improve dark export token contrast
* feat(color-converter): suggest AA-compliant foreground colors

* fix(color-converter): use hex suggestions for hex and RGB inputs
…ers in JSON to XML (#392)

escapeXml now writes a carriage return as &#13;, so a parser reads "a\r\nb" back unchanged instead of turning it into a line feed. XML 1.0 cannot hold U+0000-U+0008, U+000B, U+000C, U+000E-U+001F, U+FFFE or U+FFFF, not even as a character reference, so toXML now returns an error that names the character as U+XXXX and the path of the string it is in, instead of XML that will not parse. Tabs, line feeds and every other character convert as before. Closes #388

Co-authored-by: Saif Ullah jafri <saifullahjafri@Saifs-MacBook-Air.local>
)

* feat(timestamp-converter): calculate elapsed time between instants

* fix(timestamp-converter): handle log precision and duration labels
* feat(json-formatter): add copyable tree paths

* fix(json-formatter): preserve tree row accessible names
* feat(json-formatter): compare JSON structurally in diff panel

* fix(json-formatter): sync diff input and compare shared key order
* Added guide to convert Unix timestamp to date

Signed-off-by: Anurag Yadav <anuragyadav2787@gmail.com>

* Address review

Signed-off-by: Anurag Yadav <anuragyadav2787@gmail.com>

* update time

Signed-off-by: Anurag Yadav <anuragyadav2787@gmail.com>

---------

Signed-off-by: Anurag Yadav <anuragyadav2787@gmail.com>
* feat(url-encoder): flag repeated query parameters

* fix(url-encoder): show amber repeated-key indicators
…s or the other quote (#410)

jsonpath-plus splits an expression with regular expressions, so a quoted name holding a quote, a backslash, a bracket or a comma, or one that reads like an operator (*, .., ^, ~, $, 1:2), found nothing or ran as the operator. Quoted names are now read as RFC 9535 string literals. A name the library already read correctly is left as written. Any other is swapped for an alias that is also added, hidden, to the parsed data, and the real key is put back in the matches, the pointer and the path. buildJsonTreePath now quotes a key called $, which was written as .$ (the root). Closes #405

Co-authored-by: Saif Ullah jafri <saifullahjafri@Saifs-MacBook-Air.local>
…ild (#416)

Classes like border-[var(--rose)]/30 and bg-[var(--rose)]/5 build no CSS in Tailwind 3, which cannot put an opacity on a var() colour, so 32 of them in 12 files left the boxes with the default grey border and no tint. They now use border-tint-rose-30 and bg-tint-rose-5 style classes, which tailwind.config.ts defines as a color-mix of the accent with transparent. A test fails if a [var(--x)]/NN class comes back, and checks that Tailwind builds every tint class the source uses. Closes #411

Co-authored-by: Saif Ullah jafri <saifullahjafri@Saifs-MacBook-Air.local>
* feat(base64): report precise decode validation errors

* fix(base64): keep mixed alphabet decoding valid
* feat(case-converter): show detected words

* fix(case-converter): avoid live region announcements
@anurag629 anurag629 added the release:minor Release: bump minor version label Oct 30, 2026
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
toolbelt-dev 1ab0824 Oct 30 2026, 06:28 AM

@anurag629
anurag629 merged commit e3f0926 into production Oct 30, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:minor Release: bump minor version

Projects

None yet

Development

Successfully merging this pull request may close these issues.