Skip to content

fix(pages): keep the named action key first when a redirect repeats the request - #533

Merged
Brooooooklyn merged 3 commits into
mainfrom
fix/action-key-first
Oct 21, 2026
Merged

Brooooooklyn merged 3 commits into
mainfrom
fix/action-key-first

Conversation

@Brooooooklyn

Copy link
Copy Markdown
Member

Follow-up to #530 (Codex finding on that PR, which got merged before this fix landed).

Problem

A redirect that sends the same request again keeps the action key (307/308, or 301/302 after PUT/PATCH/DELETE). When the destination has its own query, the merge put the key after the destination's params:

PUT /books?delete&page=2 → c.redirect('/books-v2?tab=details', 302)
→ /books-v2?tab=details&delete=&page=2      repeated PUT picks "tab" ✗

Fix (only in the c.redirect wrapper)

Destination Result
/books-v2?tab=details (another page) /books-v2?delete&tab=details&page=2 (key first, as sent)
/books-v2?tab=1&delete=x (sets the key too) /books-v2?delete=x&tab=1&page=2 (its value wins, moves first)
/books?archive (same page, own first key) /books?archive=&page=2 (that key picks the action)
/books-v2? (bare reset) /books-v2?delete (rest dropped, key kept)
/books-v2 (no query) /books-v2?delete&page=2 (unchanged, byte for byte)
#fragment stays last

Unchanged: GET follow-ups (key dropped), unmarked requests, mergeQueryIntoLocation, redirect rules and platform dispatch.

Known limit: a redirect to a different page whose first query key is one of that page's actions (c.redirect('/other?archive', 307)) still puts the request's key first. The redirect code can't tell an action key from a normal param on another page.

Tests

routing-runtime.test.ts: 10 new rows in the named-action table (307 and PUT 302 with a destination query, a valued key, a fragment, a bare ?, the same key in the destination, a same-page action key). 9 fail on main. The POST 302 row passes on main too: it checks the GET follow-up stays unchanged. routing-runtime, pages-client, pages-compile and compile tests: 205/205. Lint, format and typecheck are clean.

🤖 Generated with Claude Code

…he request

A redirect that keeps the action key (307/308, or 301/302 after PUT,
PATCH or DELETE) merged it after the destination's own query, so
PUT /books?delete&page=2 + c.redirect('/books-v2?tab=details', 302) went
to /books-v2?tab=details&delete=&page=2 and the repeated PUT picked
"tab" as the action.

- Destination with its own query: the key goes first again, as sent;
  if the destination sets the same key, its value wins and moves first.
- Same page with its own first key (c.redirect('/books?archive', 307)):
  that key picks the action, and the request's key is dropped.
- A bare "?" still drops the rest of the query but keeps the key.
- No destination query, GET follow-ups and redirect rules are unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-21T11:06:31.706426Z 4a18878 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Brooooooklyn

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1910f371d8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/void/src/runtime/routing.ts Outdated
Only the destination's own value for the action key replaces the key.
Before, a repeated key in the request query (?moveTab&moveTab=secondary)
was promoted and the first one was dropped.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Brooooooklyn

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 4a1887816f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://fix-action-key-first-void-cloud.voidzero-docs.workers.dev (commit 69c68c3)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://d089671a-void-cloud.voidzero-docs.workers.dev 69c68c3 2026-10-21T11:17:00.514Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://1905218a-void-cloud.voidzero-docs.workers.dev 4a18878 2026-10-21T11:06:25.551Z Visit the dashboard ↗

The suspension and route-disable race tests attach a handler to the
racing promise only after awaiting the lock waiter and the competing
transaction. If the promise rejects first, Vitest reports an unhandled
rejection and fails the file even though every test passed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Brooooooklyn
Brooooooklyn merged commit 957026d into main Oct 21, 2026
20 checks passed
@Brooooooklyn
Brooooooklyn deleted the fix/action-key-first branch October 21, 2026 12:26
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