Skip to content

Require the async (encrypted) flash decoder in the submissions seed (solidjs/solid#3239) - #597

Merged
ryansolid merged 2 commits into
nextfrom
flash-async-decoder
Sep 8, 2026
Merged

Require the async (encrypted) flash decoder in the submissions seed (solidjs/solid#3239)#597
ryansolid merged 2 commits into
nextfrom
flash-async-decoder

Conversation

@ryansolid

@ryansolid ryansolid commented Sep 4, 2026

Copy link
Copy Markdown
Member

Summary

Companion to the encrypted no-JS flash cookie in @solidjs/web (solidjs/solid#3239, commit solidjs/solid@fbe5bef4): the flash payload carries the submitted form input, so it is now AES-GCM encrypted and decodeFlashCookie is async (WebCrypto has no sync API). The provideFlashDecoder slot now takes exactly that shape — async only, no sync compatibility path to forget about later — and the submissions seed absorbs the Promise.

How the server handles it

The seeding read moves into a memo created only when a flash cookie actually arrived, and the in-flight decode rides NotReadyError — the same SSR spelling the router already uses for unresolved lazy route matches:

  • Throws from a reactive node, never router setup. The memo is what parks; whatever scope read useSubmission resumes into the settled result.
  • At most one decode per request. The decode outcome is cached at router scope, so the parked reader's rerun (and any concurrent reader) finds the settled value rather than restarting the work.
  • No cost without a read. Server memos compute eagerly by default; lazy: true defers to the first submissions read, so a request that renders without touching useSubmission never decodes — and a request without a flash cookie never creates the memo at all. (The eager half — detection + one-shot clear — is unchanged.)
  • Hydration ids stay aligned. The memo exists on the server only; the client seeds [] without ever creating it. transparent: true keeps its owner out of the hydration-id chain, so sibling ids don't shift (the #3012 class of bug).

The one temporary line

The provide site wraps the runtime export in an async arrow (provideFlashDecoder(async h => decodeFlashCookie(h))) only because the installed rc.6 still types it synchronous; it carries a TODO(@solidjs/web >= 2.0.0-rc.7) to pass decodeFlashCookie directly with the dep bump in this PR.

Tests

The flash-seeding server spec now runs the async shape throughout: the parking round-trip (first read throws NotReadyError, resumed read seeds from a decode that ran exactly once), the laziness guarantee (a rendered request that never reads submissions never decodes, while the one-shot clear still lands), and the existing seeding/pre-seed/no-cookie contracts through a parked read helper. Full suite: 395 client + 35 server + type tests pass.

Draft until @solidjs/web 2.0.0-rc.7 ships the encrypted flash runtime; lands in unison with solidjs/solid-vite-plugin#343 (deployment-secret injection).

@changeset-bot

changeset-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7e7e34a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solidjs/router Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

…eed (solidjs/solid#3239)

The flash cookie is now AES-GCM encrypted, so the runtime's
decodeFlashCookie is async (WebCrypto has no sync API). The
provideFlashDecoder slot takes exactly that shape — no sync
compatibility path to forget about later — and the submissions seed
absorbs the Promise through the not-ready protocol:

- The decode is cached at router scope: at most one per request, and a
  parked reader's rerun finds the settled outcome rather than
  restarting it.
- The seeding read lives in a memo, so NotReadyError surfaces from a
  reactive node the graph can park and retry — never from router setup,
  which no boundary guards — bounding the recompute to the memo plus
  the readers that actually consumed it.
- lazy: server memos compute eagerly by default; deferred to first
  read, a request whose submissions are never read never decodes, and
  a request without a flash cookie never creates the memo at all.
- transparent: the memo exists on the server only (the client seeds
  submissions as [] without it), so its owner must not consume a
  hydration-id slot the client would miss — sibling ids stay aligned.

The provide site wraps decodeFlashCookie in an async arrow only because
rc.6 still types it synchronous; the wrapper is marked for removal with
the rc.7 dep bump.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ryansolid ryansolid changed the title Absorb the async (encrypted) flash decoder in the submissions seed (solidjs/solid#3239) Require the async (encrypted) flash decoder in the submissions seed (solidjs/solid#3239) Sep 4, 2026
rc.7 ships the async, encrypted flash codec (solidjs/solid#3239) this
branch's provideFlashDecoder slot requires, so the peer and dev floors
move to ^2.0.0-rc.7 together and the lockfile resolves rc.7. Pass
decodeFlashCookie to the slot directly now that it is typed async, and
drop the spec's sync-compat wrapper. The changeset states the floor.

Reviewed the rest of the rc.7 changelog against the router: the dev
artifact renames (bd22ac8) touch nothing here (no dist/dev imports); the
flash url now recording the unbound base (d0ca3a4) is exactly the
`s.url === fn.base` match useSubmission already performs; falsy no-JS
outcomes (f21e060) ride the seed's spread verbatim; GET grants bound to
function identity (1226381) match query/liveQuery's module-scope
`GET(fn)` on the registered reference.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ryansolid
ryansolid marked this pull request as ready for review September 8, 2026 17:04
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​solidjs/​web@​2.0.0-rc.6 ⏵ 2.0.0-rc.710010083 +197100
Updatedsolid-js@​2.0.0-rc.6 ⏵ 2.0.0-rc.7100 +110095 +196100

View full report

@ryansolid
ryansolid merged commit e0c244d into next Sep 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant