Repository navigation
fix: give twinOf the request, and match the CSP nonce on hydration - #34
Conversation
twinOf got only the path, so a request with a query that rewrite sends to the framework still got the prerendered twin. twinOf now gets the Hono context, the same as rewrite, and undefined keeps the request off the twin. Fixes #33
HydratedRouter takes no nonce, so React warned that the server's nonce did not match. cspNonce() from @ngrok/app-server/client gives the same nonce on the server and in the browser. The README also shows twinOf with the request context. Fixes #32
🦋 Changeset detectedLatest commit: 6c6d629 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
PR Summary by QodoPass request context to twinOf and preserve CSP nonces during hydration
AI Description
Diagram
High-Level Assessment
Files changed (8)
|
Code Review by Qodo
1. Option summary takes four sentences
|
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are recorded for this change.
No open issues 🎉
What changed in this PR
This PR addresses request-aware markdown selection (#33) and CSP nonce hydration mismatches (#32) in @ngrok/app-server.
Changes:
- Pass the Hono context to
twinOfin development and production so apps can skip twins for specific requests. - Export
cspNonce()to read the request nonce on the server and the document nonce in the browser. - Add regression tests, update framework setup examples, and include two patch changesets.
Conventions pass: Applied Minimize reader load to keep the summary concise. Checked the supplied API documentation and changesets. Automated checks were not run because this review environment prohibits project execution.
| File | Description |
|---|---|
src/core/plugins/static.ts |
Pass the request context to markdown twin callbacks. |
src/core/plugins/static.test.ts |
Cover query-based twin exclusion in both environments. |
src/client/index.ts |
Export cspNonce. |
src/client/csp-nonce.ts |
Read the nonce on the server and in the browser. |
src/client/csp-nonce.test.ts |
Cover matching nonces and absent nonces. |
README.md |
Document request-aware twins and framework nonce setup. |
.changeset/twin-of-context.md |
Add patch release notes for request-aware twins. |
.changeset/csp-nonce-client.md |
Add patch release notes for cspNonce. |
Review effort: Balanced
Benchmarks
How this was measuredBase Machines:
|
The browser bundle kept the requestContext() branch of cspNonce(), which never runs there. The ./client export now has a browser condition, so Vite's client build gets a cspNonce() that only reads the document.
Why
twinOfgot only the path. So an app could not keep a request off the prerendered twin, such as a request with a query thatrewritesends to the framework.<HydratedRouter>takes no nonce. So in the browser,<Links>,<ScrollRestoration>, and<Scripts>rendered no nonce, and React warned that the hydration did not match.What
markdownTwins.twinOf(path, context): it gets the Hono context, the same asrewriteandheaders, in development and in production. If it givesundefined, the request gets no twin. AtwinOfwith one parameter works as before.cspNonce()in@ngrok/app-server/client. On the server, it givesrequestContext()?.cspNonce. In the browser, it reads the.nonceproperty of the document's first[nonce]element, because a browser hides the attribute's value. One call works inentry.server, the rootLayout, and TanStack'sgetRouter../clienthas abrowserexport condition (dist/client-browser.js). Vite's client build resolves it, so the browser gets acspNonce()with no server code. Vite's server build, Node.js, Bun, and Deno do not resolvebrowser. A test keeps the export names of both builds the same.Layoutstep. It usescspNonce()in each render snippet.twinOfgets one more argument.Results
cspNonceVite 8.3.5
libbuild of a one-line entry againstdist/, withminify: true, one run each. The numbers include the entry's ownconsole.logcall.