feat: show a clear error when trying to use CAAPI untunnelled in localhost#3504
feat: show a clear error when trying to use CAAPI untunnelled in localhost#3504fredericoo merged 10 commits intomainfrom
Conversation
|
Oxygen deployed a preview of your
Learn more about Hydrogen's GitHub integration. |
| throw new Response( | ||
| [ | ||
| 'Customer Account API OAuth requires a Hydrogen tunnel in local development.', | ||
| 'Run `shopify hydrogen dev --customer-account-push`.', |
There was a problem hiding this comment.
note: these commands can also be aliased as just h2 dev rather than shopify hydrogen dev. i don't think the message needs to be updated but if you can think of a good way to communicate that either one works, go for it
There was a problem hiding this comment.
thats very fair
i made it more generic just mentioning to use the flag. if they got to this screen it means they know how to start the dev server, and however they did, they can just add the flag to the end
There was a problem hiding this comment.
yep exactly, i think that's super reasonable!
|
🤖 Code Review · #projects-dev-ai for questions ✅ Complete - No issues 📋 History✅ No issues → ✅ No issues → ✅ No issues → ✅ No issues → ✅ No issues |
a681ba2 to
dceae08
Compare
| await customer.login(); | ||
| } catch (error) { | ||
| const response = error as Response & {message?: string}; | ||
|
|
There was a problem hiding this comment.
non-blocking: these tests work correctly because the test file globally stubs Response with a mock class at lines 26-38 that stores the constructor's body argument as .message. This is a pre-existing test pattern, not something this PR introduced.
The tests are correct and pass as intended. However, .message is a non-standard property that only exists due to this mock - the standard Response Web API doesn't have it. If the test environment or mock strategy ever changes, these assertions would silently break. Using await response.text() would be the spec-compliant approach, but since this follows the existing pattern throughout the file, I'm fine with this shipping as-is.
| throw new Response( | ||
| [ | ||
| 'Customer Account API OAuth requires a Hydrogen tunnel in local development.', | ||
| 'Run `shopify hydrogen dev --customer-account-push`.', |
There was a problem hiding this comment.
yep exactly, i think that's super reasonable!
The development-only tunnel domain check (throwIfNotTunnelled) added in #3504 blocks legitimate HTTPS setups like ngrok and local HTTPS proxies. Rather than loosening the check entirely (which re-introduces the DX gap that #3504 was designed to prevent), this adds an explicit opt-out via the useCustomAuthDomain boolean option. When set to true, the tunnel check logs a warnOnce with actionable guidance (including the redirect_uri to register) instead of throwing. Default behavior is unchanged — developers without the opt-out still get the original error directing them to use --customer-account-push. The implementation uses a closure pattern (ensureTunnel) inside createCustomerAccountClient to avoid pass-through parameters at all 6 call sites. The tunnel check was also extracted from defaultAuthStatusHandler into the authStatusHandler closure for consistent call-site ownership. Fixes #3619
The development-only tunnel domain check (throwIfNotTunnelled) added in #3504 blocks legitimate HTTPS setups like ngrok and local HTTPS proxies. Rather than loosening the check entirely (which re-introduces the DX gap that #3504 was designed to prevent), this adds an explicit opt-out via the useCustomAuthDomain boolean option. When set to true, the tunnel check logs a warnOnce with actionable guidance (including the redirect_uri to register) instead of throwing. Default behavior is unchanged — developers without the opt-out still get the original error directing them to use --customer-account-push. The implementation uses a closure pattern (ensureTunnel) inside createCustomerAccountClient to avoid pass-through parameters at all 6 call sites. The tunnel check was also extracted from defaultAuthStatusHandler into the authStatusHandler closure for consistent call-site ownership. Fixes #3619
…ck (#3642) * feat(hydrogen): add useCustomAuthDomain opt-out for tunnel domain check The development-only tunnel domain check (throwIfNotTunnelled) added in #3504 blocks legitimate HTTPS setups like ngrok and local HTTPS proxies. Rather than loosening the check entirely (which re-introduces the DX gap that #3504 was designed to prevent), this adds an explicit opt-out via the useCustomAuthDomain boolean option. When set to true, the tunnel check logs a warnOnce with actionable guidance (including the redirect_uri to register) instead of throwing. Default behavior is unchanged — developers without the opt-out still get the original error directing them to use --customer-account-push. The implementation uses a closure pattern (ensureTunnel) inside createCustomerAccountClient to avoid pass-through parameters at all 6 call sites. The tunnel check was also extracted from defaultAuthStatusHandler into the authStatusHandler closure for consistent call-site ownership. Fixes #3619 * refactor: rename throwIfNotTunnelled to checkTunnelDomain and flatten nesting The function no longer exclusively throws — when useCustomAuthDomain is enabled, it warns and returns. The new name better describes both code paths. Early returns replace the 3-level-deep nesting with flat, top-to-bottom guard clauses. Addresses review feedback from @itsjustriley. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add production no-op test for useCustomAuthDomain Verifies that checkTunnelDomain is inert outside of development — the NODE_ENV !== 'development' early return must prevent any warning or throw in production, regardless of the useCustomAuthDomain flag. This guards against accidental removal of the environment gate. Addresses review feedback from @itsjustriley. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add useCustomAuthDomain coverage for mutate, logout, and authorize Completes tunnel-check test coverage across all six ensureTunnel call sites. Previously only login, query, and handleAuthStatus were tested. This ensures that any method-specific regression in the tunnel check wiring would be caught. Addresses review feedback from @itsjustriley. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


WHY are these changes introduced?
Local development has a bad failure mode for Customer Account OAuth:
When a developer opens
/accountonlocalhostwithout tunneling, the app redirects into the OAuth flow and eventually fails with a redirect URI error from Shopify. The error is late and unclear, so it does not tell developers what they need to do next.WHAT is this pull request doing?
HOW to test your changes?
pnpm --dir packages/hydrogen buildpnpm --dir packages/hydrogen test -- src/customer/customer.test.tshttp://localhost:3000/account400error page with guidance to use--customer-account-pushand a*.tryhydrogen.devURL.--customer-account-push) and open the provided*.tryhydrogen.devURL./accountcontinues into normal Customer Account login flow.Post-merge steps
None.
Checklist