v0.19.1
Release notes from CHANGELOG.md for @async/framework@0.19.1 (2026-07-31).
- Fixed pre-runtime
app.applySnapshot(...): snapshots without aflowkey
no longer throw, and snapshot browser-cache entries now reach the first
runtime instead of being dropped. - Unified the reveal vocabulary in
src/reveal-policy.js, shared by the
boundary receiver and the build optimizer. The receiver now accepts the
optimizer's default tailvisible(normalized to "no tail treatment")
instead of throwing. AsyncStreampatches resolved through a runtime or loader now share one
receiver per loader, so sequence dedup and reveal buffering work across
inline stream scripts.- Errored patches carrying reveal metadata settle their reveal index so
ordered andtogethergroups commit buffered siblings instead of stalling
forever. applyServerResultno longer blanks a boundary for envelopes with
html: undefinedorstatus: 204, matching the router's swap accounting;
the router now shares the exportedisServerEnvelopepredicate instead of
a drifted truthy wire-key check.- Bare
*route segments compile as anonymous rest splats (previously scored
as wildcards but compiled as the literal character*). signal:class:xnow delegates to the shared class-token writer, removing a
binding-key collision withclass:xthat silently dropped one of the two
bindings.- Expired server-route prefetch entries are swept on insert instead of
accumulating for the router's lifetime. - Removed dead code that duplicated live implementations:
parsePathin
signals.js,isAsyncSignalSnapshotin app.js, and a no-op template branch
in the loader's swap HTML renderer. - Centralized the typed-registry CRUD scaffolding
(createTypedRegistryMethodsin registry-store.js): the handler, partial,
component, cache, and server registries now share one
register/registerMany/unregister/_adoptMany implementation instead of five
drifting copies. Route and signal registries stay custom by design. - Replaced the three hand-rolled pending facades in app.js (loader, router,
router-loader) with onecreatePendingFacadeimplementation; per-facade
differences (commit-await methods,_clearCurrentbatch clearing) are now
explicit options. - Extracted shared DOM helpers into
src/dom-utils.js(element walking,
boundary lookup,toFragment): the boundary receiver now uses the
loader's TreeWalker walk instead ofquerySelectorAll("*"), and the
receiver-vs-loader clone/adopt fork is an explicitcloneoption. - One owner for repeated micro-implementations:
mergeFeatures(app.js
createAppFeatureSet, previously copied byte-identical into three entry
files), the component fragment comment-marker protocol (html.js, built by
components and parsed by the loader), lazy-descriptor invocation
(createLazyInvokerin lazy-registry.js, adopted by handlers, partials,
components, and async signals),toError/errorMessage/reportUnhandled
(errors.js, adopted by server, router, and the scheduler), and script-JSON
plus attribute escaping (html.js, adopted by app.js SSR output).
boundary-receiver.js and lazy-registry.js keep deliberately-commented
local copies oftoError/errorMessageso the stream slice stays free of
the errors.js module. - Derived flow bridges (async-signal
loading/error/ready/status/
versionmetadata and computed refs) no longer serialize into page
snapshots: they recompute on resume, and the.errormetadata bridge
previously embedded raw error objects in the page payload. - Fixed the inline swap-binding lifecycle: comparison renders (
ifChanged,
bind, swap-many snapshots) serialize binding values to stable tokens
instead of minting registry ids — per-render ids embedded in snapshots
made every comparison unequal, silently degrading dedupe to always-swap —
and a boundary's committed render now tracks its minted ids and releases
the previous content's ids on re-swap, so repeated swaps no longer grow
the binding map for the loader's lifetime. - Owned schedulers (constructed by
LoaderandcreateApp) report job
failures through the structured error pipeline: bindings, commits, and
effects that fail now reach the configuredonErrorand dispatch a
cancelableasync:errorevent on the job's element scope, instead of
escaping straight toglobalThis.reportError. Injected schedulers keep
their creator's error wiring. detachRoot(null)destroys a supplied loader that never registered into
the root set (detach beforestart()), mirroring the guarddestroy()
already had.- Rendering an inline template binding without a Loader now throws the same
clear error the component renderer raises, instead of silently emitting
[object Object]into the attribute. - Completion and recovery hardening: completion jobs (awaited commits) reject
their awaiter without double-reporting through the scheduleronError
bridge; inline binding comparison tokens JSON-escape keys and leaves so
differently-shaped values cannot collide into a skipped swap; a content
retry now recovers an error-settled reveal index instead of rejecting as a
double commit; the router facade restores the original ready()-resolution
order; the registry store's introspection snapshot honors
_snapshotExempt; the app-owned
scheduler bridge readsruntime.onErrorat failure time. - Examples: the router example gains a
"*"fallback route (first render no
longer errors on the served URL); the ssr example resumes through the
publicreadSnapshot(document)API; the streaming example now actually
streams — out-of-order inline wire patches through
AsyncStream.applyScriptwith reveal ordering, error settling, and
recovery; new swap-dedupe example forifChanged; partials README
documents the runtime-capture pattern. - Production tests: a server-render → JSON wire →
readSnapshotbrowser
resume round trip (no partial, server function, or re-render on the
browser side), and a progressive-document streaming flow (shuffled inline
patches, buffering, error settle, recovery) run as part of the server and
runtime suites. - Removed the dead
scripts/release-doctor.js(superseded by
async-pipeline release doctor); theexamplesscripts run the whole
tests/examples/suite; fixed the stalebenchmarks/results/ignore
rule; stream scenario budgets carry working headroom (47500). - Updated the inlined Flow integration to
@async/flow0.10.5 for
resume-safe async-signal snapshots and cross-copy compose stops. - Bundle size from bundled TypeScript source:
browser.tsraw 279,370 B (279.4 KB / 0.279 MB), gzip 56,946 B (56.9 KB / 0.057 MB), br 46,741 B (46.7 KB / 0.047 MB) ->browser.min.jsraw 114,724 B (114.7 KB / 0.115 MB), gzip 34,458 B (34.5 KB / 0.034 MB), br 30,253 B (30.3 KB / 0.030 MB); delta raw -164,646 B (-164.6 KB / -0.165 MB), gzip -22,488 B (-22.5 KB / -0.022 MB), br -16,488 B (-16.5 KB / -0.016 MB).
Release evidence
- Release type: stable
- Package profile: framework-browser
- npm pack files: 63
| File | Raw | Gzip | Brotli |
|---|---|---|---|
browser.d.ts |
45.1 KB | 8.2 KB | 7.3 KB |
browser.js |
272.8 KB | 55.9 KB | 45.6 KB |
browser.min.js |
112.0 KB | 33.7 KB | 29.5 KB |
browser.ts |
272.8 KB | 55.9 KB | 45.6 KB |
browser.umd.js |
289.2 KB | 57.0 KB | 46.3 KB |
browser.umd.min.js |
113.7 KB | 33.9 KB | 29.6 KB |
framework.d.ts |
49.3 KB | 9.0 KB | 8.0 KB |
framework.ts |
429.4 KB | 86.1 KB | 68.4 KB |
server.js |
429.4 KB | 86.0 KB | 68.4 KB |
Diff links:
- browser.d.ts: https://github.com/async/framework/compare/HEAD%5E...v0.19.1?diff=unified#diff-browser.d.ts
- browser.js: https://github.com/async/framework/compare/HEAD%5E...v0.19.1?diff=unified#diff-browser.js
- browser.ts: https://github.com/async/framework/compare/HEAD%5E...v0.19.1?diff=unified#diff-browser.ts
- browser.umd.js: https://github.com/async/framework/compare/HEAD%5E...v0.19.1?diff=unified#diff-browser.umd.js
- framework.d.ts: https://github.com/async/framework/compare/HEAD%5E...v0.19.1?diff=unified#diff-framework.d.ts
- framework.ts: https://github.com/async/framework/compare/HEAD%5E...v0.19.1?diff=unified#diff-framework.ts
- server.js: https://github.com/async/framework/compare/HEAD%5E...v0.19.1?diff=unified#diff-server.js
Source: CHANGELOG.md in tag v0.19.1.