Repository navigation
Releases
esrun@0.47.0
Added
-
fetch(url, { decompress: false })(DECISIONS D210), Bun's init member:
a compressed response body arrives as the server sent it, with
Content-EncodingandContent-Lengthintact, and the request asks for
identityunless it sets its ownAccept-Encoding. For a stored object whose
coding is part of it (an S3 object saved gzipped), a byte-exact proxy, or a
checksum over the wire bytes. -
runtime:websocket'sserve()serveswss:withsecureTransport: "on",
certandkey, likeruntime:http'sserve. -
--proxy=<url>and--no-proxy=<list>(DECISIONS D205):fetch, the
WebSocketclient and the--otelexporter go through anhttp://or
https://forward proxy —http:targets forwarded,https:/ws:/wss:
tunnelled withCONNECT, credentials from the URL sent as
Proxy-Authorizationand never printed.--allow-netstill judges the
target. Exceptions take domains, IPs, CIDR blocks andhost:port;
loopback always goes direct. No environment variable is read: esrun warns
whenHTTP(S)_PROXYis set. A refused tunnel is the new code
ERR_PROXY_TUNNEL. -
serve({ onError(error, request) })(DECISIONS D206): answers for a
handler that threw or returned noResponse. Without it the500's report
now names the request:runtime:http: GET /path failed (trace …), the query
left out. -
--otelreports the outcome of a request: its span carries
http.response.status_codeanderror.typeand isERRORfor a5xxor a
throw, andhttp.server.request.durationis exported to/v1/metrics—
counted before sampling. A request span used to closeOKwhatever happened. -
The
WebSocketclient has the 30s connect deadlinefetchhas, and its
connect errors carry codes (ERR_DNS,ERR_CONNECTION_REFUSED,ERR_TLS,
ERR_TIMED_OUT). -
runtime:pdfsanitize profiles and categories (otf-pdf 0.2):
sanitize({ profile: "basic" | "privacy" | "strict" | "all" }), and
comments,hiddenAnnotations,thumbnails,navigation,webCapture,
structure,hiddenLayersandinvisibleText, each counted by
sanitizeReport. Hidden layers and invisible text are cut from page
content without moving the visible text. The defaults are unchanged.
Changed
-
The minimum supported Rust version is 1.97, up from 1.96: oxc 0.157, which
esdev builds with, requires it. -
runtime:serializationmoves toquick-xml0.42 andtoml1.2. XML input
nested more than 65,535 elements deep is refused instead of overflowing the
parser's depth counter; output is unchanged (the writer is our own). esdev's
HTML splicing moves tohtml5gum0.9. -
brotli9 (withasync-compression0.4.52) andbase640.23: one copy of
each in the binary, matching whatbcryptand the bundler already use. No
change in behaviour. -
runtime:websocketmoves totungstenite0.30: a server refuses a
handshake whoseSec-WebSocket-Keyis not a valid 16-byte key, as RFC 6455
requires, and large messages read faster. The last copy of the older
digestcrates leaves the binary with it. -
Password hashing moves to
argon20.6 andscrypt0.12, on the same
digestgeneration as the rest of the crypto stack, so the oldersha2,
hmac,pbkdf2andblake2copies leave the binary. Hashes are written in
the same PHC format and verify in both directions across the upgrade.
Fixed
-
On Windows, the warning that a proxy variable is ignored names it once:
HTTP_PROXYandhttp_proxyare one variable there, and the warning listed
both. -
runtime:httpkeeps a handler'sContent-Lengthon the answer to aHEAD,
sonew Response(null, { headers: { "content-length": "1234" } })tells the
client the size aGETwould return (RFC 9110 §9.3.2), as Deno does. It was
dropped, leaving no length at all. Only a plain decimal is kept, and only for
HEAD; every other response is still framed from its body. -
fetchwith aRangeheader sendsAccept-Encoding: identity, as the Fetch
standard says (D210), instead of leaving the header out — which accepted any
coding, so a server could compress the range into a body that cannot be
decoded. -
runtime:pdf: a page whose content stream exceedsmaxDecodedSizefails
withERR_PDF_LIMITinstead of reading as an empty page, andpageText
reuses the fonts an earlier call loaded on the same document (otf-pdf 0.2). -
A response the server cut short fails
fetchwithERR_CONNECTION_RESET
and "the connection closed before the response completed", instead of the
HTTP client's chain of wrappers.
Removed
esrun upgrade(DECISIONS D204). A deployment pins its esrun in its
image or install step; on a development machine,esdev upgradenow
updates esrun and esdev together.esrun upgradeexits with an error that
names both routes. To upgrade an esrun-only machine, re-run the installer
withESRUN_VERSION=<version>.
Security
rustix1.1.6, for RUSTSEC-2026-0486 (GHSA-jh2m-fhpj-3vr7): its xattr
functions marked unwritten bytes as initialized. Neither binary calls them.copycan no longer be pointed outside the root jail. It checked both
paths when called and opened them by name when it ran, so acopyissued
with arenameof its directory and asymlinkout of the jail in the same
tick read a file outside the root, or wrote one there. Both ends are now
pinned by descriptor at the call, like every other mutation.stat,
exists,readDir, glob scans andmakeTempFile/makeTempDirare pinned
the same way, which closes the same window for threads racing each other.- No op hands a worker's entry source back to JavaScript. Starting a worker
was two ops, and the first, reachable from guest code through__ops,
returned the entry's text: under--allow-importsalone it read any text
file in the project,.envincluded, whatever--allow-readsaid. The
spawn now reads the entry itself. A worker refused for want ofworkers
says that starting it is what needs the grant. - An import loads only a module file (DECISIONS D209). Any other file —
.env,config.yaml,notes.txt, an extensionless name — is refused
with the new codeERR_UNKNOWN_FILE_EXTENSIONbefore it is read. The
loader used to run whatever a specifier named as JavaScript: a YAML mapping
is a valid script, and a trap on the global object collected every value in
it, so--allow-importsread project files that--allow-readdid not
grant. A module file is.js,.mjs,.cjs,.json(with
type: "json") or.wasm; the file you run, andimport.meta.resolve(),
are unaffected. --allow-run=<program>no longer admits every name of a multi-call
binary. Entries were matched on the real file alone, and on Alpinels
andshare both links to busybox — so--allow-run=lsransh -c …. The
name a program is invoked by must now match as well as the file.crypto.subtleRSA is constant-time (DECISIONS D203). It moves to
RustCryptorsa0.10.0-rc.20, which fixes RUSTSEC-2023-0071 ("Marvin"):
constant-time private-key arithmetic, blinded signing and decryption, and
implicit rejection. All RSA randomness still comes from the injected
entropy provider. RSA-OAEP labels may now be any bytes;generateKey
refuses a modulus outside 1024–8192 bits, andimportKeyrefuses an RSA
key under 1024 bits with aDataError. Checked against OpenSSL-generated
keys, signatures and ciphertexts in both directions.
esdev@0.27.0
Added
-
A
pluginsentry may be several plugins (DECISIONS D214). An export, or
what its factory returns, may be a list of plugins, and the list takes the
entry's place in order, so a package made of several plugins needs one
esdev.jsonentry. Nested lists flatten andnull/falseare skipped.
runtime:build'sbuild({ plugins })reads its list the same way and also
awaits promises, as Rollup does. A0or""is refused rather than
skipped. This used to fail withplugin-0: unknown hook "0". -
The
fullstacktemplate's server is the generated AFW handler
(@afw/server): API routes, loaders, middleware, server functions and
server-rendered pages all come through onecreateHandler, so a new route
needs no edit toserver.js. It ships a server-function sample
(app/todos/todos.server.js) that the todos page calls and its loader calls
directly. In TypeScript the sample is typed; that needs
@opentf/esdev-plugin-afwwith its.tsxtype fix (after 0.7.0). -
dev.servers(DECISIONS D208):esdev startruns several servers —
each with its owntarget,port,env,args, startedafterthe ones
it names — restarts only those whose output changed, and shows each one's
errors on the page under its name.dev.server.proxymay name a server,
making esdev the front door: one address for the page, the update channel
and every server, with the page'sHostkept.dev.runis unchanged. -
Server errors in the overlay (DECISIONS D207). When the server
esdev startruns fails a request or crashes, open pages show it under
Server error, with the request's method, path and trace id. -
esdev startand its server are linked: a restart drains in-flight
requests on every platform, Windows included (it used to kill the server
there), the loop learns the server is listening whenserve()binds, and a
server whoseesdev startis killed exits instead of holding its port. -
An outbound proxy (DECISIONS D205).
fetch, theWebSocketclient
and the--otelexporter — in the programs esdev runs,esdev start's
server,esdev create's registry lookups andesdev upgrade— follow
HTTPS_PROXY/HTTP_PROXY/NO_PROXY(lowercase first), as npm and git do.
--proxy=<url>and--no-proxy=<list>override them;--no-proxy=*turns
the proxy off.
Changed
-
esdev createandesdev initask in Clack's layout and colours, as
create-afw does (@clack/prompts1.8): a gray gutter joining the questions
under a cyan title badge, the question being asked in cyan with a
↑/↓ to navigate • Enter: confirm • Esc: backfooter,●/○options with
the hint beside the focused one, an inline● Yes / ○ Nofor yes/no
questions, and a text input with its default as the placeholder. Outcomes
are marked with ticks, crosses and warning signs: a green✔on each answer
and oncreated, a red✖and struck-through answer on a cancel, a gray–
on a skipped question and a yellow⚠on a registry retry. The keys stay as
they were (Esc steps back, a digit jumps). Esc on the install question now
readsSkipped; it still installs nothing. -
esdev create --template=docsleaves the blog out unless asked, as
create-afw does: the question is now "Add a blog?" and starts on No, and an
unattended run without--blogwrites docs only.--blogaddsapp/blog/
with a sample post, a Blog link, and RSS and Atom feeds;--no-blogis
still accepted. -
esdev upgradealso updates theesruninstalled beside it
(DECISIONS D204), each to its own newest release, checked against its
checksums.txt.--only=esdevor--only=esrun(install.sh's spelling)
limits it to one, and--dry-runreports on both. Anesrunelsewhere on
PATHis left alone. This replacesesrun upgrade, which is removed. -
The bundler moves to rolldown 1.3.1 and oxc 0.157. Among rolldown's
fixes since 1.2.3: a use-after-free in async transforms that read a
tsconfig.json, side effects dropped by tree-shaking (through import
cycles, afterexports.xwrites, and when an exported constant was inlined),
several renaming collisions, chunk execution order, and module namespace
objects that are now null-prototype and non-extensible. oxc fixes TypeScript
enums exported across namespace blocks and the lowering of private class
members andusing. The React Compiler pass stays on the oxc it targets. -
A library build names a non-JavaScript module's output after the whole
file:button.module.cssbecomesbutton.module.css.js(was
button.module.js), anddata.jsonbecomesdata.json.js, as Rollup and
Vite library builds name them. A module can no longer collide with a
button.module.jsbeside it. The imports,requires and declarations the
build writes name the new files; a packageexportsmap that names one of
the old paths needs updating.
Fixed
esdev upgradetries a download again when the network fails it (a
dropped connection, a truncated or stalled body, a5xxor429), up to
three attempts in all, and shows a progress bar for the archive when
stderr is a terminal.
Security
- An import loads only what esdev turns into a module (DECISIONS D209),
as under esrun: module files, the TypeScript and JSX esdev compiles,
.css, and whatever a plugin'stransformfilter admits. Anything else is
refused withERR_UNKNOWN_FILE_EXTENSIONbefore it is read — it used to
run as JavaScript. A plugin with noidfilter on itstransformstill
claims every file. - A web page can no longer attach to
--inspect. The debugger answered
anyHostand anyOrigin, so a page using DNS rebinding could read
/json/list, attach and run code in the process — Node's CVE-2018-7160.
It now answers only tolocalhostor an IP address, refuses a WebSocket
upgrade carrying anyOriginbut Chrome DevTools' (devtools://devtools),
and its session id comes from the OS random source rather than the clock.
@opentf/esrun-types@0.22.0
Added
secureTransport,certandkeyonruntime:websocket'sserve().decompressonRequestInit(D210):falsereturns a compressed response
body as the server sent it.
@opentf/esrun-s3@0.1.0
Added
- The
@opentf/esrun-s3package (DECISIONS D211): an S3 client in JavaScript
overfetch, signed with SigV4, for AWS S3, Cloudflare R2, Google Cloud
Storage and S3-compatible stores. Bun'sS3Client/S3Filesurface —
file(),text(),json(),bytes(),stream(),slice()ranges,
write(),writer(),exists(),stat(),delete(),presign(),
list()— pluslistAll(),copy()anddeleteMany(). Multipart uploads
for large blobs and streams with bounded memory, aborted on failure;
conditional reads and writes; CRC32, CRC32C, SHA-1 and SHA-256 checksums;
SSE-S3, SSE-KMS and SSE-C (HTTPS only); retries with backoff and clock-skew
correction; refreshing credential providers;S3Client.fromEnv()reading
Bun'sS3_*names and the AWS ones. Objects are read byte for byte,
Content-Encodingincluded (decompress: false, D210), so it needs esrun
0.47.0 or later. - Credential providers (DECISIONS D212):
instanceMetadata()(IMDSv2 only),
containerCredentials()(ECS task roles, EKS Pod Identity),webIdentity()
(STSAssumeRoleWithWebIdentity: EKS IRSA, GitHub Actions OIDC) and
assumeRole(), each refreshed before its credentials expire. - Reads resume where a dropped connection left them: the rest is requested
withRangeandIf-Matchon the first answer's ETag, up toretrytimes,
so a replaced object fails the read instead of splicing two versions. copy()copies sources of any size inside S3: when one CopyObject is
refused for a source over 5 GiB, it copies the source in ranges
(UploadPartCopy), pinned to its version or checked against its ETag
(DECISIONS D213).
esrun@0.46.0
Security
-
Mutual TLS (DECISIONS D201).
serveandlistentakerequestCert,
caandcrlto require client certificates, always verified — there is
norejectUnauthorized. The handler'sinfo.peerCertificateand an
accepted socket'sopened.peerCertificatecarry the verified certificate
(subject,subjectaltname,fingerprint256,raw,validFrom,
validTo). Clients present one withcert/keyonruntime:net
connect,sslCert/sslKeyon the PostgreSQL and MySQL drivers,
cert/keyortlsCertificateKeyFileon MongoDB (withMONGODB-X509
authentication), and Bun'stls: { ca, cert, key }onfetch, which gets a
connection pool of its own. -
Certificate rotation (D200):
server.setSecureContext({ cert, key })on
a TLSserveserver orlistenlistener replaces its credentials for new
connections without dropping open ones, and refuses a key that does not
belong to the certificate. -
Revocation (D202):
--tls-crl=<file>checks every TLS client's servers
against operator-supplied CRLs, andcrldoes the same for client
certificates. A CRL past itsnextUpdaterefuses what it covers; nothing is
fetched over the network. -
TLS prefers the hybrid post-quantum key exchange X25519MLKEM768 in every
client and server (DECISIONS D199). The build had turned rustls's
preference off, so handshakes used plain X25519 first. -
esrun upgradeverifies what it installs (DECISIONS D198). It replaced
the running binary with the downloaded archive without checking it, though
the CLI reference said it did. It now refuses a release that publishes no
checksums.txt, or whose archive's SHA-256 does not match it, and leaves the
installed binary untouched. The new binary is written beside the old one and
renamed into place, so an interrupted upgrade never leaves half a binary.
Drafts and pre-releases are no longer offered, and there is no progress bar. -
fetchruns on the runtime's own HTTP client (D198): hyper's framing
and hyper-util's connection pool, with redirects, content codings and
deadlines written to their specifications. Following a redirect now drops
the body'sContent-*headers when the method becomesGET, rejects rather
than resending a streamed body, and dropsCookie2andWWW-Authenticate
along withAuthorization,CookieandProxy-Authorizationon a hop to
another origin. A decoded body arrives at most 64 KiB at a time.
TCP_NODELAYis on. reqwest,self_updateandrustls-platform-verifier
are gone, takingsecurity-framework,core-foundationand the system
proxy readers with them: 25 to 26 fewer crates on each platform. -
Every TLS client verifies against one trust store (DECISIONS D197).
fetchand the--otelexporter checked the operating system's store
whileruntime:net, the database drivers andWebSocketchecked the
bundled Mozilla roots, so a CA one API trusted another refused, and
SSL_CERT_FILEchanged whomfetchalone trusted. All of them now use the
bundled Mozilla roots, or exactly what the new--tls-calists. A private
CA installed only in the operating system is no longer trusted byfetch:
name it with--tls-ca=bundled --tls-ca=<file>. -
--tls-ca=<file|bundled>(repeatable) sets the process trust store. A file
that cannot be read, holds no certificate, holds a private key or any other
non-certificate block, or has a certificate outside its validity period stops
startup, naming the file but never quoting it. No environment variable
changes trust; esrun warns whenNODE_EXTRA_CA_CERTS,NODE_USE_SYSTEM_CA,
DENO_CERTorDENO_TLS_CA_STOREis set. -
fetchand the--otelexporter no longer readHTTP_PROXY,
HTTPS_PROXY,ALL_PROXYor the operating system's proxy settings. The
HTTP client enabled them by default, so an inherited environment variable
could route every outbound request through a host the deployment never
named. Requests now go to the host in the URL. -
The bundled TLS root certificates (
webpki-roots1.0.11) no longer trust
"emSign Root CA - C1" or "emSign ECC Root CA - C3". Mozilla removed them
after the October 2026 compromise of eight eMudhra intermediate CA keys;
"emSign ECC Root CA - G3", the root that signed those intermediates, was
already dropped in 1.0.10. Applies to every TLS client.
Fixed
install.shsupports the fish shell: asked to add ES Runtime toPATH, it
writes~/.config/fish/conf.d/es-runtime.fish(honouring
XDG_CONFIG_HOME) withfish_add_path, instead of appending a POSIX
exportline to~/.bashrcthat fish never reads. The manual instruction
is printed in fish syntax too.
Changed
-
The site footer centers a visibly external Foundation policies link without
changing the AFW badge's position. -
The footer states that the site uses no trackers or analytics.
-
Footer text colors meet WCAG AA contrast against the dark footer background.
-
The AFW footer badge icon uses black strokes.
-
Update the website AFW packages; adapt benchmark components to the current
compiler's single final view return requirement. -
The site's benchmark data is re-measured with esrun 0.45.0 (esdev 0.24.0,
node 26.13.0, bun 1.4.4, deno 2.9.7, llrt 0.9.0-beta, PostgreSQL 18.6) — the
previous full run published 0.43.0 against node 24 and PostgreSQL 16 — and
now includes thejsonc_largeandjson5_largerows.
website/src/versions.jsis regenerated to match. Eleven esrun rows are more
than 10% faster;crypto_asym(ECDSA P-256 sign + verify) is 55% slower,
the cost of the move to the 0.14 NIST curves for RUSTSEC-2026-0387. -
Benchmark charts expose row and column relationships to assistive technology;
animated benchmarks can be paused from the keyboard, and selector controls
announce their pressed state. -
The durable-worker diagram keeps commit and restart markers visible without
motion and improves the storage-link contrast.
esdev@0.26.0
Security
-
--tls-crl=<file>(DECISIONS D202) is taken wherever--tls-cais, and
esdev startpasses it to its server. Programs run by esdev get client
certificates (D201) andsetSecureContext(D200) as under esrun. -
esdev upgraderefuses a release whose archive is not listed in, or does
not match, itschecksums.txt(DECISIONS D198); it used to install the
download unchecked.esdev create's npm registry lookups and the program's
fetchuse the runtime's own HTTP client, as under esrun. -
--tls-ca=<file|bundled>(DECISIONS D197) is taken by every command that
runs a program, and byesdev startandesdev preview, which use it for
the server they start and for anhttpsdev.server.proxytarget. As under
esrun, the program'sfetchnow verifies against the bundled roots or what
--tls-calists, not the operating system's store. -
A program run by esdev no longer sends
fetchrequests or--otelspans
through a proxy named byHTTP_PROXY,HTTPS_PROXYorALL_PROXY, the
same as under esrun. -
esdev's dev proxy no longer trusts the eMudhra roots Mozilla removed after
the October 2026 intermediate CA key compromise ("emSign Root CA - C1",
"emSign ECC Root CA - C3";webpki-roots1.0.11).
Fixed
esdev test --browserresolvesruntime:testagain. The 0.25 alias plugin
treated every URL-shaped specifier as a path and skipped it, so
runtime:test— which parses as schemeruntime— was left as an external
import the browser could not load. An exact alias match now always applies;
only a prefix match on a path or URL is skipped.
@opentf/esrun-types@0.21.0
Added
- Mutual TLS, rotation and revocation (D200–D202):
runtime:net's
PeerCertificate,SecureContextandPem;requestCert,caandcrl
onlistenandserve;cert/keyonconnect;setSecureContexton
ListenerandServer;peerCertificateonSocketInfoand theserve
handler's info;tlsonRequestInit;sslCert/sslKeyand MongoDB's
cert,key,tlsCertificateKeyFileandMONGODB-X509.
Changed
runtime:netconnect'scasays it adds to the process trust store, the
bundled roots or what--tls-calists (D197).
esdev@0.25.0
Fixed
- One resolution rule for every importer (D196). A module takes the
tsconfig.jsonnearest to it — or the reference of it that covers the
file — whatever its extension: a.mdxpage a plugin compiles gets the
project'spaths, where it got none, and a.jsxfile in a project without
allowJsno longer takes a parent folder'spaths,jsxand decorator
settings. A project nested in a workspace could bundle two copies of one
package.esdev.json'sresolve.aliasnow applies beforepathsin a bundle,
as it already did inesdev testandesdev <file>, and an alias that names
nothing fails the build instead of resolving the specifier as written.
esdev builds with a vendored oxc_resolver carrying this rule
(crates/vendor/oxc_resolver/PATCHES.md).
esrun@0.45.0
Removed
esrun --import-policy(D194). The runtime loader judged modules by name and
could not pin what they contained, and a built program — the way esrun runs
in production — has its packages inlined, so the loader never saw them.
Which packages ship is now decided only at build time, by esdev's dependency
policy; a bundle runs without--allow-imports, so nothing else can load.
--allow-imports=<list>now says so.import.meta.resolveand the loader are
otherwise unchanged.
Changed
-
On Windows, environment variable names are case-insensitive, as Windows
makes them (D195).env.PATH,env.pathand"PATH" in envreach the
variable the OS spellsPath, and a write or delete in any case changes
that one variable;--allow-env=PATHgrants it; an--env-fileentry or a
RUNTIME_ENVdefault replaces or keeps it instead of adding a second
variable beside it; andruntime:system'senvoverinheritEnvsets or
removes it, where{ PATH: undefined }had let the inheritedPaththrough
to the child. On Linux and macOS names stay exact. -
BSON.decodebuilds documents and the BSON class instances in V8's fast
mode, asJSON.parsebuilds objects, where it used to build dictionaries
(D187). Documents with the same fields share a shape, so reading them is
several times faster, a decode holds less heap and costs less to collect,
and a typical collection decodes faster overall; a document of only plain
fields decodes somewhat slower.bench/bson/decode.mjsmeasures it. The
MongoDB driver's results come through the same decoder.
Added
environment()inruntime:process: the deployment environment, read at
run time —RUNTIME_ENV, elseNODE_ENV, else"production"(D192).
RUNTIME_ENVis proposed as one name for every runtime and language, for
the questionNODE_ENVhas been made to answer alongside the kind of
build; it needs--allow-env=RUNTIME_ENV,NODE_ENVand nothing more.
process.env.NODE_ENVin bundles is unchanged.JSONCandJSON5inruntime:serialization(D191), each mirroring the
globalJSONwithparse(text, reviver?),stringify(value, replacer?, space?)andvalidate(text, opts?).JSONCreads JSON with comments and
trailing commas, astsconfig.jsonand VS Code's settings are written;
JSON5reads JSON5 1.0.0. Both give back exactly whatJSON.parsebuilds
for the JSON they share, built by the engine straight from the text.
JSONC.stringifyisJSON.stringify;JSON5.stringifywrites JSON5 as the
json5package does, withtoJSON5()and aquoteoption. Errors name the
dialect and endat line L column C.JSONC.edit(text, path, value)andJSON5.edit(text, path, value)change
one value in a config file and keep every other byte: comments, blank
lines, key order and quotes (D191). A missing key is added in the style of
its siblings, missing objects on the path are created, andundefined
removes the member with its comma and its line's comment. Ajson_edit
fuzz target checks that every edit means exactly the change asked for.es-runtime-json, the reader behind the comingJSONCandJSON5in
runtime:serialization(D191). JSONC is JSON with//and/* */
comments and one trailing comma; JSON5 is JSON5 1.0.0 in full. One lexer
reads both and reports each value to a sink, so the engine can build values
with no intermediate tree. Nesting stops at 256 levels, and errors give the
line and column. Every case of JSONTestSuite and json5-tests runs in
cargo test, and ajsonfuzz target checks that whatever JSONC reads,
JSON5 reads the same way.
Fixed
- A PostgreSQL
cancel()— direct, or from an abortedsignal— returns only
once the server has acted on it, as libpq'sPQcanceldoes. It returned as
soon as the request was sent, so a cancel that arrived after its query had
finished, or one made with nothing running, cancelled the next query
instead: 297 of 300 queries sent straight after an idlecancel()were.
Testing / CI
bench/run.shgainsjsonc_largeandjson5_large: each runtime parses a
5,000-record document with what it ships —runtime:serialization, Bun's
Bun.JSONCandBun.JSON5, Deno's@std/jsonc, and for Node (and Deno's
JSON5) thejsonc-parserandjson5packages — and must read it the same.scripts/fs-discipline.shlists the DNS resolver's read of
/etc/resolv.confand the MongoDB specification tests' reads, which had
left the check failing.- The sharded hibernating-room test waits for both clients to receive the
last broadcast before printing, where it waited for one and failed when the
other's copy was still in flight. - The MongoDB job waits for its servers by asking each from inside its own
container, for up to three minutes, and prints the server's log when one
never answers. It started amongoshcontainer per probe and gave up after
two minutes without saying why. - The MongoDB 8 leg of the driver job checks the runner's kernel first.
MongoDB 8 refuses to start on Linux 6.19 through 7.0.13, no MongoDB release
fixes it, and GitHub's runners are on such kernels, so there the leg posts a
warning and stops; MongoDB 7 runs every driver test, and the leg resumes by
itself on a kernel from 7.0.14. - The release leaves
es-runtime-jsonunpublished, as it does the other
internal crates; it had tried to publish it to crates.io and failed. - The benchmark's comparison dependencies move to Hono 4.13 and
puppeteer-core 25.16, past advisories in Hono'sserveStaticand in the zod
that puppeteer pulls in;pnpm auditis clean. Nothing in them ships. - The fuzz build turns on
stdforbranches, which turso_core brings in
without it. On nightly that crate then callscore::intrinsics::abort,
which nightly removed on 2026-10-27, so every fuzz run had failed to build.
esdev@0.24.0
Removed
esdev <file> --import-policy(D194), with esrun's: a dependency policy is
applied byesdev build, which names it inesdev.json.
Added
esdev buildapplies the import policyesdev.jsonnames as
build.importPolicyto what every build ships (D193): each module read into
a bundle, for every target and the dev loop's builds. A deployed bundle
inlines its packages, so the runtime loader never saw them and a policy
governed nothing that shipped. A refusal lists every refused package and
writes nothing;"unlisted": "warn"reports instead; build tools whose code
does not ship are never judged.- An import policy's
allowentries can pin a package:
{ "package": "zod", "version": "3.23.8", "integrity": "h1:…", "reason": "…" }.
esdev buildchecks each shipped copy's installed version and, where
integrityis given, Go'sh1:hash of its installed files; a mismatch
fails the build in every mode (D193). esdev build --inventory=<file>writes what the build shipped as a draft
import policy — each package's version andh1:hash, an emptyreason,
and the project's own directories — for a security team to review and
commit. The configured policy is still applied, and the draft is written
even when it refuses; the reviewed file itself is never overwritten.build.subresourceIntegrityaddsintegrity="sha384-…"to every
<script>and stylesheet,preloadormodulepreload<link>a release
HTML build writes, so a browser refuses a file that changed after the build.
Off by default, as a CDN that rewrites files breaks it.
Changed
- The programs esdev runs get
RUNTIME_ENVwhen the shell has not set it
(D192):developmentforesdev <file>and the serveresdev startruns,
testunderesdev test, soenvironment()inruntime:processsays
where code is running.esdev buildstill defines only
process.env.NODE_ENV, which describes the build. esdev --install-typesadds itscompilerOptions.typesentry to a
tsconfig.jsonwith comments or trailing commas, keeping both and the
file's layout, where it used to leave such a file alone and print the lines
to add (D191). A file that is not valid JSONC is still left alone, and says
so.- The
spa,fullstack,docsandlibrarystarters follow the framework's
rename from OTF Web to AFW: they depend on
@opentf/esdev-plugin-afw,@opentf/afw,@opentf/afw-docs,
@opentf/afw-cliand@opentf/afw-test, the docs config is
afw.config.js, routes come from@afw/routes, and TypeScript projects get
afw-env.d.ts. The menu group reads "AFW". Projects scaffolded earlier keep
working on the@opentf/web*packages they were pinned to.
Removed
esdev buildandesdev startno longer recognise a project built by the
retiredotfwCLI (anotfw.config.js, or scripts callingotfw) to point
at its own toolchain. AFW projects are esdev projects with anesdev.json;
a directory without one gets the ordinary missing-esdev.jsonerror.
Fixed
-
esdev build --minifykeeps the space after a closing]or)in a
selector, which is the descendant combinator:[data-theme="dark"] *was
written as[data-theme="dark"]*, which matches the themed element alone.
Every Tailwinddark:utility built on a class or attribute variant matched
only<html>, so a minified site's dark mode left its own components light.
[open] .xand:not(.a) .blost their space the same way. -
The
docsstarter builds its search index: its config named an unknown
search provider (otf), so the build skipped the index and the navbar
search had nothing to query. The fullstack starter's sample middleware
sendsx-powered-by: afw. -
The
docsstarter's root layout uses the theme'safwd-shellclasses, so
the navbar, page and footer stack as the theme lays them out.
Testing / CI
- The hot-replacement tests attach to the browser's page rather than to the
first target its debugger lists. Newer Chrome lists its own UI and its
extensions' service workers first, so every test waited on a page that was
not there and failed on the Ubuntu 26.04 runner. The browser's profile is
now kept outside the watched project, where each write the browser made to
it was a rebuild and a reload the test had not asked for.