Skip to content

fix: four defects found by Payload's own e2e suites (0.1.2) - #3

Merged
Mheaus merged 6 commits into
mainfrom
fix/flight-key-validation
Oct 9, 2026
Merged

Mheaus merged 6 commits into
mainfrom
fix/flight-key-validation

Conversation

@Mheaus

@Mheaus Mheaus commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Stacked on #2. Found by running Payload's own e2e suites against the adapter (Payload monorepo at v4.0.0-canary.39, PAYLOAD_FRAMEWORK=react-router).

Problem

loadAdminPage renders the admin view to the end, decodes the Flight stream, and React Router sends the decoded tree to the browser a second time. Decoding sets the key-validation flag of some elements back to 0, so in development React logged "Each child in a list should have a unique key prop. Check the render method of RouteId" for lists that were valid. Payload's e2e harness fails a test on any console error: 6 of the 15 auth tests failed on it.

Fix

markKeysValidated sets the flag again on the decoded tree, through arrays and resolved lazy nodes, in development only. React still validates keys when the view first creates its elements, so a real missing key is still reported on the server console.

Second fix: process in pre-bundled browser dependencies

processInClient replaces process.env and process.cwd() in browser code, but Vite pre-bundles node_modules dependencies before any plugin transforms them. A Next.js package that a Payload config imports then throws process is not defined in the browser: next/link reads process.env.__NEXT_ROUTER_BASEPATH. Payload's fields suites import next/link in their nav component, so every test of each suite failed (fields__collections__Array: 0/34).

The same replacement now runs as a Rolldown plugin of the client environment's dependency optimizer; server environments keep the real process. fields__collections__Array: 34/34, against 31/34 on TanStack Start on the same machine. New unit test.

Third fix: admin metadata

loadAdminPage kept only the title and description of Payload's page metadata. Robots (noindex, nofollow by default), Open Graph, Twitter cards and the configured favicons were missing: 8 admin tests failed. toAdminPageMeta now converts the whole MetaConfig (ported from @payloadcms/tanstack-start, MIT, credited in LICENSE) and AdminPage renders the tags. The admin metadata group: 17/18, the last one is a dev-server WebSocket drop.

Fourth fix: version-diff components inside the Payload monorepo

@vitejs/plugin-rsc wraps every exported capitalized function of a CSS-importing module as a server component. The Lexical diff converters are such functions, so the wrapper broke them and rich text diffs showed "unknown node". stripDistStyleImports removes their CSS imports, but its pattern did not match the /packages/<pkg>/src/ paths of the Payload monorepo. Published installs were not affected. The versions diff group: 45/46, the failure is shared with Next.js.

The full per-suite comparison with Next.js is in docs/COMPAT.md.

Results

  • Payload auth suite on React Router: 14/15 (was 1/15). Next.js on the same machine and database (SQLite): 14/15, with the same failing test, which comes from the suite itself.
  • Adapter unit tests: 19/19 (three new). Demo bench: 36/36 on the production build and on vite dev.
  • Version 0.1.2.

🤖 Generated with Claude Code

@Mheaus Mheaus changed the title fix(server): keep list children validated after the admin view render fix: two defects found by Payload's own e2e suites (0.1.2) Oct 9, 2026
@Mheaus Mheaus changed the title fix: two defects found by Payload's own e2e suites (0.1.2) fix: four defects found by Payload's own e2e suites (0.1.2) Oct 9, 2026
@sakuga-agent
sakuga-agent Bot force-pushed the test/server-function-access branch from 032a1db to f771228 Compare October 9, 2026 18:28
@sakuga-agent
sakuga-agent Bot force-pushed the fix/flight-key-validation branch from 89358b3 to d1871bf Compare October 9, 2026 18:28
@Mheaus
Mheaus changed the base branch from test/server-function-access to main October 9, 2026 18:30
Mheaus added 6 commits October 9, 2026 20:31
loadAdminPage renders the admin view to the end, decodes the Flight stream, and React Router sends the decoded tree to the browser a second time. Decoding sets the key-validation flag of some elements back to 0, so React logged "Each child in a list should have a unique key" in development for lists that were valid. Payload's e2e harness fails a test on that console error: 6 of the 15 auth tests failed on it.

markKeysValidated sets the flag again on the decoded tree, through arrays and resolved lazy nodes, in development only. React still validates the keys when it creates the elements, so a missing key is still reported on the server console.

Version 0.1.2.
…pre-bundles

processInClient replaces process.env and process.cwd() in browser code, but Vite pre-bundles the dependencies of node_modules before any plugin can transform them. A Next.js package that a Payload config imports then throws "process is not defined" in the browser: next/link reads process.env.__NEXT_ROUTER_BASEPATH. Payload's fields e2e suites import next/link through their nav component, and every test of each suite failed on it (Array: 0/34).

The same replacement now runs as a Rolldown plugin of the client environment's dependency optimizer. Server environments keep the real process. Array: 34/34, against 31/34 on TanStack Start on the same machine.
…tags

loadAdminPage kept only the title and the description of Payload's page metadata. The robots tag (noindex, nofollow by default), Open Graph, Twitter cards and the configured favicons were missing: 8 tests of Payload's admin e2e suite failed on them.

toAdminPageMeta now converts the whole MetaConfig, ported from @payloadcms/tanstack-start so both adapters render the same tags, and AdminPage renders them. React hoists them into the document head.
…yload's monorepo too

@vitejs/plugin-rsc wraps every exported, capitalized function of a module that imports CSS as a server component. The Lexical diff converters (RelationshipDiffHTMLConverterAsync and the others) are such functions but return converter objects, so the wrapper broke them: the relationship and unknown converters disappeared, and rich text diffs showed "unknown node". stripDistStyleImports prevents this by removing their CSS imports, but its pattern only matched @payloadcms/<pkg>/(dist|src) paths.

Inside the Payload monorepo, these modules resolve to /packages/<pkg>/src/. The pattern now matches that form too. Published installs were not affected. Payload's versions diff view suite: 45/46, the remaining failure is shared with Next.js.
@sakuga-agent
sakuga-agent Bot force-pushed the fix/flight-key-validation branch from d1871bf to 6264dff Compare October 9, 2026 18:31
@Mheaus
Mheaus merged commit 84452f5 into main Oct 9, 2026
3 checks passed
@Mheaus
Mheaus deleted the fix/flight-key-validation branch October 9, 2026 18:37
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