Skip to content

v0.1.15

Choose a tag to compare

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

Apply the store rules to every store, not just one

The rules in _internal/subscription.ts say what makes a subscription usable
and that they hold on the way in and on the way out. The file store applies
them; the other two did not.

The Redis store's guard checked that three fields were strings and declared the
value a StoredSubscription — a claim about expirationTime, which it never
looked at. A record with a truncated p256dh, or with no expirationTime at
all, came back whole and reached web-push, where it fails as an encryption
error naming neither the record nor the endpoint. Nothing ever cleans it up:
cleanup runs on a 404 or 410 from the push service, and that request was never
made. It is now read through the same check the file store uses, and refuses to
store what it would refuse to read. The SQL store gets the same check on the
way in — a column type checks a length, not what a P-256 point looks like.

A default naming a store that is not in stores was already refused, for the
reason written beside it: an application that meant to persist subscriptions
and silently got the in-memory driver only finds out when a restart has lost
them all. With no stores block at all the check was skipped entirely, and a
deployment asking for sql booted on memory.

nova:vapid:generate wrote the key that signs every push into a .env left to
the umask — 0644 on a default image, where every other process in the container
can read it. It creates the file 0600 now, and reports rather than changes the
permissions of one that already exists.

Also removes the casts the compiler was being lied to through: an index
assertion in the base64url helpers, a narrowed property re-asserted inside a
closure, a router context asserted back into shape by the handler that receives
it, and two in the quasar bridge whose checks were already guards.

And lets the gates run. CI typechecked only the build project, which excludes
tests; lint skipped them too, which is where the three unsafe optional chains
it now reports were sitting. Vitest ran without coverage, so the thresholds
were never a gate — they are raised to just under what the suite reaches, and
@vitest/coverage-v8 is declared and pinned, since a standalone clone resolves
it fresh and v8 branch-counting moves between releases.

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.

Release 0.1.15

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.

Move jsdom to 30

The client tests run on it; nothing in the 30 line touched what they use.

Typecheck the tests, and turn on noUnusedLocals/noUnusedParameters

tsconfig named tests in include AND in exclude, and exclude wins — so
nothing under tests/ was ever typechecked, while the config claimed otherwise.
Four gaps had accumulated behind that:

  • subscribe-route kept its own copy of NovaAppContext whose resolve was
    synchronous, where the real one is async. It now uses the exported type, so
    the fake cannot drift from what the provider is handed again.
  • store-selection's container stub narrowed its tokens to string where
    ContainerLike says string | symbol.
  • service-accessor's fake declared pushToUser with one parameter where the
    real one takes two or three.
  • Two mockImplementation callbacks took an implicit any.

Changes since v0.1.14.