Skip to content

Tags: tonioloewald/tosijs-ui

Tags

v1.9.6

Toggle v1.9.6's commit message
feat(dev-server): serve brotli/gzip for text assets

[new] text-shaped assets are compressed per the client's Accept-Encoding — brotli
      preferred, gzip fallback, nothing forced. Measured over the wire: iife.js 1236KB →
      366KB brotli / 396KB gzip, hydrate.js 441KB → 122KB, docs.json 376KB → 108KB. Roughly
      70% off everything text-shaped.
[note] this is the proper fix for the LAN stalls behind #63. Raising `idleTimeout` to 120s
      stopped Bun closing the connection mid-transfer; this stops the transfer needing the
      extra time. tosijs-3d's 10MB iife becomes roughly 3MB.
[note] brotli at quality 5, not 11 — measured on the 1.21MB iife: q5 is 19ms for 0.36MB,
      q11 is 1169ms for 0.32MB. Sixty times the cost for four percent.
[note] the cache is BOUNDED — 64MB ceiling, oldest-out eviction, keyed on path + mtime so a
      rebuild invalidates it. Not optional in a process that lives for days: an unbounded
      cache here is the same failure class that took this machine down twice, and it would
      be invisible to the JS heap. Without any cache it would be worse than useless,
      recompressing a 10MB bundle per request.
[note] dev server only, deliberately — the build emits nothing precompressed, because
      distribution is a host's job and Cloudflare/Firebase do it better and free. The
      tunnel gets it automatically: both listeners share one request handler.
[note] verified end to end rather than by ratio — correct Content-Encoding and Vary headers,
      both encodings round-trip (curl for gzip, node's brotliDecompressSync for br, since
      curl on this machine has no brotli), already-compressed formats stream untouched, and
      real browsers decode it: 37 doc tests + 22 Playwright specs green.

Lanes: unit 872/0; test-browser 37/0; playwright chromium 22/0; test-consumer 29.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GL7GXQAWmDzM16boUUzcqx

v1.9.5

Toggle v1.9.5's commit message
v1.9.5

#55 (snowfox): localize() destroyed literal '#'. An annotation is now recognised only when
it looks like the suffix identifier it is, so 'C# Tutorial', 'Issue #42' and '#hashtag'
survive; `\#` escapes the ambiguous residue. Translations are no longer scanned for
annotations at all — a translation containing '#' was being truncated even when the source
had none.

[note] kept as a PATCH deliberately. The fix introduced `annotationIndex` / `stripAnnotation`
      as exports for testability, and `src/index.ts` re-exports localize wholesale — so they
      landed on the package root surface, which by this project's own rule ("a feature that
      adds public API is a minor") would have forced 1.10.0. They are internal parsing
      details, the committed tests exercise them through `localize()` alone, and nothing else
      imports them, so they are internal again and the release is honestly a patch.

Also: brace-expansion pinned >=5.0.9 (GHSA-rgw5-rvv9-x895) — a follow-up advisory against a
package already pinned for the previous one. The audit gate blocked the build on it.

Lanes: unit 850/0; test-browser 37/0; playwright 59 passed 7 skipped; test-consumer 24;
audit clean; release-check clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GL7GXQAWmDzM16boUUzcqx

v1.9.4

Toggle v1.9.4's commit message
v1.9.4

#48 (tosijs-3d): the dev server spawned its own haltija via bunx and ignored the project's
installed one — and bunx caches the resolution, so a range that resolves forward never
re-resolves. An adopter who upgraded haltija for a fix kept getting a cached older build,
with `hj where` reporting the spawned server and so agreeing with them.

Now prefers node_modules/.bin/haltija, falls back to bunx haltija@^1.11.2, and prints
which channel it used and where it came from at both spawn sites.

Lanes: unit 846/0; release-check clean; tsc/eslint clean; build green. Browser, Playwright
and consumer lanes were run green on this tree at 30708d7 — the only delta since is the
version string and CHANGELOG.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GL7GXQAWmDzM16boUUzcqx

v1.9.3

Toggle v1.9.3's commit message
v1.9.3

Two adopter-reported fixes, both with the diagnosis largely done by the reporter.

