Skip to content

fix(region): route projects in any cloud region to their subdomain (DISCORD-15265968)#3119

Open
claudear wants to merge 1 commit into
mainfrom
fix/DISCORD-15265968-region-subdomain-cors
Open

fix(region): route projects in any cloud region to their subdomain (DISCORD-15265968)#3119
claudear wants to merge 1 commit into
mainfrom
fix/DISCORD-15265968-region-subdomain-cors

Conversation

@claudear

Copy link
Copy Markdown

What / Why

Reported via Discord (DISCORD-15265968): clicking a project in the organization view gets stuck, while the same action works from the internal impersonation tooling. Another user saw the browser throw CORS for the same flow.

Root cause

getRegionSubdomain() in src/lib/helpers/apiEndpoint.ts resolved a project's regional subdomain through a hardcoded switch that only knew fra / syd / nyc / sfo / sgp / tor. Any project hosted in a region outside that list fell through to the empty default, so buildRegionalV1Endpoint() left the hostname unchanged and the SDK issued requests to the apex host (or whatever region is baked into APPWRITE_ENDPOINT) instead of the project's real regional host, e.g. blr.cloud.appwrite.io.

Those cross-origin requests failed the CORS preflight and the navigation hung. The impersonation tooling opens the project against its correct regional endpoint directly, which is why it was unaffected.

The set of Appwrite Cloud regions is dynamic and grows over time, so a hardcoded list is inherently fragile — every new region silently breaks project navigation until the switch is updated.

Fix

  • Derive the subdomain directly from the region id (`${region}.`) so any current or future region routes correctly. The default placeholder (and empty/undefined values) still resolve to the apex domain.
  • stripLeadingRegionSubdomain() now also strips the region that is about to be prepended, preventing a doubled subdomain (blr.blr.cloud…) when the console itself is served from that region.

Tests

Added src/lib/helpers/apiEndpoint.test.ts covering:

  • well-known regions still map correctly,
  • regions outside the hardcoded set (the regression) now resolve to their own subdomain,
  • default/empty/undefined → apex,
  • endpoint building for apex/regional hosts and the no-double-subdomain edge case.

The new tests fail against the previous logic (unlisted region → apex → CORS) and pass with this change.

🤖 Generated with Claude Code

…5265968)

Clicking a project in the organization view got stuck for projects hosted
in an Appwrite Cloud region that was not part of the hardcoded region list.

getRegionSubdomain() resolved a project's regional subdomain via a switch
that only knew fra/syd/nyc/sfo/sgp/tor. Any other region fell through to the
empty default, so buildRegionalV1Endpoint() left the host unchanged and the
SDK issued requests to the apex host (or the region baked into
APPWRITE_ENDPOINT) instead of the project's real regional host
(e.g. blr.cloud.appwrite.io). Those cross-origin requests failed CORS and the
navigation hung. The impersonation tooling targets the correct regional
endpoint directly, which is why the same action worked there.

Derive the subdomain directly from the region id so any current or future
region is routed correctly, keeping the `default` placeholder (and empty
values) mapped to the apex domain. stripLeadingRegionSubdomain() now also
strips the region about to be prepended, avoiding a doubled subdomain when
the console itself is served from that region. Adds unit tests covering the
regression and the edge cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes project navigation getting stuck (with CORS errors) when clicking a project in any Appwrite Cloud region not covered by the old hardcoded switch in getRegionSubdomain. The fix derives the regional subdomain directly from the region id (${region}.) so any current or future region is handled automatically, and stripLeadingRegionSubdomain gains an extraPrefix parameter to prevent doubling when the console is already served from the target region.

  • getRegionSubdomain is simplified from a six-case switch to a one-liner, with default/empty/undefined still returning the apex (no subdomain).
  • stripLeadingRegionSubdomain now accepts extraPrefix (the subdomain about to be prepended) and adds it to the strip list when it is not already in the hardcoded REGION_SUBDOMAIN_PREFIXES, preventing blr.blr.cloud… double-prefixing.
  • A new test file covers the primary regression, the no-double case, and several edge cases, though the cross-region scenario (blr → nyc from an unlisted-region hostname) is not tested.

Confidence Score: 4/5

Safe to merge for the primary reported scenario; a narrow gap remains for consoles served from unlisted regions navigating to a different region.

The main fix is correct and well-tested: any region id now maps directly to its subdomain, resolving the CORS hang for all new regions. The remaining gap — the extraPrefix mechanism only prevents doubling when the hostname already carries the same unlisted region as the target, so navigating from an unlisted-region console host to a different region produces a compound hostname — is a corner case that would only surface when APPWRITE_ENDPOINT is unset and the console is opened from a new-region URL.

Both changed files are worth a second look: apiEndpoint.ts for the stripping logic gap, and apiEndpoint.test.ts for the missing cross-region test case.

Important Files Changed

Filename Overview
src/lib/helpers/apiEndpoint.ts Core logic replaced: switch-case swapped for a direct template-literal derivation; stripLeadingRegionSubdomain gains an extraPrefix param to prevent doubling for unlisted regions. A gap remains when the hostname already contains an unlisted region and the target is a different region.
src/lib/helpers/apiEndpoint.test.ts New test file with good coverage of the main regression (unlisted region from apex host) and the no-double-subdomain edge case; missing a case for an unlisted source host navigating to a different target region.

Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
src/lib/helpers/apiEndpoint.ts:34-37
**Unlisted source-region prefix not stripped when navigating to a different region**

