Skip to content

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

Draft
ryansolid wants to merge 1 commit into
nextfrom
flash-async-decoder
Draft

Require the async (encrypted) flash decoder in the submissions seed (solidjs/solid#3239)#597
ryansolid wants to merge 1 commit 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: 8edac15

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
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