- #47 (tosijs-3d): the dev server SEGFAULTED at the 8h idle timeout instead of exiting,
  so a workspace left up for a working day went offline silently. All six exit paths
  stopped listeners before process.exit(); that buys nothing and was where it died.
  Filed upstream as oven-sh/bun#36788 — try/catch is not a mitigation, a segfault is not
  a catchable exception.
- #46 (foresight-rpg): the build wrote an ePub per volume and linked to none of them.
  Now a `<!-- epub-downloads -->` marker, an /epub-volumes.json manifest, and an exported
  helper — with the ePub build naming its output through the same function, so a link
  cannot point at a name nothing wrote.
- #45: a valid session now trumps a stale invite link.
- `tosijs-tunnel --close` confirms a matched pid is really ssh before signalling, and
  escapes the host before interpolating it into a pgrep pattern.

Lanes: unit 842/0; test-browser 37/0; playwright 59 passed 7 skipped; test-consumer 24;
release-check clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GL7GXQAWmDzM16boUUzcqx

v1.9.2

Toggle v1.9.2's commit message
fix(a11y): stale accent fallbacks, and the brand bar's own text

[fix] three stale colour fallbacks survived the sweep because they were VALUES, not
      theme definitions: `header.ts` fell back to `var(--tosi-accent, #EE257B)` and
      doc-browser's focus pulse to `#007aff`. Both are live defaults whenever the var is
      unset, so the fix had been applied to the theme and not to what ships when the theme
      is absent.
[fix] the doc-site brand bar's text was `brandColor.rotate(30).brighten(0.9)` — a warm
      off-white at 4.09:1 on the brand, under AA for the normal-size nav links in it.
      Every brighten value short of pure white also misses (0.96 → 4.49), so the tint is
      gone in favour of `contrasting()`, which picks the readable extreme for whatever the
      brand currently is and cannot drift when the brand moves.
[note] dark mode was already fine and stays fine: invertLuminance flips that text to
      near-black on the brightened bar. Checked rather than assumed — the brightening
      added for dark-mode brand TEXT takes white at only 3.81:1, so a header using the
      brightened brand as a BACKGROUND with white text would have regressed. It doesn't,
      because the text inverts too.
[note] found by asking what was worth double-checking before release, which is the only
      reason these were caught: an earlier "0 failures" sweep was misleading because a
      previous eval had left `.darkmode` applied to the page.

Lanes: unit 829/0; test-browser 37/0; playwright 59 passed 7 skipped; test-consumer 24;
release-check clean. Contrast: 0 failures across 8 pages, both themes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GL7GXQAWmDzM16boUUzcqx

v1.9.1

Toggle v1.9.1's commit message
v1.9.1 — ship module specifiers Node can resolve

[fix] shipped `dist/` used extensionless relative imports (`from './site-config'`), which
      bun resolves and Node ESM does not. Every entry point failed under Node with
      `Cannot find module` — including ones with nothing to do with bun — and it goes back
      well before 1.8.0. 678 specifiers across 113 source files now carry explicit `.js`,
      the form Node requires and every bundler accepts.
[fix] bare side-effect imports (`import './css-var-editor'`) were missed by the first
      pass because they have no `from` clause — and they matter most, since they exist
      only to register custom elements.
[new] the consumer lane imports every entry point through NODE and asserts the absence of
      module-resolution errors specifically, so "packaging is broken" stays distinguishable
      from "this needs a DOM" or "this needs bun". Verified to fail against the published
      1.9.0. `tosijs-ui/icon-svg` is additionally asserted to RUN under node, since being
      DOM-free is the entire reason it exists.
[new] `engines` declares bun, and doc-site-system.md gained "Runtimes — what runs where":
      /site is a bun tool, the components need a browser, icon-svg needs nothing. Those
      constraints were always true; the failure messages named symptoms instead.
[note] the four lanes missed this because ALL FOUR run under bun. test-consumer packs the
      real tarball, installs it and builds from a foreign cwd — but with bun, so it proved
      the package works for people exactly like us. The fixed axis was cwd and packaging;
      the runtime was held constant.

Lanes: unit 829/0; test-browser 37/0; playwright 59 passed 7 skipped; test-consumer 24.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GL7GXQAWmDzM16boUUzcqx