`extraPrefix` is the subdomain being *prepended* (the target region), so it only prevents doubling when the hostname already carries the same unlisted region as the destination. If the console is served from an unlisted region (e.g. `blr.cloud.appwrite.io`) and the user navigates to a *different* region (e.g. `nyc`), `extraPrefix = 'nyc.'` is already in `REGION_SUBDOMAIN_PREFIXES`, so the original list is used unchanged and `blr.` is never stripped — the result is `nyc.blr.cloud.appwrite.io/v1` instead of `nyc.cloud.appwrite.io/v1`. This scenario is real when `APPWRITE_ENDPOINT` is unset and `getApiEndpoint` in `sdk.ts` falls back to `globalThis.location`, picking up the console's own host, which can itself carry a new-region prefix.

### Issue 2 of 2
src/lib/helpers/apiEndpoint.test.ts:53-67
**Missing test for unlisted source region with a different target region**

The existing `buildRegionalV1Endpoint` tests cover `fra → blr` and `blr → blr`, but not `blr → nyc` (unlisted source region, different listed target region). Adding a case like `buildRegionalV1Endpoint('https:', 'blr.cloud.appwrite.io', 'nyc', true)` and asserting it returns `https://nyc.cloud.appwrite.io/v1` would pin down the behaviour described above and catch any future regression in the stripping logic.

Reviews (1): Last reviewed commit: "fix: route projects in any cloud region ..." | Re-trigger Greptile

Comment on lines +34 to +37
const prefixes =
extraPrefix && !REGION_SUBDOMAIN_PREFIXES.includes(extraPrefix)
? [extraPrefix, ...REGION_SUBDOMAIN_PREFIXES]
: REGION_SUBDOMAIN_PREFIXES;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Unlisted source-region prefix not stripped when navigating to a different region

extraPrefix is the subdomain being prepended (the target region), so it only prevents doubling when the hostname already carries the same unlisted region as the destination. If the console is served from an unlisted region (e.g. blr.cloud.appwrite.io) and the user navigates to a different region (e.g. nyc), extraPrefix = 'nyc.' is already in REGION_SUBDOMAIN_PREFIXES, so the original list is used unchanged and blr. is never stripped — the result is nyc.blr.cloud.appwrite.io/v1 instead of nyc.cloud.appwrite.io/v1. This scenario is real when APPWRITE_ENDPOINT is unset and getApiEndpoint in sdk.ts falls back to globalThis.location, picking up the console's own host, which can itself carry a new-region prefix.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/lib/helpers/apiEndpoint.ts
Line: 34-37

Comment:
**Unlisted source-region prefix not stripped when navigating to a different region**

`extraPrefix` is the subdomain being *prepended* (the target region), so it only prevents doubling when the hostname already carries the same unlisted region as the destination. If the console is served from an unlisted region (e.g. `blr.cloud.appwrite.io`) and the user navigates to a *different* region (e.g. `nyc`), `extraPrefix = 'nyc.'` is already in `REGION_SUBDOMAIN_PREFIXES`, so the original list is used unchanged and `blr.` is never stripped — the result is `nyc.blr.cloud.appwrite.io/v1` instead of `nyc.cloud.appwrite.io/v1`. This scenario is real when `APPWRITE_ENDPOINT` is unset and `getApiEndpoint` in `sdk.ts` falls back to `globalThis.location`, picking up the console's own host, which can itself carry a new-region prefix.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Codex

Comment on lines +53 to +67
it('prepends the regional subdomain for a region outside the hardcoded set', () => {
// apex host
expect(buildRegionalV1Endpoint('https:', 'cloud.appwrite.io', 'blr', true)).toBe(
'https://blr.cloud.appwrite.io/v1'
);
// host that already carries a known region label
expect(buildRegionalV1Endpoint('https:', 'fra.cloud.appwrite.io', 'blr', true)).toBe(
'https://blr.cloud.appwrite.io/v1'
);
});

it('does not double the subdomain when the host already carries the target region', () => {
expect(buildRegionalV1Endpoint('https:', 'blr.cloud.appwrite.io', 'blr', true)).toBe(
'https://blr.cloud.appwrite.io/v1'
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Missing test for unlisted source region with a different target region

The existing buildRegionalV1Endpoint tests cover fra → blr and blr → blr, but not blr → nyc (unlisted source region, different listed target region). Adding a case like buildRegionalV1Endpoint('https:', 'blr.cloud.appwrite.io', 'nyc', true) and asserting it returns https://nyc.cloud.appwrite.io/v1 would pin down the behaviour described above and catch any future regression in the stripping logic.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/lib/helpers/apiEndpoint.test.ts
Line: 53-67

Comment:
**Missing test for unlisted source region with a different target region**

The existing `buildRegionalV1Endpoint` tests cover `fra → blr` and `blr → blr`, but not `blr → nyc` (unlisted source region, different listed target region). Adding a case like `buildRegionalV1Endpoint('https:', 'blr.cloud.appwrite.io', 'nyc', true)` and asserting it returns `https://nyc.cloud.appwrite.io/v1` would pin down the behaviour described above and catch any future regression in the stripping logic.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code Fix in Codex

@claudear

Copy link
Copy Markdown
Author

Fix Confidence: 80/100

The mechanism is well-supported: a hardcoded region→subdomain switch means projects in newer/unlisted regions route to the apex domain, exactly matching the reported CORS-and-stuck symptom that works in impersonation (which targets the correct regional endpoint). The fix is minimal, backward-compatible, and CI's build job (which runs bun test:unit + type-check + lint + build) passed, so the new tests pass. Confidence is not higher because I could not reproduce the exact failing region in a live environment (sandbox can't install deps / no confirmed region id from the reporter), and the issue text left open that the true fault could be in cloud/appwrite backend CORS config rather than the console.

@@ -1,10 +1,4 @@
import {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@claudear very bad way of fixing it here. No requests were made out of these regions. So error is somewhere else

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.

2 participants