tosijs-ui 1.9.0-rc.2 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +307 -39
- package/bin/deploy-preview.ts +78 -65
- package/bin/make-icon-data.js +93 -2
- package/bin/release-notes.ts +150 -0
- package/bin/resolve-site-config.ts +151 -1
- package/bin/tunnel.ts +99 -44
- package/deploy/Caddyfile +24 -13
- package/deploy/build-index.sh +8 -2
- package/dist/babylon-3d.js +2 -2
- package/dist/bodymovin-player.js +1 -1
- package/dist/carousel.js +1 -1
- package/dist/code-editor.d.ts +2 -2
- package/dist/code-editor.js +3 -3
- package/dist/data-table.d.ts +2 -2
- package/dist/data-table.js +6 -6
- package/dist/dialog.js +1 -1
- package/dist/doc-browser.d.ts +1 -1
- package/dist/doc-browser.js +13 -12
- package/dist/doc-system/book-html.d.ts +1 -1
- package/dist/doc-system/book-html.js +3 -3
- package/dist/doc-system/book-target.d.ts +51 -0
- package/dist/doc-system/book-target.js +136 -0
- package/dist/doc-system/css-var-editor.d.ts +1 -1
- package/dist/doc-system/css-var-editor.js +1 -1
- package/dist/doc-system/doc-system-styles.js +1 -1
- package/dist/doc-system/doc-system.d.ts +1 -1
- package/dist/doc-system/doc-system.js +8 -8
- package/dist/doc-system/nav-tree.js +1 -1
- package/dist/doc-system/release-notes.d.ts +33 -0
- package/dist/doc-system/release-notes.js +199 -0
- package/dist/doc-system/site/audit-guard.js +13 -6
- package/dist/doc-system/site/check-examples-cli.js +1 -1
- package/dist/doc-system/site/check-examples.d.ts +2 -2
- package/dist/doc-system/site/check-examples.js +1 -1
- package/dist/doc-system/site/dev-auth.d.ts +32 -1
- package/dist/doc-system/site/dev-auth.js +71 -1
- package/dist/doc-system/site/dev-server.d.ts +9 -2
- package/dist/doc-system/site/dev-server.js +167 -43
- package/dist/doc-system/site/docs.d.ts +23 -0
- package/dist/doc-system/site/docs.js +18 -2
- package/dist/doc-system/site/epub-cli.js +1 -1
- package/dist/doc-system/site/epub.d.ts +11 -2
- package/dist/doc-system/site/epub.js +60 -9
- package/dist/doc-system/site/generate-css.d.ts +2 -2
- package/dist/doc-system/site/generate-css.js +2 -2
- package/dist/doc-system/site/generate-site.d.ts +3 -3
- package/dist/doc-system/site/generate-site.js +4 -4
- package/dist/doc-system/site/index.d.ts +16 -16
- package/dist/doc-system/site/index.js +9 -9
- package/dist/doc-system/site/make-llms-txt.js +1 -1
- package/dist/doc-system/site/open-browser.js +10 -2
- package/dist/doc-system/site/orchestrator.d.ts +1 -1
- package/dist/doc-system/site/orchestrator.js +67 -15
- package/dist/doc-system/site/sections.js +2 -2
- package/dist/doc-system/site/site-config.d.ts +50 -27
- package/dist/doc-system/site/site-config.js +10 -0
- package/dist/editable-rect.js +2 -2
- package/dist/filter-builder.d.ts +1 -1
- package/dist/filter-builder.js +2 -2
- package/dist/float.js +1 -1
- package/dist/form.js +1 -1
- package/dist/header.js +1 -1
- package/dist/icon-data.js +314 -314
- package/dist/icon-svg.js +21 -3
- package/dist/icons/data/index.d.ts +313 -313
- package/dist/icons/data/index.js +313 -313
- package/dist/icons.d.ts +2 -2
- package/dist/icons.js +6 -4
- package/dist/iife.js +74 -66
- package/dist/iife.js.map +47 -47
- package/dist/index-iife.js +1 -1
- package/dist/index.d.ts +49 -49
- package/dist/index.js +49 -49
- package/dist/live-example/code-transform.d.ts +1 -1
- package/dist/live-example/component.d.ts +1 -1
- package/dist/live-example/component.js +16 -15
- package/dist/live-example/execution.d.ts +1 -1
- package/dist/live-example/execution.js +1 -1
- package/dist/live-example/index.d.ts +8 -8
- package/dist/live-example/index.js +6 -6
- package/dist/live-example/insert-examples.d.ts +2 -2
- package/dist/live-example/remote-sync.d.ts +1 -1
- package/dist/live-example/test-harness.d.ts +1 -1
- package/dist/live-example/test-harness.js +1 -1
- package/dist/live-example/types.d.ts +2 -2
- package/dist/live-example.d.ts +1 -1
- package/dist/live-example.js +1 -1
- package/dist/live-theme.js +1 -1
- package/dist/localize.d.ts +1 -1
- package/dist/localize.js +2 -2
- package/dist/mapbox.js +1 -1
- package/dist/menu.d.ts +2 -2
- package/dist/menu.js +5 -5
- package/dist/month.d.ts +2 -2
- package/dist/month.js +3 -3
- package/dist/notifications.js +2 -2
- package/dist/pocket-bar.d.ts +1 -1
- package/dist/pocket-bar.js +2 -2
- package/dist/pop-float.d.ts +1 -1
- package/dist/pop-float.js +2 -2
- package/dist/rating.js +1 -1
- package/dist/rich-text.d.ts +1 -1
- package/dist/rich-text.js +3 -3
- package/dist/segmented.js +2 -2
- package/dist/select.d.ts +1 -1
- package/dist/select.js +3 -3
- package/dist/sizer.js +2 -2
- package/dist/tab-selector.js +2 -2
- package/dist/tag-list.js +2 -2
- package/dist/tooltip.js +2 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/value-renderer.js +13 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/llms.txt +5 -1
- package/package.json +19 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,279 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 1.9.
|
|
3
|
+
## 1.9.1
|
|
4
|
+
|
|
5
|
+
**`tosijs-ui` did not import under Node.** Shipped `dist/` used extensionless relative
|
|
6
|
+
imports (`from './site-config'`), which bun resolves and Node ESM does not — so a Node
|
|
7
|
+
consumer got `Cannot find module` on entry points that had nothing to do with bun. Every
|
|
8
|
+
entry point is affected, and this goes back well before 1.8.0.
|
|
9
|
+
|
|
10
|
+
Everything shipped now uses explicit `.js` specifiers, which Node requires and every
|
|
11
|
+
bundler accepts. **If you are on Node, upgrade; 1.9.0 and earlier will not resolve.**
|
|
12
|
+
|
|
13
|
+
Two runtime requirements are unchanged, and are now documented rather than implied — they
|
|
14
|
+
are honest constraints, not bugs, but the failure messages named symptoms rather than
|
|
15
|
+
causes:
|
|
16
|
+
|
|
17
|
+
| entry point | runtime |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `tosijs-ui/site` | **bun** — it shells out, builds and spawns |
|
|
20
|
+
| `tosijs-ui`, `tosijs-ui/<component>` | a **browser** or a bundler targeting one |
|
|
21
|
+
| `tosijs-ui/icon-svg` | anything — deliberately DOM-free |
|
|
22
|
+
|
|
23
|
+
`engines` now declares bun, and `doc-site-system.md` has a "Runtimes — what runs where"
|
|
24
|
+
section.
|
|
25
|
+
|
|
26
|
+
**Why four test lanes missed it:** all four run under bun. `test-consumer` packs the real
|
|
27
|
+
tarball, installs it and builds from a foreign cwd — but with bun, so it proved the
|
|
28
|
+
package works for people exactly like us. It now imports every entry point through **Node**
|
|
29
|
+
and asserts the absence of module-resolution errors specifically, separating "packaging is
|
|
30
|
+
broken" from "this needs a DOM / needs bun". Verified against the published 1.9.0: all
|
|
31
|
+
three checks fail on it.
|
|
32
|
+
|
|
33
|
+
## 1.9.0
|
|
34
|
+
|
|
35
|
+
Consumer repairs, remote access, and **authoring: many books from one corpus**.
|
|
36
|
+
|
|
37
|
+
**Anyone on 1.8.0 should upgrade, whether or not they want the new remote-editing
|
|
38
|
+
feature.** 1.8.0's `tosijs-ui/site` entry point does not import at all in a clean
|
|
39
|
+
install — `index.js` statically re-exports `devServer`, which imports `chokidar` at top
|
|
40
|
+
level, and `chokidar` was declared only in `devDependencies` (#32). 1.8.0 also shipped
|
|
41
|
+
5.2 MB / 16 files of doc-site hydrate bundle into every consumer's `dist/` (#31), and
|
|
42
|
+
broke the `tosijs-make-icons` bin (#30). All three are fixed here.
|
|
43
|
+
|
|
44
|
+
### Consumer repairs
|
|
45
|
+
|
|
46
|
+
- **`tosijs-ui/site` imports in a clean install again** (#32). `chokidar` is now an
|
|
47
|
+
optional peer, imported lazily by the watch path only — a plain `buildSite()` never
|
|
48
|
+
reaches for it.
|
|
49
|
+
- **The library package no longer carries the doc-site hydrate bundle** (#31). It built
|
|
50
|
+
into `dist/hydrate/` and shipped to everyone though nothing references it; one adopter's
|
|
51
|
+
package went from 0.62 MB / 398 files to **10.2 MB / 2888 files**. It now builds in a
|
|
52
|
+
temp dir. Caught only by reading `npm pack` output, which is why there is now a lane
|
|
53
|
+
that does exactly that (`bun run test-consumer`).
|
|
54
|
+
- **`tosijs-make-icons` no longer strips `fill-rule`** (#30), which rendered holes in
|
|
55
|
+
compound `evenodd` paths solid — a keyboard drawn as one path came out filled. It was
|
|
56
|
+
stripped in **three** places, not one. `fill-rule` is fill _topology_, not colour, and
|
|
57
|
+
takes no part in the tinting the strip exists for. Ships as a bin, so it affects anyone
|
|
58
|
+
generating their own icon data.
|
|
59
|
+
- **The shipped bins have shebangs** (#35, #36 — reported independently by both adopters).
|
|
60
|
+
Without one, `node_modules/.bin` shims hand TypeScript to the shell.
|
|
61
|
+
- **`/version.json`'s `generator` reports tosijs-ui's version, not the consumer's** (#37).
|
|
62
|
+
It read `package.json` from the _cwd_, so the one field that answers "which tosijs-ui
|
|
63
|
+
built this?" named the wrong package entirely.
|
|
64
|
+
- **A failed "save to source" says why** (#34). The server answers 501 with an actionable
|
|
65
|
+
reason and the client discarded it for a generic "Save failed.", so an unconfigured
|
|
66
|
+
server was indistinguishable from a broken one and the edit appeared to vanish.
|
|
67
|
+
- **New: `iconSvg(name)` / `iconNames()`** (#33) — raw SVG markup with **no DOM
|
|
68
|
+
required**, for build scripts, ePub passes and server-rendered templates. `defineIcons()`
|
|
69
|
+
could write to the icon map but nothing could read it.
|
|
70
|
+
|
|
71
|
+
### Remote access — view and edit your dev server from anywhere
|
|
72
|
+
|
|
73
|
+
`preview.tunnel` exposes the dev server running on your machine at an authenticated public
|
|
74
|
+
URL over an SSH reverse tunnel, so you can read and edit real source from a phone or a
|
|
75
|
+
borrowed laptop. The box does no compute — it terminates TLS and routes — which is what
|
|
76
|
+
lets one small VPS front many projects. Two hostnames make the posture legible:
|
|
77
|
+
|
|
78
|
+
| host | what it is | gate |
|
|
79
|
+
| -------------------------------- | ----------------------------- | --------------- |
|
|
80
|
+
| `<project>.dev.example.com` | read-only snapshot, shareable | invite cookie |
|
|
81
|
+
| `<project>.edit.dev.example.com` | live workspace, yours | session, always |
|
|
82
|
+
|
|
83
|
+
`tosijs-tunnel --link` prints a single-use link; opening it once exchanges the token for a
|
|
84
|
+
durable `HttpOnly; Secure; SameSite=Lax` session cookie and redirects with the token
|
|
85
|
+
stripped, so it never lands in history or a `Referer`. `tosijs-deploy` publishes the static
|
|
86
|
+
snapshot and self-registers a Caddy fragment, so adding a project edits no shared file.
|
|
87
|
+
|
|
88
|
+
**Write authorization keys on the LISTENER, never on a peer address or a header.** Tunnel
|
|
89
|
+
traffic arrives on a dedicated loopback listener, and anything arriving there needs a valid
|
|
90
|
+
session — because a reverse tunnel counterfeits "local" by construction.
|
|
91
|
+
|
|
92
|
+
### Security
|
|
93
|
+
|
|
94
|
+
- The tunnelled workspace's **read** gate keyed on `X-Forwarded-*` rather than the
|
|
95
|
+
listener, so any forwarder that omits those headers — `ssh -R` with `GatewayPorts yes`,
|
|
96
|
+
`ngrok tcp`, `socat`, iptables DNAT, nginx `proxy_pass`, HAProxy without
|
|
97
|
+
`option forwardfor` — read the entire uncommitted working tree unauthenticated, while
|
|
98
|
+
`requireToken` promised "nothing at all, not even the page". Now keyed on the listener,
|
|
99
|
+
like every other gate.
|
|
100
|
+
- `POST /report` was unauthenticated and reachable through the tunnel — a stranger could
|
|
101
|
+
fabricate `{passed:N, failed:0}` and make the test lane **exit green on a suite that
|
|
102
|
+
never ran**. Now local-only.
|
|
103
|
+
- Build-error text (absolute paths from your machine) was injected into every served page
|
|
104
|
+
with no auth check. The label stays public; the detail needs a session.
|
|
105
|
+
- `rsync --delete` accepted any absolute path two segments deep — including `/usr/lib` and
|
|
106
|
+
`/etc/caddy`, which it would have _mirrored_, i.e. emptied. Now an allowlist of preview
|
|
107
|
+
roots, and never the root itself: one dropped path segment would otherwise have deleted
|
|
108
|
+
every other project on a shared box, including the Caddy fragments that route them.
|
|
109
|
+
- `tunnel.requireToken` defaults to **`true`**. The hostname is not a secret — Let's
|
|
110
|
+
Encrypt publishes every certificate to public CT logs — so the session gate carries the
|
|
111
|
+
weight. See the docs for what the hostname discloses and what to do about it (#38).
|
|
112
|
+
|
|
113
|
+
### Fixed
|
|
114
|
+
|
|
115
|
+
- **A 403 could destroy uncommitted work.** An unauthorized read fell through to GitHub
|
|
116
|
+
`main`, so you edited the _published_ file, and the save then handed you a download of
|
|
117
|
+
it — applying which silently reverts your working copy.
|
|
118
|
+
- **`?t=` was intercepted on every request and method**, so any dev server answered
|
|
119
|
+
`GET /?t=12345` with "that invite link has been used" instead of the page, and 401'd
|
|
120
|
+
POSTs carrying `t`. (`t` is the classic cache-buster name.)
|
|
121
|
+
- **Tunnel ports are derived, not fixed** (#39). The bin fell back to a hard-coded 8788
|
|
122
|
+
while the server used `PORT + 1`; they agreed only when `PORT` was 8787. `remotePort` is
|
|
123
|
+
now derived per project too, so two projects on one host cannot collide. One resolver
|
|
124
|
+
serves both, and `tosijs-tunnel --status` reports the ports it would use.
|
|
125
|
+
- **The last-good build protection moved to where the wipe is** — it lived in the dev
|
|
126
|
+
server's watch branch, so `bun run build`, CI, adopters and `bun start`'s own initial
|
|
127
|
+
build had none of it. A red `tsc` no longer discards a freshly generated site either.
|
|
128
|
+
- Two dev servers can coexist; the idle-exit timer counts requests again, not just builds;
|
|
129
|
+
"Build failed" is no longer overwritten by test results seconds later.
|
|
130
|
+
|
|
131
|
+
### ⚠️ `hidden` now actually withholds
|
|
132
|
+
|
|
133
|
+
**If you have been using `draft: true` or `hidden: true` for working notes or unfinished
|
|
134
|
+
chapters, they were public.** `hidden` only removed a doc from the nav and the book — its
|
|
135
|
+
full text was still written into `docs.json`, and it still got a pre-rendered page at its
|
|
136
|
+
own URL. The code comment claimed "drafts don't ship"; a probe confirmed they did, twice
|
|
137
|
+
over.
|
|
138
|
+
|
|
139
|
+
`hidden: true` now means **not published at all**: absent from `docs.json`, from the
|
|
140
|
+
generated pages, from every book, and from `llms.txt`. It is filtered at _extraction_,
|
|
141
|
+
because the corpus is the thing that gets published and any filter applied after it is
|
|
142
|
+
written is too late.
|
|
143
|
+
|
|
144
|
+
It is inherited, and a child **cannot** un-hide itself from a hidden parent — accidentally
|
|
145
|
+
publishing one chapter of a withheld section is the failure worth preventing.
|
|
146
|
+
|
|
147
|
+
### Books
|
|
148
|
+
|
|
149
|
+
A `book` value on a doc selects which volume it binds into. Volumes are discovered from
|
|
150
|
+
the corpus, so a second book needs no configuration:
|
|
151
|
+
|
|
152
|
+
```text
|
|
153
|
+
<!--{ "book": "field-guide" }--> → its own volume
|
|
154
|
+
<!--{ "book": ["default", "field-guide"] }--> → bound into both
|
|
155
|
+
<!--{ "book": "none" }--> → on the site, in no book
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Like `hidden`, it is inherited down the `parent` chain — you mark a section, not every
|
|
159
|
+
leaf — with the **nearest declaration winning outright**, so a chapter can divert to
|
|
160
|
+
another volume, join several, or opt out. A list is what gets you shared front matter: a
|
|
161
|
+
glossary or licence page bound into every volume from one source file rather than copied
|
|
162
|
+
per book. `"none"` anywhere in a list wins, because a contradiction should resolve to
|
|
163
|
+
withholding. `"default"` exists as a writable name for the main volume precisely so a list
|
|
164
|
+
can include it — without one, an array could only ever express "not the default".
|
|
165
|
+
|
|
166
|
+
`config.book` (the manifest that curates and orders docs _within_ a volume) and a doc's
|
|
167
|
+
`book` metadata (_which_ volume) are different things that share a word; both are
|
|
168
|
+
documented.
|
|
169
|
+
|
|
170
|
+
### Release notes assemble themselves
|
|
171
|
+
|
|
172
|
+
`tosijs-release-notes` builds a CHANGELOG section from `[tag]` bullets in commit bodies,
|
|
173
|
+
so notes are written next to the diff rather than reconstructed from memory at the end —
|
|
174
|
+
which is where three false claims in the 1.9.0 notes came from. One bullet per
|
|
175
|
+
separately-interesting _thing_, layered on the conventional subject rather than replacing
|
|
176
|
+
it: a `type:` prefix can only ever represent one change, and the 1.9.0 review commit did
|
|
177
|
+
ten things.
|
|
178
|
+
|
|
179
|
+
tosijs-release-notes # assemble the section
|
|
180
|
+
tosijs-release-notes --check # gate: nothing since the last tag is unaccounted for
|
|
181
|
+
|
|
182
|
+
`--check` fails when an annotation is missing from the changelog, and separately reports
|
|
183
|
+
any commit whose `[fix]`/`[new]` bullets are contradicted by a **markdown-only diff** —
|
|
184
|
+
the shape of the worst 1.9.0 bug, where an auth-gate fix was asserted by a commit whose
|
|
185
|
+
diff never touched the file it named. Matching is deliberately loose: rewriting a bullet
|
|
186
|
+
into prose is the intent, and demanding a literal match would only train people to paste.
|
|
187
|
+
|
|
188
|
+
This section was assembled by the tool and then written up by hand, which is the intended
|
|
189
|
+
workflow — it generates a skeleton and a coverage gate, never the prose. The gate then
|
|
190
|
+
caught two things this very section had dropped, including a bug found by running the tool
|
|
191
|
+
over this repo's own 2026-04/05 history: a bullet used as the commit _subject_ swallowed
|
|
192
|
+
the entire body as continuation text, so one note came out as three paragraphs of
|
|
193
|
+
implementation detail.
|
|
194
|
+
|
|
195
|
+
### Also
|
|
196
|
+
|
|
197
|
+
- `tosijs-make-icons` emits clean, stable, formatter-conformant output, and honours your
|
|
198
|
+
prettier config if prettier is resolvable. Generated icon data no longer churns against
|
|
199
|
+
a formatter (and should still be added to `.prettierignore`).
|
|
200
|
+
- `resolveBook` → `resolveBooks`, returning a list. New in this release; no migration.
|
|
201
|
+
|
|
202
|
+
### Late fixes (rc.3 → rc.4)
|
|
203
|
+
|
|
204
|
+
Three review passes ran against this release. The last two found defects **introduced by
|
|
205
|
+
the previous pass's fixes**, which is why these are listed separately rather than folded
|
|
206
|
+
in silently.
|
|
207
|
+
|
|
208
|
+
**⚠️ `deploy/Caddyfile` is now a TEMPLATE — action required if you installed it.** It
|
|
209
|
+
shipped in every tarball carrying a real ACME email, a specific preview domain, and a
|
|
210
|
+
literal `__PREVIEW_TOKEN__`, while its own header told you to `scp` it to `/etc/caddy`.
|
|
211
|
+
Following that gave you a preview host whose entire invite gate was a string published in
|
|
212
|
+
a public repo, issuing certificates under someone else's Let's Encrypt account. Set
|
|
213
|
+
`PREVIEW_TOKEN`, `ACME_EMAIL` and `PREVIEW_DOMAIN` in `/etc/caddy/preview.env` and
|
|
214
|
+
re-install with `deploy:caddy`, which now substitutes all three, **refuses to install if
|
|
215
|
+
any placeholder survives**, and validates into a temp file before replacing the live
|
|
216
|
+
config rather than after.
|
|
217
|
+
|
|
218
|
+
- **Every ePub volume shipped an identical `dc:identifier`, `dc:title` and cover.**
|
|
219
|
+
`unique-identifier` is EPUB3's primary key, so importing two volumes into Apple Books
|
|
220
|
+
or Calibre made the second replace the first — you would silently lose a book. Volumes
|
|
221
|
+
now derive their own identity; `epub.volumeTitles` names them properly.
|
|
222
|
+
- **An ePub volume matching no documents shipped as a success** — a typo'd book name
|
|
223
|
+
produced a valid ~10KB book with a cover, a nav and no chapters, at exit 0. It now fails
|
|
224
|
+
and lists the volumes that do exist. Relatedly, a corpus where _every_ doc names a
|
|
225
|
+
volume no longer errors on its empty default bucket.
|
|
226
|
+
- **An invite link was unredeemable** on a proxied dev server with no `preview.tunnel`
|
|
227
|
+
block: the lock armed off a config section that did not exist while the `?t=` reader,
|
|
228
|
+
correctly gated on it, refused to look. One predicate now, exported and tested.
|
|
229
|
+
- **`tosijs-tunnel` ignored `PORT` and `--port`**, targeting one port while the server
|
|
230
|
+
listened on another — the drift #39 was meant to end, reintroduced by the commit that
|
|
231
|
+
claimed to end it.
|
|
232
|
+
- **The deploy and tunnel bins printed ✅ over failed remote steps.** `tosijs-deploy` now
|
|
233
|
+
distinguishes _deployed_ from _routed_ and exits non-zero when the files landed but
|
|
234
|
+
nothing serves them; `tosijs-tunnel` marks a public URL that is not routed.
|
|
235
|
+
- **Preview roots other than `/srv/preview` registered successfully and routed nothing** —
|
|
236
|
+
the write side was de-hardcoded while the Caddyfile glob and index script still named
|
|
237
|
+
the default. One place decides now, and a mismatch says so. Override with
|
|
238
|
+
`preview.caddySitesDir`.
|
|
239
|
+
- **`release-check` cleared an empty range** at exactly the release boundary, because
|
|
240
|
+
`git describe` returns the nearest tag including prereleases. It now baselines on the
|
|
241
|
+
last stable release _this commit descends from_, so a hotfix tagged out of order or a
|
|
242
|
+
maintenance branch cannot mislead it.
|
|
243
|
+
- **Publishing now gates on `release-check`.** It was added mid-cycle, and the first thing
|
|
244
|
+
it caught was nine unrecorded annotations including a `[break]` — the `deploy/Caddyfile`
|
|
245
|
+
change above, which would otherwise have shipped with no migration note at all.
|
|
246
|
+
- **The release gate hardened against itself.** `release-check` is now baselined on the
|
|
247
|
+
last stable release this commit _descends from_ (`git describe --exclude`), so a hotfix
|
|
248
|
+
tagged after a later release, or a maintenance branch, cannot mislead it — a repo-wide
|
|
249
|
+
tag scan got both wrong. Its coverage matcher also stopped crying wolf: it filtered
|
|
250
|
+
short words out of the annotation but not out of the changelog, so entries that were
|
|
251
|
+
plainly written up got reported as missing.
|
|
252
|
+
- **`isLockedDown()` and `hasTunnel()` are exported** from the auth module. The predicate
|
|
253
|
+
existed in three places, one of them recomputed inside its own regression test — so
|
|
254
|
+
reverting the fix left the entire suite green. The test imports the real function now.
|
|
255
|
+
- **The browser-test lane keys on haltija's `ready` signal** (haltija ≥ 1.6.1, added in
|
|
256
|
+
response to us filing it): a server that is up but has no connected tab is no longer
|
|
257
|
+
adopted, because `hj navigate` then fails with "no browser reachable". That cost three
|
|
258
|
+
lane runs in a day, each needing a manual `pkill`. The floor also named 1.5.5, a version
|
|
259
|
+
that was never published.
|
|
260
|
+
- **New "Host bootstrap" docs**, because the preview host needs setting up once before
|
|
261
|
+
any project can register. Both bins write fragments that `import preview_site` /
|
|
262
|
+
`import tunnel_site` — snippets that only exist once the host has a Caddyfile — so an
|
|
263
|
+
un-bootstrapped box failed `caddy validate` forever, for every project, silently. That
|
|
264
|
+
failure now names the missing prerequisite.
|
|
265
|
+
- `epub.volumeTitles` is now accepted by `defineSiteConfig` — it was documented and
|
|
266
|
+
type-rejected. `extractDocs`'s hidden-filtering gained tests at the tier that matters:
|
|
267
|
+
real files, real entry point, verified by mutation.
|
|
268
|
+
|
|
269
|
+
### For maintainers of adopting projects
|
|
270
|
+
|
|
271
|
+
`bun run test-consumer` packs the tarball, installs it into a scratch project, and builds
|
|
272
|
+
from that project's cwd. Every other lane runs _in this repo, from this repo, with one dev
|
|
273
|
+
server_ — and four regressions shipped anyway, each living outside exactly that envelope.
|
|
274
|
+
More unit tests would have caught none of them; the gap was context, not depth.
|
|
275
|
+
|
|
276
|
+
### 1.9.0-rc.2 (prerelease detail)
|
|
4
277
|
|
|
5
278
|
Fixes everything both consumers hit within minutes of `rc.1`. Three were regressions
|
|
6
279
|
introduced by rc.1 itself.
|
|
@@ -21,8 +294,8 @@ introduced by rc.1 itself.
|
|
|
21
294
|
broken".
|
|
22
295
|
- **New lane: `bun run test-consumer`** — packs the tarball, installs it into a scratch
|
|
23
296
|
project, runs every bin through the `node_modules/.bin` shims, and builds a site from
|
|
24
|
-
that project's cwd. Every other lane runs
|
|
25
|
-
|
|
297
|
+
that project's cwd. Every other lane runs _in this repo, from this repo, with one dev
|
|
298
|
+
server_, and all four rc.1-era regressions lived outside that envelope. It found a real
|
|
26
299
|
bug on its first run.
|
|
27
300
|
- **A failed "save to source" now says why** (#34). The endpoint answers 501 with an
|
|
28
301
|
actionable sentence ("editableSources is not enabled…") and the client threw it away
|
|
@@ -30,8 +303,7 @@ introduced by rc.1 itself.
|
|
|
30
303
|
broken one and the edit appeared to vanish. The server's reason is surfaced, and every
|
|
31
304
|
failure path now states that the edit is still in the editor.
|
|
32
305
|
|
|
33
|
-
|
|
34
|
-
## 1.9.0-rc.1
|
|
306
|
+
### 1.9.0-rc.1 (prerelease detail)
|
|
35
307
|
|
|
36
308
|
Release candidate. Everything the nine-lens review and the first adopters raised is
|
|
37
309
|
addressed; no features are pending. Install with `tosijs-ui@rc`.
|
|
@@ -39,10 +311,10 @@ addressed; no features are pending. Install with `tosijs-ui@rc`.
|
|
|
39
311
|
**Edit and view are now separate hostnames**, which makes the security posture legible
|
|
40
312
|
without reading config:
|
|
41
313
|
|
|
42
|
-
| host
|
|
43
|
-
|
|
|
44
|
-
| `<project>.dev.example.com`
|
|
45
|
-
| `<project>.edit.dev.example.com` | live editable workspace — yours
|
|
314
|
+
| host | what it is | gate |
|
|
315
|
+
| -------------------------------- | ------------------------------------ | --------------- |
|
|
316
|
+
| `<project>.dev.example.com` | read-only static preview — shareable | invite cookie |
|
|
317
|
+
| `<project>.edit.dev.example.com` | live editable workspace — yours | session, always |
|
|
46
318
|
|
|
47
319
|
- **`tunnel.requireToken` now defaults to `true`.** The old default (read-open) was
|
|
48
320
|
justified by "an expired link should degrade to a readable page when you open a second
|
|
@@ -53,10 +325,10 @@ without reading config:
|
|
|
53
325
|
deliberately if you want a live read-only audience.
|
|
54
326
|
- **An edit host with no tunnel behind it explains itself** — a 503 saying the workspace
|
|
55
327
|
is offline, with a link to the static preview, instead of a bare 502. It deliberately
|
|
56
|
-
does
|
|
328
|
+
does _not_ fall back to serving the snapshot: you would think you were looking at live
|
|
57
329
|
work when you were not.
|
|
58
330
|
- **A spent invite link says so.** The likely culprit is a chat-app link-preview bot,
|
|
59
|
-
whose GET
|
|
331
|
+
whose GET _is_ the first use; previously you got a silent redirect and discovered it
|
|
60
332
|
when a save failed.
|
|
61
333
|
|
|
62
334
|
**Security fixes** (all found by review or adopters, none reported in the wild):
|
|
@@ -67,14 +339,14 @@ without reading config:
|
|
|
67
339
|
- Build-error text (absolute paths from your machine) was injected into every served page
|
|
68
340
|
with no auth check. The label stays public; the detail needs a session.
|
|
69
341
|
- `rsync --delete` accepted any absolute path two segments deep — including `/usr/lib`
|
|
70
|
-
and `/etc/caddy`, which it would have
|
|
342
|
+
and `/etc/caddy`, which it would have _mirrored_, i.e. emptied. Now an allowlist of
|
|
71
343
|
preview roots, extracted and tested.
|
|
72
344
|
|
|
73
345
|
**Adopter-reported fixes** (all from tosijs-3d, all consumer-facing):
|
|
74
346
|
|
|
75
347
|
- **`tosijs-make-icons` stripped `fill-rule`** (#30), so a compound path using `evenodd`
|
|
76
348
|
for holes — a keyboard drawn as one path — rendered the holes solid. `fill-rule` is
|
|
77
|
-
fill
|
|
349
|
+
fill _topology_, not colour, and takes no part in the tinting the strip exists for.
|
|
78
350
|
It turned out to be stripped in **three** places, not one; the `stroked/` branch is the
|
|
79
351
|
one that bit. This ships as a bin, so it affects anyone generating their own icon data.
|
|
80
352
|
- **The doc-site hydrate bundle was written into the library `dist/`** (#31) and shipped
|
|
@@ -92,7 +364,7 @@ without reading config:
|
|
|
92
364
|
**Correctness:**
|
|
93
365
|
|
|
94
366
|
- **A 403 could destroy uncommitted work.** An unauthorized read fell through to GitHub
|
|
95
|
-
`main`, so you edited the
|
|
367
|
+
`main`, so you edited the _published_ file, and the save then handed you a download of
|
|
96
368
|
it — applying which silently reverts your working copy. 401/403 is now its own case in
|
|
97
369
|
both editors.
|
|
98
370
|
- **The last-good build protection moved to where the wipe is.** It lived in the dev
|
|
@@ -104,8 +376,7 @@ without reading config:
|
|
|
104
376
|
- `?t=` is only intercepted when a tunnel is configured, and only on GET — `t` is the
|
|
105
377
|
classic cache-buster name, and a 302'd POST loses its body.
|
|
106
378
|
|
|
107
|
-
|
|
108
|
-
## 1.9.0-beta.3
|
|
379
|
+
### 1.9.0-beta.3 (prerelease detail)
|
|
109
380
|
|
|
110
381
|
Fixes three blockers found by the nine-lens review of beta.2, all in the remote-editing
|
|
111
382
|
feature, plus a rebuild loop the review did not catch because nothing automated runs
|
|
@@ -113,20 +384,19 @@ feature, plus a rebuild loop the review did not catch because nothing automated
|
|
|
113
384
|
|
|
114
385
|
- **`bun run tunnel --link` never worked.** It ran `pgrep -f 'bun bin/dev.ts'`, which does
|
|
115
386
|
not match the documented start command (`bun --watch bin/dev.ts`) — so the headline flow
|
|
116
|
-
was unreachable. Worse, it
|
|
387
|
+
was unreachable. Worse, it _did_ match `bun bin/dev.ts --build-only`, whose process exits
|
|
117
388
|
before the signal handler is registered, so the default SIGUSR2 disposition **killed
|
|
118
389
|
in-flight builds**. Now it asks the dev server over a loopback-only `/__devlink` endpoint:
|
|
119
390
|
no process guessing, no signals, and it cannot touch a sibling project. (`/__devlink` is
|
|
120
391
|
refused over the tunnel — a read-only visitor minting a write session would be privilege
|
|
121
392
|
escalation.)
|
|
122
|
-
- **Write authorization failed OPEN.** It inferred "this is local" from the
|
|
393
|
+
- **Write authorization failed OPEN.** It inferred "this is local" from the _absence_ of
|
|
123
394
|
`X-Forwarded-*`, so any forwarder that doesn't set them — `ssh -R` with `GatewayPorts yes`,
|
|
124
395
|
`ngrok tcp`, `socat`, iptables DNAT, nginx without `forwardfor` — delivered an off-machine
|
|
125
396
|
request as `{peer: 127.0.0.1, no headers}` and got an **arbitrary repo write**, which the
|
|
126
397
|
watcher rebuilds and runs. The dev server now binds a **separate loopback-only port** for
|
|
127
398
|
tunnel traffic; arriving there always requires a session. Which socket you connected to is
|
|
128
|
-
not something a client can forge.
|
|
129
|
-
to loopback and says so loudly if it isn't.
|
|
399
|
+
not something a client can forge.
|
|
130
400
|
- **The decision guarding that RCE had no tests**, while its own comment claimed a
|
|
131
401
|
regression test that did not exist. It is now `mayWriteSource()` — pure, exported, and
|
|
132
402
|
covered including a named regression case for the fail-open above.
|
|
@@ -140,13 +410,13 @@ feature, plus a rebuild loop the review did not catch because nothing automated
|
|
|
140
410
|
workspace, so silently adopting a neighbour's config would publish the wrong project.
|
|
141
411
|
- **Fix: the tunnel probed the wrong port**, so forwarding to a dead listener failed
|
|
142
412
|
silently with a 502 and a healthy-looking dev server (tosijs-ui#28). `ssh -R` can't
|
|
143
|
-
catch it — the
|
|
413
|
+
catch it — the _remote_ bind succeeds, so `ExitOnForwardFailure` stays quiet; it's the
|
|
144
414
|
local end that connects to nothing. It now probes the port it actually forwards to and
|
|
145
415
|
**refuses to open**, naming the likely cause (including "your tosijs-ui predates the
|
|
146
416
|
tunnel listener").
|
|
147
417
|
- **Tunnelled workspaces self-register too** (tosijs-ui#29). Static previews have
|
|
148
418
|
self-registered since beta.1, but a tunnelled host still needed a block hand-added to
|
|
149
|
-
the
|
|
419
|
+
the _shared_ Caddyfile — so the one remaining manual edit was the **riskier** one: a
|
|
150
420
|
typo there breaks routing for every project on the box, which is exactly what the
|
|
151
421
|
fragment design set out to abolish. `tosijs-tunnel` now writes its own fragment with
|
|
152
422
|
the same validate-before-reload discipline, and the shared file names no hostnames at
|
|
@@ -162,13 +432,12 @@ feature, plus a rebuild loop the review did not catch because nothing automated
|
|
|
162
432
|
watcher path and declared an **optional peer**, so building needs nothing extra and the
|
|
163
433
|
watching dev server explains itself if it is missing.
|
|
164
434
|
- **Fix: `bun start` was in a rebuild loop** (measured at 899 restarts in ~40s), which made
|
|
165
|
-
the documented dev command unusable. The build stamp imported the
|
|
435
|
+
the documented dev command unusable. The build stamp imported the _generated_
|
|
166
436
|
`src/version.ts`, putting it in `bun --watch`'s module graph while prebuild rewrote it every
|
|
167
437
|
build. The import is gone, and generated files are now written **only when the content
|
|
168
438
|
changes**, which makes the whole class of self-write loops impossible.
|
|
169
439
|
|
|
170
|
-
|
|
171
|
-
## 1.9.0-beta.2
|
|
440
|
+
### 1.9.0-beta.2 (prerelease detail)
|
|
172
441
|
|
|
173
442
|
> Prerelease — install with `tosijs-ui@beta`. `latest` stays on 1.8.0.
|
|
174
443
|
|
|
@@ -182,7 +451,7 @@ same watcher, same files.
|
|
|
182
451
|
which is what lets one small VPS serve many projects. The work stays where the data is.
|
|
183
452
|
- **Magic-link auth.** Two tokens on purpose: the **link** rides in a URL so it is the
|
|
184
453
|
one that leaks (history, `Referer`, proxy logs, chat-app link previews) and is
|
|
185
|
-
therefore
|
|
454
|
+
therefore _single-use and 15 minutes_; the **session** never appears in a URL, arrives
|
|
186
455
|
as an `HttpOnly` cookie, and is durable. A durable token pasted into a URL would be
|
|
187
456
|
strictly worse than basic auth. `SameSite=Lax` gives the write endpoint free CSRF
|
|
188
457
|
protection.
|
|
@@ -205,8 +474,7 @@ same watcher, same files.
|
|
|
205
474
|
session) — Caddy serving static files has no session store — but equivalent to the
|
|
206
475
|
basicauth it replaces, with no dialog.
|
|
207
476
|
|
|
208
|
-
|
|
209
|
-
## 1.9.0-beta.1
|
|
477
|
+
### 1.9.0-beta.1 (prerelease detail)
|
|
210
478
|
|
|
211
479
|
> **Prerelease.** The preview-host system works end to end and is in daily use, but the
|
|
212
480
|
> plan it belongs to (`REMOTE-ACCESS-PLAN.md`) has two more phases. Published under the
|
|
@@ -284,7 +552,7 @@ same watcher, same files.
|
|
|
284
552
|
shown), plus an **advisories-per-package tally** — a dependency that keeps producing them
|
|
285
553
|
is a code smell worth replacing rather than patching.
|
|
286
554
|
- **Fix (issue #24, reported by a consumer): nav `order` now sorts numerically.** Section nav
|
|
287
|
-
and the generated `<!-- toc -->` built a zero-padded
|
|
555
|
+
and the generated `<!-- toc -->` built a zero-padded _string_ key and compared it lexically,
|
|
288
556
|
so a fractional order silently sorted to the **end** of its section — `order: 1.5` landed
|
|
289
557
|
after `2`, `3`, … because `"01.5" > "0002"` as text. "Insert a page at N.5" reads like a
|
|
290
558
|
supported idiom and did the opposite with no warning. The same padding capped `order` at 4
|
|
@@ -299,7 +567,7 @@ same watcher, same files.
|
|
|
299
567
|
above was effectively unfindable. The comparator needs no delimiter; the NUL is gone.
|
|
300
568
|
- **Adopting the gate — budget for one upgrade, not one pin.** From the first real
|
|
301
569
|
adoption (`tosijs`, which went from 12 blocking advisories to zero): if the gate flags
|
|
302
|
-
**`brace-expansion`**, note that `GHSA-mh99-v99m-4gvg` marks
|
|
570
|
+
**`brace-expansion`**, note that `GHSA-mh99-v99m-4gvg` marks _every_ version below
|
|
303
571
|
**5.0.8** affected, so the override is mandatory — and `brace-expansion@5` breaks
|
|
304
572
|
**eslint 8**'s bundled `minimatch@3` with `expand is not a function`. In practice that
|
|
305
573
|
means **an eslint 8 → 10 migration** (flat config + typescript-eslint 8), not a one-line
|
|
@@ -360,13 +628,13 @@ same watcher, same files.
|
|
|
360
628
|
it never sits over the code editors in side-by-side mode). The collapsed handle carries the
|
|
361
629
|
example's pass/fail color, "run tests" is a checkbox that greys when off, and the bar stays
|
|
362
630
|
visible when the example is maximized.
|
|
363
|
-
- **Build system is fragility-tolerant.** An
|
|
631
|
+
- **Build system is fragility-tolerant.** An _unsupported import_ in a live example (a bare
|
|
364
632
|
specifier the runtime can't resolve) now downgrades that block to display-only with a warning
|
|
365
633
|
instead of failing the whole build; genuine syntax errors still fail the build.
|
|
366
634
|
- **Removed a render-skip anti-pattern** from `<tosi-segmented>`, `<tosi-color>`, and
|
|
367
|
-
`<tosi-form>`. They previously depended on `render()` being
|
|
635
|
+
`<tosi-form>`. They previously depended on `render()` being _skipped_ after interaction via a
|
|
368
636
|
`valueChanged` flag — fragile timing that broke under tosijs's parts changes. Renders are now
|
|
369
|
-
idempotent: they skip only
|
|
637
|
+
idempotent: they skip only _provably-redundant_ writes by comparing values (colors compared
|
|
370
638
|
**parsed**, so a `#rrggbb ↔ rgba()` round-trip no longer clobbers the caret/selection in the
|
|
371
639
|
field being edited).
|
|
372
640
|
- **Code editor background is now a neutral off-white** (off-black in dark mode) instead of a
|
|
@@ -391,7 +659,7 @@ same watcher, same files.
|
|
|
391
659
|
build was locked to one mount — adding a custom domain to a GitHub project page flipped the
|
|
392
660
|
live site to the root while `docs/` still pointed at `/repo`, 404ing every asset into a bare,
|
|
393
661
|
unstyled shell with no warning. Functional URLs are now emitted **relative to each page**, so
|
|
394
|
-
one build works at `/repo`, a custom-domain root, or a moved mount with no rebuild.
|
|
662
|
+
one build works at `/repo`, a custom-domain root, or a moved mount with no rebuild. _Metadata_
|
|
395
663
|
URLs (`canonical`, `og:url`, `og:image`, `sitemap.xml`) stay absolute via `baseUrl`+`basePath`
|
|
396
664
|
— so `basePath` now only affects metadata, never the page's assets. (The hydrated SPA's own
|
|
397
665
|
nav/`pushState` and `__TJS_LOCAL_BASE` remain root-relative — tracked in #16.)
|
|
@@ -424,7 +692,7 @@ same watcher, same files.
|
|
|
424
692
|
- **Fix: "edit page source" showed HTML instead of source in a dev server without
|
|
425
693
|
`editableSources`.** The `/__docstore/source` endpoint was only routed when
|
|
426
694
|
`editableSources` was on; otherwise the request fell through to the SPA `index.html`
|
|
427
|
-
fallback and returned the rendered page at status 200 — so the client loaded HTML
|
|
695
|
+
fallback and returned the rendered page at status 200 — so the client loaded HTML _as_ the
|
|
428
696
|
source (and save read HTML). The endpoint is now handled unconditionally and answers a clean
|
|
429
697
|
`501` when editing is disabled, so `loadSource` falls back to the GitHub raw source (read-only
|
|
430
698
|
editing, matching the deployed site). Belt-and-suspenders: the client also rejects any
|
|
@@ -432,8 +700,8 @@ same watcher, same files.
|
|
|
432
700
|
more fully in `doc-site-system.md`.
|
|
433
701
|
- **Local example save now gives feedback.** "Save changes (local)" writes a per-browser
|
|
434
702
|
scratchpad (not the file) — it used to do so silently, reading as a no-op. It now posts a
|
|
435
|
-
toast (`postNotification`):
|
|
436
|
-
file."
|
|
703
|
+
toast (`postNotification`): _"Saved to this browser only — use 'Save to source' to write the
|
|
704
|
+
file."_
|
|
437
705
|
|
|
438
706
|
- **`valueRenderer(type)` + declarative `<tosi-table>` column `type`.** A new exported helper
|
|
439
707
|
turns a compact type string into a reusable, locale-aware renderer with a sensible default
|
|
@@ -449,7 +717,7 @@ same watcher, same files.
|
|
|
449
717
|
|
|
450
718
|
- **Deprecation cleanup: `on<Event>` component callbacks → `handle<Event>`.** tosijs reserves the
|
|
451
719
|
`on<Event>` prefix for elements-factory event-handler sugar and now warns when a component
|
|
452
|
-
|
|
720
|
+
_defines_ such a property. Renamed the internal ones: `onResize` → `handleResize` (`size-break`,
|
|
453
721
|
`side-nav`, `code-editor`, `babylon-3d`, `tab-selector`) and `onScrollEnd` → `handleScrollEnd`
|
|
454
722
|
(`data-table`). Verified: those pages now load with zero `on<Event>` deprecation warnings.
|
|
455
723
|
(`<tosi-tabs>`'s public `onCloseTab` still uses the old name — a breaking rename deferred to a
|
|
@@ -517,7 +785,7 @@ the real transpiler + editor on demand; saving keeps the transpiled JS.
|
|
|
517
785
|
With `importResolver` enabled, a live example can `import` any npm package — resolved through a
|
|
518
786
|
same-origin service worker (tjs-lang's import-resolver). Three execution modes are flaggable on
|
|
519
787
|
the fence: `inline` (default), `iframe` (DOM/CSS isolation), `ide` (recognized; iframe path for
|
|
520
|
-
now). Fence grammar is order-free:
|
|
788
|
+
now). Fence grammar is order-free: ` ```ts:ide#demo ` and ` ```ts#demo:ide ` both parse.
|
|
521
789
|
|
|
522
790
|
### Doc-system & build
|
|
523
791
|
|