blume@1.5.0
Minor Changes
- 94b0678: Add docs versioning. The latest documentation lives at the content root with unprefixed URLs; each past version is a frozen snapshot directory cut with the new
blume version <id>command, which copies the tree, rewrites root-absolute links to stay inside the snapshot, and registers the id inblume.config.ts. With aversionsblock configured, the header grows an automatic version switcher (same-page navigation, falling back to the version root), every archived page shows a localized “you’re viewing an old version” notice with a go-to-latest link, and archived pages default their canonical to the same page in the live docs — the SEO treatment guides recommend and no docs framework automates — while version-only pages stay self-canonical and per-versioncanonical: "self"andnoindexremain available. Search scopes results to the version being viewed with a remembered “All versions” toggle across Orama, FlexSearch, Algolia, and Typesense, and the agent surface is version-aware: the MCPsearch_docs/list_pagestools default to the current docs and accept an archived id or"all"(plus a newlocalefilter),get_navigationserves snapshot and per-locale trees,llms.txtsections archived versions with an “(archived)” label,llms-full.txtstays current-only, and the sitemap drops archived pages whose canonical points at a live equivalent. Versioning composes with i18n (snapshot outermost on disk, locale outermost in URLs), snapshots keep their own folder meta and translations, andblume translatenever retranslates them.
Patch Changes
-
b954287: Tighten types across the package:
unknown-typed parameters, returns, and open dictionaries are replaced with precise named types, and every remaining type assertion carries a documented invariant (adopting ultracite’s anti-slop lint preset). -
c8d1624: Native AsyncAPI renderer. The
asyncapiblock now defaults torenderer: "blume"— one real page persend/receiveoperation, grouped by tag (or channel address) in a tab-scoped sidebar, with message payload and header schema tables, channel parameters, protocol bindings, an Authorization section derived fromsecuritySchemes, protocol-aware code samples (wscat/WebSocketfor ws,kcatfor Kafka,mosquitto_pub/mosquitto_subfor MQTT), and full participation in site search,llms.txt, and OG images. AsyncAPI 2.x specs are normalized to 3.x automatically with the official AsyncAPI converter, sopublish/subscribemap onto stable operation URLs. Theasyncapiblock gainsrenderer,codeSamples, andexpandSchemasfor full parity withopenapi; per-sourceincludeInSearch/includeInLlms/noindexnow apply to AsyncAPI sources too.Behavior change: AsyncAPI references were previously always rendered by the embedded Scalar SPA. Set
asyncapi: { renderer: "scalar" }to keep the old behavior. -
84055a7: Measure the audit’s title and meta-description limits in display columns rather than characters. What a search engine truncates is the space the text takes up, and a character count only stands in for that where every character is one column wide — true of Latin text and of nothing else. Counted in characters, one range cannot serve both scripts: the same 110–160 was at once too strict for a Japanese description (which says in ~60 characters what English needs ~120 for, so every page of a Japanese site reported
BLUME_AUDIT_DESCRIPTION_LENGTH) and too loose for a Japanese title (60 characters render as wide as 120 Latin ones and truncate, and nothing was reported). Widths come fromstring-width, so a fullwidth or wide character counts 2 and ASCII or precomposed (NFC) Latin text scores exactly as it did before — an English site’s findings are unchanged. (Two knowable divergences: an emoji now counts 2 columns instead of its UTF-16 code units, and a decomposed (NFD) combining mark counts 0 instead of 1.) The changelog and OpenAPI generators, which trim their derived meta descriptions to the same snippet range, now budget in display columns too, so generated pages keep passing the audit in every script. -
a749fd7:
blume ejectno longer dropsai.ask.instructions: the ejected Ask AI endpoint now carries the custom system-prompt text, matching the hidden runtime. -
eab66c5: Per-group sidebar display modes on the generated sidebar. A folder can opt its group into
flat,group, orpagewithout an explicitnavigation.sidebarconfig: setdisplayin the folder’smeta.ts, or — sugar for folders with anindexpage —sidebar.displayin the index page’s frontmatter. A generated group’s effective mode resolves index frontmatter first, then folder meta, then the globalnavigation.sidebar.display, then theflatdefault; a group’s value applies to that group only, and nested subgroups resolve their own chain.page-mode drill-in panels stay route-aware and list the index page first, loose pages hoist above sibling groups only where a sibling rendersflat(self-delimitinggroup/pagerows keep authored interleaving), and under i18n a fallback-filled index page never overrides a locale’s ownmeta.tsdisplay.sidebar.displayanywhere it is dead — a non-index page, the content root’s own index page, or any page under an explicit config sidebar — reports a newBLUME_SIDEBAR_DISPLAY_IGNOREDwarning instead of being silently dropped. Explicit config sidebars render exactly as before.