Skip to content

v0.1.16

Choose a tag to compare

@github-actions github-actions released this 04 Sep 15:31
· 18 commits to main since this release

Reformat what the strictness pass reflowed

Two files-worth of blank lines and one long call the formatter wraps
differently now that a helper sits above them. CI resolves biome from a
caret range and installs a newer one than the lockfile pins.

Turn on noUncheckedIndexedAccess

It was not missing here — it was explicitly false, in sixteen of the
seventeen tsconfigs. eon alone had it on, which is why nobody had seen
what it finds.

It stays a named deviation from upstream: @adonisjs/tsconfig sets
strictNullChecks and noImplicitAny but not this one. We keep it because
turning it on is what caught an as asserting a possibly-absent regex
group was a known value — the exact shape the flag exists to find. Doing
better than upstream is kept and written down, not reverted to parity.

Every site is restated rather than silenced: no !, no cast, no ?? 0
standing in for a branch that cannot happen. A reversed copy read by
value where an index walked a callback list backwards, the winner of a
scan kept as the value it found rather than its position, destructuring
where a length check was doing the proving, and an explicit break where a
loop condition already bounds the read.

Say what container.make() returns for the tokens this package binds

ream declares ContainerBindings open on purpose: it registers its own
entries and expects each package to contribute the ones it owns — its
comment on the interface names auth (warden), logger (spectrum) and db
(atlas) as exactly this. None of them did, and every other package that
binds a string token was in the same state, so container.make('cache'),
make('mail'), make('hash') and the rest all answered unknown and
every call site had to assert a type it could not prove.

Loaded from the barrel AND from the provider, the second of which is where
AdonisJS puts its own (providers/redis_provider.ts carries the
declare module for redis, database_provider.ts for lucid.db).

Verified live rather than assumed: a declare module naming a specifier
that does not resolve is silently inert, so renaming the member has to
break the compile. It does.

Release 0.1.16

Stop nl2br and classNames from emitting unescaped user input

Both marked their result as a SafeString, which means "already escaped, print
verbatim". Neither escaped anything, so {{ }} — the form that reads as safe —
emitted whatever was passed in as live markup.

{{ nl2br(comment) }}
comment = "hi\n<img src=x onerror=alert(1)>"
→ hi<br><img src=x onerror=alert(1)>

<i class="{{ html.classNames(c) }}">
c = 'a" onmouseover="alert(1)'
→ <i class="a" onmouseover="alert(1)">

nl2br is the worse of the two: it exists to print the multi-line text a user
typed, so its input is hostile by definition, and the output is a stored XSS on
any view that renders a comment, a description or an address.

Edge returns a plain string from both. There, {{ }} escapes it, and a caller
who wants markup types {{{ }}} — the unescaping is a choice the developer
writes out. Returning a SafeString reached that same output with no such choice
made anywhere.

classNames now matches Edge exactly: a plain string. Escaping changes nothing
about a legitimate class name, which contains no character that escapes.

nl2br keeps its SafeString but escapes the text before inserting the breaks —
a NAMED DEVIATION, and a hardening one. Edge's plain string would be escaped by
{{ }} and the <br> would never render, making the helper useless outside
{{{ }}}. Escaping first keeps the breaks working and takes the trap out.
html.safe() still passes through untouched, so the opt-in remains.

Move thiserror to 2

Move the NAPI bindings to napi 3

The Rust needed no change; the toolchain did. napi-derive 3 writes one type-def
file per crate into NAPI_TYPE_DEF_TMP_FOLDER and panics outright when it sees
the old single-file TYPE_DEF_TMP_PATH — that variable is how it detects an
out-of-date toolchain, so the failure reads as "upgrade @napi-rs/cli" even
though the generator here is our own.

It also emits a function as a bare function name(...) where 2 emitted the
signature alone, so concatenating the name onto it produced
function xfunction x(...). The generator handles all three shapes now.

napi-build stays at 2 — there is no 3 on crates.io.

Verified by what the migration could break rather than by it compiling: the
generated src/native/generated.ts comes out byte-identical to the napi 2 one,
and the native binary is rebuilt and exercised by the JS suite.


Changes since v0.1.15.