fix(next-config): redirect Magento account URLs to the GraphCommerce routes - #2660
Conversation
…routes
Magento renders links from base_link_url, which on a headless setup points
at the GraphCommerce storefront. Every stock email template contains a
customer/account/ link ("Sign in to your account") and gated Magento routes
302 to customer/account/login — GraphCommerce serves none of those, so
customers landed on a 404.
withGraphCommerce now adds permanent redirects for /customer/account,
/customer/account/index, /customer/account/login, /customer/account/create,
/customer/account/forgotpassword and /sales/order/history. They are exact
matches on purpose: redirects run before the filesystem routes, so a
/customer/account/:path* catch-all would shadow the
pages/customer/account/{confirm,createPassword} routes that
@graphcommerce/magento-customer copies into the project.
This restores the /customer/account redirect that was dropped as collateral
in "Remove redirects for /product/$type/[url] routes".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: a3a45d2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 86 packages
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 |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| source: "/customer/account/forgotpassword", | ||
| destination: "/account/forgot-password", | ||
| permanent: true | ||
| }, |
There was a problem hiding this comment.
I think this is incorrect? We already have a path for this in the examples? As the forgotPassword also carries a token etc.
There was a problem hiding this comment.
Written by Claude Code:
You're right that it should go — dropped in a3a45d2. The reasoning is slightly different from yours though, and the difference matters for the entries I kept, so let me lay out what I actually found.
There is no forgotpassword page. Full inventory of what GraphCommerce serves under /customer/, across all three examples:
examples/magento-graphcms/pages/customer/account/confirm.tsx
examples/magento-graphcms/pages/customer/account/createPassword/index.tsx
examples/magento-open-source/pages/customer/account/confirm.tsx
examples/magento-open-source/pages/customer/account/createPassword.tsx
examples/magento-storyblok/pages/customer/account/confirm.tsx
examples/magento-storyblok/pages/customer/account/createPassword.tsx
That's it — confirm and createPassword. /account/forgot-password exists, but that's the GraphCommerce route and it was the destination of the redirect, not the source. (Also worth correcting something I wrote in the original comment: @graphcommerce/magento-customer has no copy/ directory, so these aren't copy-pages — they're scaffolded from the examples.)
The token is on createPassword, not on forgotpassword. Grepping every stock Magento email template for customer URLs:
'customer/account/' → [_nosid:1] 48x
'customer/account/createPassword' → [_query:[id, token: $customer.rp_token, …]] 12x
'customer/account/confirm/' → [_query:[id, key: $customer.confirmation, …]] 2x
forgotpassword appears in zero templates. It's the form where a customer types their email address; the reset link Magento mails out points at createPassword with id + rp_token. So the entry wasn't dangerous — it just had no evidence behind it, which is a good enough reason to cut it.
Why the rest are safe, stated properly. The mechanism I should have named up front: a redirects() entry is evaluated before the filesystem routes, so redirecting a path that has a page makes that page unreachable. confirm and createPassword are exactly the two pages that carry a one-shot token, so making either unreachable would break account confirmation and password reset outright. That's why every source is an exact match and why a /customer/account/:path* catch-all is off the table. Re-audited against the inventory above:
| source | collides with a page? |
|---|---|
/customer/account |
no |
/customer/account/index |
no |
/customer/account/login |
no |
/customer/account/create |
no — exact match, does not cover /customer/account/createPassword |
/sales/order/history |
no |
That fourth row is the one that looks alarming at a glance and I suspect is what caught your eye. Next matches source against the full path, so /customer/account/create and /customer/account/createPassword are distinct routes; the redirect fires only on the former. I've made the comment in the code say all of this explicitly instead of hand-waving at "shadowing".
On evidence tiers for what's left, so you can trim further if you'd rather: /customer/account is the strong one (48 email templates). /customer/account/login is backed in-repo — magento-product-downloadable's copy pages already sniff for that string in Magento's 302 Location. /customer/account/index is the same controller action as the first, same destination, zero risk. /customer/account/create and /sales/order/history are the weakest — no direct hit in the mail templates, just canonical Magento entry points people bookmark or land on from an old indexed URL. Happy to drop those two as well if you'd prefer the list to be strictly email-evidenced.
Mirrored downstream in ho-nl/project-jumbosports-gc (b48a202) so the project list stays identical to this one.
Review feedback: the entry had no evidence behind it. Grepping every stock Magento email template shows only three customer URLs — customer/account/ (48x), customer/account/createPassword (12x, carries id + rp_token) and customer/account/confirm (2x, carries id + key). forgotpassword appears in none of them; Magento's reset token rides on createPassword, and forgotpassword is just the form where a customer types their email. The remaining five are re-audited for shadowing. GraphCommerce serves exactly two paths under /customer: confirm and createPassword, both real pages in all three examples. None of the five sources collide with them (/customer/account/ create is an exact match and does not cover createPassword), and the comment now states the mechanism that makes this matter: a redirect wins over a filesystem route, so redirecting a path that has a page makes that page unreachable. Also corrects the comment's claim that @graphcommerce/magento-customer copies those pages in — it has no copy/ directory; they are scaffolded from the examples. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Written by Claude Code:
Magento builds its own frontend URLs from
base_link_url. On a headless setup that value points at the GraphCommerce storefront, so every stock transactional email ships a link GraphCommerce cannot serve:createPasswordandconfirmare covered — all three examples shippages/customer/account/{confirm,createPassword}(they are scaffolded from the examples;@graphcommerce/magento-customerhas nocopy/directory).customer/account/is not, and it is the single most common link in the whole email set ("Sign in to your account", in the footer of every order/invoice/shipment/credit-memo mail). It 404s.There used to be exactly this redirect, added in #1936 and moved into
withGraphCommerceshortly after. It was dropped as collateral in "Remove redirects for/product/$type/[url]routes" (2c79a4c) — that commit removed the wholeredirects()block, and the/customer/accountentry happened to live in the same array. This restores it and adds the neighbouring URLs that Magento also emits.The list
/customer/account/account/customer/account/index/account/customer/account/login/account/signinLocationon gated Magento routes —magento-product-downloadable's copy pages already sniff for this string/customer/account/create/account/signin/account/signinrenders both sign-in and sign-up/sales/order/history/account/ordersWhy exact matches, not
:path*A
redirects()entry is evaluated before the filesystem routes, so redirecting a path that has a page makes that page unreachable. GraphCommerce serves exactly two paths under/customer/:confirmandcreatePassword— the two carrying Magento's one-shot confirmationkeyand resetrp_token. A catch-all would break account confirmation and password reset outright, so every entry stays an exact source. Note that/customer/account/createis a distinct route from/customer/account/createPasswordand does not cover it.Dropped after review (a3a45d2):
/customer/account/forgotpasswordwas in the first revision. It shadows nothing — there is noforgotpasswordpage anywhere in the examples — but it appears in zero email templates, and Magento's reset token rides oncreatePassword, not on it. No evidence, so it's gone.Notes
redirects()keep working:withGraphCommerceawaitsnextConfig.redirects()first and appends, and Next.js takes the first match, so a project override wins.dist/index.jsis updated alongsidesrc/per the convention in this package.🤖 Generated with Claude Code