Conversation
Target a non-decentraland.* deployment (e.g. interconnected.online) by
resolving every backend host through DecentralandUrlsSource.ResolveDomain,
which swaps the whole decentraland.{ENV} host token for a custom base domain
supplied by the --base-domain app arg (AppArgsFlags.BASE_DOMAIN). The default
path is byte-identical, swapping only the {ENV} TLD.
Consumers that follow the resolved domain: teleport validation
(ChatEnvironmentValidator), realm trust (DeepLinkAllowlist), the main-realm
comms fallback (RealmController), the realm-name server list (RealmNamesMap),
the pre-login feature-flag whitelist URL (GetFeatureFlagsUrl), the
smart-wearable content fallback (SmartWearableCache), and the local scene
adapter (LocalGateKeeperSceneAdapter). Gateway routing already follows it: the
transform runs on the {ENV} template and ResolveDomain rewrites the whole
token, gateway host included. The default "Empty place" no longer hardcodes a
peer.decentraland.org thumbnail and falls back to the built-in placeholder.
Characterization tests pin every DecentralandUrl across org/zone/custom
domains and gateway routing (gatekeeper family included); unit tests cover
custom-domain teleport validation and deep-link realm trust.
🚦 CI StatusNew build in progress, come back later! Warnings count reduced: 13156 => 13093 Warnings/errors in files changed by this PR (102)All Unity tests passed ✅
|
|
Slack notification sent to #explorer-ext-contributions for external review. |
decentraland-bot
left a comment
There was a problem hiding this comment.
PR Review: feat(urls): configurable base domain via --base-domain
STEP 2 — Root-cause check: PASS ✅
The PR introduces a --base-domain CLI argument so the client can target a non-decentraland.* deployment (e.g. interconnected.online). The approach is sound: DecentralandUrlsSource.ResolveDomain() centralizes domain substitution. The default path replaces only {ENV} (byte-identical to before, today-mixture safe); a custom base domain replaces the whole decentraland.{ENV} token, moving every backend host. This is a feature addition, not a symptom fix.
STEP 3 — Design & integration: PASS ✅
No new long-lived units — all changes extend existing classes. The design introduces:
- A
customBaseDomainfield onDecentralandUrlsSource(immutable after construction) - A static
customBaseDomainonDeepLinkAllowlist(follows existingwhitelistedWorldspattern, set once during initialization, reset in test teardown) - New constructor parameters on
SmartWearableCache,RealmNamesMap,ChatEnvironmentValidator
Owner search results:
DecentralandUrlsSourcealready owns all URL resolution —ResolveDomain()andResolvedBaseDomainbelong here.DeepLinkAllowlistalready owns host trust checks — extendingIsDecentralandHostwith the custom domain is the right place.ChatEnvironmentValidatoralready owns teleport validation — parameterizing its domain suffix rather than hardcoding it is correct.GatewayUrlsSourcederives gateway routing from the base class — usingResolvedBaseDomain(protected) is legitimate inheritance, not leaky abstraction.
Teardown/consumption trace:
- No new subscriptions, event hookups, connections, or disposable resources introduced. All changes are constructor-time wiring or one-time static initialization.
STEP 4 — Member audit: PASS ✅
| Member | Consumers | Verdict |
|---|---|---|
ResolveDomain() (private) |
Probe(), Url(), ResolveOptimizedAssetsUrl() — central substitution point |
Correctly encapsulated |
ResolvedBaseDomain (protected) |
GatewayUrlsSource ctor (3 refs: resolvedNonClientHosts, gatewayPrefix, domainSuffix) |
Legitimate protected accessor for inheritance |
SetCustomBaseDomain() (public static) |
MainSceneLoader.InitializeFlowAsync(), test teardown |
Follows existing SetWhitelistedWorlds pattern |
DOMAIN_TOKEN (protected const) |
ResolveDomain(), GatewayUrlsSource ctor, GetFeatureFlagsUrl() |
Correctly scoped |
No single-use intermediaries, no absent-≠-false predicates, no redundant guards.
STEP 5 — Line-level review
Security review: No security issues found.
BASE_DOMAINis a CLI arg, NOT in the deep linkPERMITTED_KEYSorWHITELISTED_REALM_PERMITTED_KEYS— an attacker cannot inject it via deep link ✅IsDecentralandHostboundary checks are correct:host.Length > customBaseDomain.Length+host[..] == '.'+EndsWith— rejects both bare domain and suffix-spoof attacks ✅ChatEnvironmentValidator.HostHasSuffixrejects userinfo-based host confusion (@check before:) ✅- No secrets, credentials, or PII exposed ✅
- Gateway routing works correctly:
IsGatewayTransformableruns on unresolved templates (which always contain.decentraland.), thenResolveDomainsubstitutes the custom domain afterward ✅
Findings: Two P2 issues (see line comments below).
STEP 6 — Complexity: COMPLEX
20 files changed (+444 −37). Touches URL infrastructure (DecentralandUrlsSource, GatewayUrlsSource), gateway routing, deep link trust model (DeepLinkAllowlist), teleport validation, realm name resolution, and smart wearable content fallback across multiple assemblies.
STEP 7 — QA assessment: YES
Runtime code changes affecting URL routing, teleport validation, and realm trust. Although the default path is byte-identical (backward compatible when --base-domain is not supplied), the URL resolution and gateway routing paths have changed.
STEP 8 — Non-blocking warnings
None. Main scene not modified.
STEP 9 — Verdict
REVIEW_RESULT: PASS ✅
COMPLEXITY: COMPLEX
COMPLEXITY_REASON: Touches URL infrastructure, gateway routing, deep link trust model, and teleport validation across 7+ assemblies
QA_REQUIRED: YES
Reviewed by Jarvis 🤖 · Requested by unknown via Slack
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Rename catalyrst -> catalyst in the base-domain doc and drop the ReSharper CheckNamespace suppression from the new characterization test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
decentraland-bot
left a comment
There was a problem hiding this comment.
STEP 1 — Context & Scope
PR: feat(urls): configurable base domain via --base-domain
Target: dev
Files: 20 changed (+442 −37)
Subsystems: NetworkDefinitions (DecentralandUrlsSource, GatewayUrlsSource), Infrastructure (DeepLinkAllowlist, ChatContainer, RealmController, MainSceneLoader, StaticContainer, BootstrapContainer), Chat (ChatEnvironmentValidator), PlacesAPIService, SmartWearables.
Loaded: CLAUDE.md, docs/README.md, review-instructions.md. Reviewed full source of DecentralandUrlsSource.cs, GatewayUrlsSource.cs, IDecentralandUrlsSource.cs, DeepLinkAllowlist.cs, RealmController.cs, ChatContainer.cs, SmartWearableCache.cs, ThumbnailLoader.cs.
STEP 2 — Root-cause check
PASS. This PR adds a feature (configurable base domain via --base-domain), not a bug fix. The approach centralizes domain resolution through ResolveDomain() — a new private method that substitutes either {ENV} (default, byte-identical to prior behavior) or the full decentraland.{ENV} token (custom domain). The design correctly addresses the need to target non-decentraland.* deployments without modifying the DecentralandEnvironment enum.
STEP 3 — Design & integration
PASS. No new long-lived units introduced. The changes parameterize existing classes:
DecentralandUrlsSource: gainscustomBaseDomainfield,DOMAIN_TOKENconstant,ResolveDomain()method, andResolvedBaseDomainproperty. All contained within the existing class hierarchy.GatewayUrlsSource: derives gateway prefix/suffix/non-client hosts fromResolvedBaseDomaininstead of direct ENV replacement. Gateway transform runs on raw templates beforeResolveDomain()— these compose correctly (confirmed by characterization tests).DeepLinkAllowlist.SetCustomBaseDomain(): follows the establishedSetWhitelistedWorlds()pattern (static mutable state, same class). Domain-trust check mirrors the existingALL_DOMAINSloop with identical dot-boundary validation. Suffix-spoofing correctly rejected (test at line 800 confirmsinterconnected.online.attacker.com→false).- Consumer updates (
ChatEnvironmentValidator,RealmNamesMap,SmartWearableCache,RealmController) receive the resolved domain via dependency injection or the URL source — no lifecycle duplication, no new reconciliation loops.
Owner search: No new lifecycle-owning units to audit.
Teardown/consumption trace: No new subscriptions, event hookups, or connections. RealmData.RealmType.OnUpdate += ResetRealmDependentUrls is pre-existing and unchanged.
STEP 4 — Member audit
| Member | Consumers | Assessment |
|---|---|---|
ResolvedBaseDomain (protected) |
ResolveDomain(), GatewayUrlsSource ctor (3 reads) |
Multi-use, justified. Two external call sites re-derive this value — see inline finding. |
ResolveDomain() (private) |
Probe(), Url(), ResolveOptimizedAssetsUrl() |
4 call sites, cleanly encapsulates branching logic. |
DOMAIN_TOKEN (const) |
ResolveDomain(), GetFeatureFlagsUrl(), GatewayUrlsSource ctor |
3 call sites across 2 files, justified. |
SetCustomBaseDomain() |
MainSceneLoader.InitializeFlowAsync, test teardown |
2 call sites, follows SetWhitelistedWorlds pattern. |
realmDomainSuffix (ChatEnvironmentValidator) |
ValidateTeleport() Zone/Org cases |
Replaces previously hardcoded domain constants. Legitimate parameterization. |
Note: GetFeatureFlagsUrl (line 255) duplicates the custom-domain-or-env-fallback branching from ResolveDomain() as a static method. This is necessary since it runs before the instance exists (InitializeDeepLinkWorldWhitelistAsync), but the parallel logic could drift — worth extracting a shared static helper if this method gains more callers.
STEP 5 — Line-level review
See inline comments for each finding with suggestion blocks.
Summary of findings:
| # | Sev | File | Issue |
|---|---|---|---|
| 1 | P2 | ChatContainer.cs:106-108 |
Fragile .Replace("https://", "") re-derives ResolvedBaseDomain |
| 2 | P2 | RealmController.cs:375 |
Same .Replace pattern (second occurrence) |
| 3 | P2 | DeepLinkAllowlist.cs:172-173 |
No format validation on custom domain — single-label domains trust entire TLDs |
| 4 | P2 | DecentralandUrlsSource.cs:68 |
Redundant null-forgiving ! operator |
Security review: No secrets committed. --base-domain is correctly excluded from PERMITTED_KEYS (not injectable via deep links). Domain-trust expansion in IsDecentralandHost uses proper dot-boundary validation matching the existing ALL_DOMAINS pattern. Gateway routing correctly composes with domain resolution. No auth bypass vectors identified.
Characterization tests: The 246-line DecentralandUrlsSourceCharacterizationShould.cs is excellent — it pins every domain-bearing URL for both Org and Zone environments, verifies env-independent URLs stay unchanged, tests gateway routing round-trips, and covers custom-domain retargeting. This is exactly the safety net needed for this change.
STEP 6 — Complexity assessment
COMPLEX. Touches URL resolution, domain trust (DeepLinkAllowlist), gateway routing, realm validation, and chat teleport validation across 20 files spanning NetworkDefinitions, Infrastructure, Chat, PlacesAPIService, and SmartWearables assemblies.
STEP 7 — QA assessment
QA_REQUIRED: YES. Changes runtime URL resolution affecting realm connections, teleportation validation, gateway routing, smart wearable content loading, and realm name resolution. However, the PR is designed to be byte-identical on the default path (no custom domain), so the risk to existing behavior is low.
STEP 8 — Non-blocking warnings
None. Main.unity is not modified.
STEP 9 — Verdict
REVIEW_RESULT: PASS ✅
COMPLEXITY: COMPLEX
COMPLEXITY_REASON: Touches URL resolution, domain trust, gateway routing, and realm validation across 20 files in NetworkDefinitions, Infrastructure, Chat, and SmartWearables assemblies
QA_REQUIRED: YES
Reviewed by Jarvis 🤖 · Requested by eordano via GitHub
| string realmDomainSuffix = bootstrapContainer.DecentralandUrlsSource | ||
| .Url(DCL.Multiplayer.Connections.DecentralandUrls.DecentralandUrl.Host) | ||
| .Replace("https://", string.Empty); |
There was a problem hiding this comment.
[P2] Re-derives ResolvedBaseDomain via fragile scheme stripping (CLAUDE.md: "Don't re-derive what already exists").
DecentralandUrlsSource.ResolvedBaseDomain already computes this exact value, but is protected and not on IDecentralandUrlsSource. Both this site and RealmController.ResolveHostname (line 375) independently strip the scheme with .Replace("https://", ""), which silently breaks if the scheme ever changes.
Ideal fix: expose BaseDomain on IDecentralandUrlsSource (backed by ResolvedBaseDomain). Immediate improvement: use Uri.Host for safer parsing:
| string realmDomainSuffix = bootstrapContainer.DecentralandUrlsSource | |
| .Url(DCL.Multiplayer.Connections.DecentralandUrls.DecentralandUrl.Host) | |
| .Replace("https://", string.Empty); | |
| string realmDomainSuffix = new Uri(bootstrapContainer.DecentralandUrlsSource | |
| .Url(DCL.Multiplayer.Connections.DecentralandUrls.DecentralandUrl.Host)).Host; |
There was a problem hiding this comment.
I agree with the comment from Jarvis:
[P2] Re-derives ResolvedBaseDomain via fragile scheme stripping (CLAUDE.md: "Don't re-derive what already exists").
DecentralandUrlsSource.ResolvedBaseDomain already computes this exact value, but is protected and not on IDecentralandUrlsSource. Both this site and RealmController.ResolveHostname (line 375) independently strip the scheme with .Replace("https://", ""), which silently breaks if the scheme ever changes.
Ideal fix: expose BaseDomain on IDecentralandUrlsSource (backed by ResolvedBaseDomain). Immediate improvement: use Uri.Host for safer parsing:
| // TODO: take in consideration the web3-network. If its sepolia then it should be .zone | ||
| ? "realm-provider." + IDecentralandUrlsSource.ORG_DOMAIN | ||
| // Consider it as the "main" realm which shares the comms with many catalysts. | ||
| ? "realm-provider." + decentralandUrlsSource.Url(DecentralandUrl.Host).Replace("https://", string.Empty) |
There was a problem hiding this comment.
[P2] Same .Replace("https://", "") pattern — second occurrence of the fragile domain extraction. Same BaseDomain interface property would eliminate both.
| ? "realm-provider." + decentralandUrlsSource.Url(DecentralandUrl.Host).Replace("https://", string.Empty) | |
| ? "realm-provider." + new Uri(decentralandUrlsSource.Url(DecentralandUrl.Host)).Host |
| public static void SetCustomBaseDomain(string? domain) => | ||
| customBaseDomain = string.IsNullOrWhiteSpace(domain) ? null : domain.Trim(); |
There was a problem hiding this comment.
[P2] Defense-in-depth: validate domain shape. A single-label domain (e.g. --base-domain com) would cause IsDecentralandHost to trust every .com host. While --base-domain is CLI-only (not in PERMITTED_KEYS, so deep links cannot inject it), basic format validation prevents accidental misconfiguration and hardens the public API surface of SetCustomBaseDomain().
| public static void SetCustomBaseDomain(string? domain) => | |
| customBaseDomain = string.IsNullOrWhiteSpace(domain) ? null : domain.Trim(); | |
| public static void SetCustomBaseDomain(string? domain) | |
| { | |
| if (string.IsNullOrWhiteSpace(domain)) | |
| { | |
| customBaseDomain = null; | |
| return; | |
| } | |
| string trimmed = domain.Trim(); | |
| // Require at least two labels and reject URL control characters (defense-in-depth). | |
| if (!trimmed.Contains('.') || trimmed.IndexOfAny(new[] { '/', '?', '#', '@', ':' }) >= 0) | |
| throw new ArgumentException($"Invalid base domain: '{trimmed}'"); | |
| customBaseDomain = trimmed; | |
| } |
| string? customBaseDomain = null) | ||
| { | ||
| decentralandDomain = environment.ToString()!.ToLower(); | ||
| this.customBaseDomain = string.IsNullOrWhiteSpace(customBaseDomain) ? null : customBaseDomain!.Trim(); |
There was a problem hiding this comment.
[P2] Redundant null-forgiving ! — IsNullOrWhiteSpace returning false guarantees non-null on the else branch; the ! is unnecessary noise.
| this.customBaseDomain = string.IsNullOrWhiteSpace(customBaseDomain) ? null : customBaseDomain!.Trim(); | |
| this.customBaseDomain = string.IsNullOrWhiteSpace(customBaseDomain) ? null : customBaseDomain.Trim(); |
Gateway-eligible URLs resolved before feature flags load are no longer cached in raw form for the process lifetime; they stay uncacheable until the use-gateway flag is known. The main-realm comms fallback pins realm-provider.decentraland.org for every decentraland.* environment and follows only a custom base domain. Characterization tests pin the pre-flags -> post-flags resolution sequence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SystemSpecUtils honors TryGetJsonPayload's result and absent individual fields instead of dereferencing null members; a failing specs evaluation reports the exception and never blocks startup, so --skip-minimum-specs-screen stays effective. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A payload defining only one platform's requirements no longer rejects the other platform: when every field of a dimension (cpu/gpu/os) is absent the check passes, while an explicitly-present empty list still rejects. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Clears the 50 InspectCode findings in files this PR touches (CS8618 uninitialized non-nullables via null! / nullable annotations per file idiom, CS8602/03/04 via real guards or invariant-backed forgiveness), bringing the warning count back under the ratchet baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…missing The tolerance fixes land without a regression test for the missing-payload path; this pins every SystemSpecUtils check against an empty flags configuration, live-hit on a --base-domain deployment whose flags backend served no alfa-minimum-requirements payload (boot died on splash). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
…domain check Pre-flags gateway-eligible URLs get a dedicated FlagsPending cache state: cached provisionally, then dropped and re-resolved once feature flags load. This closes the torn-read window that could permanently cache an un-gatewayed URL when flags landed mid-resolution, and bounds flags-never-load sessions to one resolution per URL instead of one per call. RealmController classifies environment domains by exact membership in ALL_DOMAINS instead of a spoofable name prefix, and SmartWearableCache returns the tracked item instead of null! on the cancelled path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
StaticContainer.GPUInstancingService is nullable for real: the disabled path (no render feature / instancing off) now skips registering the GPU-instancing feature set (plugin, RoadsPresence, debug system) instead of carrying a null! that consumers dereference; intentional disable and misconfiguration are logged distinctly. RealmController's main-realm hostname derivation becomes an internal static seam with tests pinning org, the zone->org re-pin, custom domains, and the env-domain spoof shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Unity-bundled NUnit predates Assert.Multiple (CS0117), which broke compilation of DCL.EditMode.Tests and with it the Lint and EditMode jobs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
|
Two client patches, rebased onto I could not push them myself — see "Why this is a comment" at the bottom. Commit 1 —
|
The skip note justified keeping the `= null!` initializer sweep by calling it the
sanctioned `[field: SerializeField]` inspector idiom with a linter carve-out.
Neither holds: CLAUDE.md § Anti-Patterns sanctions `null!` only for deserialized
JSON DTO fields, and the custom-rules linter has no null!/default! rule at all.
The decision to keep the sweep is still right, but for a different reason - the
`{ get; private set; } = null!` form is what composition-root containers already
use (654 occurrences at the PR base) and `Explorer/Assets/csc.rsp` already
`-nowarn:8618`, so the initializers change no compiler outcome and dropping them
would only move the two files against the prevailing pattern. The note now cites
that evidence instead.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018c638dR1vPysCMbYt2qQg5
Also includes (squashed): fix(gateway): apply --base-domain before deep links, restore empty-place thumbnails
Review fixes for PR #9728.
DeepLinkAllowlist.SetCustomBaseDomain was called ~40 lines after
InitializeDeepLinks(), which fires exactly once and synchronously walks
ProcessDeepLinkParameters -> IsRealmWhitelisted -> IsDecentralandHost - the very
check that consults customBaseDomain. On a cold launch carrying both
--base-domain=X and a decentraland:// link into a world hosted on X, that check
ran with customBaseDomain still null, so the link's whitelisted-realm-gated dev
params (local-scene, hub, skip-auth-screen, mcp) were denied for the exact launch
the flag exists to support. The arg is now read once, right after the deferring
parser is built, and handed to both the allowlist and the whitelist fetch; the
duplicate read inside InitializeDeepLinkWorldWhitelistAsync is gone.
PlacesAPIResponse's "Empty place" lost its hardcoded peer.decentraland.org
thumbnail, and ImageController only paints a placeholder when the caller supplies
defaultSprite. PlaceInfoPanelController, PlaceElementView (search results) and
TeleportPromptController passed none, so any parcel without a registered place
rendered a transparent image instead of a thumbnail. Each now passes the
placeholder its own prefab already ships (DefaultImagePlace.png) - the teleport
prompt reuses viewInstance.defaultImage, the other two capture the sprite the
prefab authored on the ImageView before the first request replaces it.
Null-forgiving suppressions are replaced by restructuring rather than annotation:
- FixedScenePointers.SceneResults is a non-nullable field; only `= default` made
it look nullable, so the struct is read back from the world after the wait.
- CreateBootstrapperAsync reached back into the half-built container for
IdentityCache; it now takes the identity cache the caller already holds.
- The Sentry scope configurator binds SentryReportHandler with a pattern, since
DiagnosticsContainer.Sentry is genuinely nullable.
- UrlData.Url is nullable by design, so Url()/Probe() bind it with `is { }` and
fall back to the NOT_CONFIGURED sentinel, now a named constant shared with
UrlData.ToString().
- SmartWearableCache passes the already-narrowed AvatarAttachmentDTO into
IsSmart/GetContentUrl instead of re-dereferencing IWearable.DTO.
- The smart-wearable authorization popup reports the missing scene metadata
instead of dereferencing it blind.
LocalGateKeeperSceneAdapter was the only SUPPORTED_URLS member with no gateway
coverage. It is added to the default-domain routing and round-trip cases; because
RawUrl resolves its host eagerly it carries no decentraland.{ENV} token for
IsGatewayTransformable to match under a custom base domain, so that case is
pinned by its own test instead.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018c638dR1vPysCMbYt2qQg5
|
PR #9728, run #32035435390 Builds: Windows change, Windows baseline, macOS change, macOS baseline How to read this table
|
mikhail-dcl
left a comment
There was a problem hiding this comment.
The current implementation with domain overriding created low-quality injections in several places, while the real purpose is to replace the whole environment.
Thus, I propose to revise the whole implementation by introducing a separate value in DecentralandEnvironment enum, which in conjunction with the app arg, will provide the first-class source for decentraland urls, instead of clumsily sitting on top of the org / zone / today. In turn it will ensure by design that the default env will not leak anywhere by accident.
| string realmDomainSuffix = bootstrapContainer.DecentralandUrlsSource | ||
| .Url(DCL.Multiplayer.Connections.DecentralandUrls.DecentralandUrl.Host) | ||
| .Replace("https://", string.Empty); |
There was a problem hiding this comment.
I agree with the comment from Jarvis:
[P2] Re-derives ResolvedBaseDomain via fragile scheme stripping (CLAUDE.md: "Don't re-derive what already exists").
DecentralandUrlsSource.ResolvedBaseDomain already computes this exact value, but is protected and not on IDecentralandUrlsSource. Both this site and RealmController.ResolveHostname (line 375) independently strip the scheme with .Replace("https://", ""), which silently breaks if the scheme ever changes.
Ideal fix: expose BaseDomain on IDecentralandUrlsSource (backed by ResolvedBaseDomain). Immediate improvement: use Uri.Host for safer parsing:
| "🔴 Error. You cannot change realms in the Today environment. Please restart DCL with the desired environment"); | ||
| case DecentralandEnvironment.Zone: | ||
| return HostHasSuffix(realmToTeleportTo, IDecentralandUrlsSource.ZONE_DOMAIN) | ||
| return HostHasSuffix(realmToTeleportTo, realmDomainSuffix) |
There was a problem hiding this comment.
This class reveals the real design defect of this PR (look, two paths are now identical because of the changes).
The whole description is provided in the parent review comment
|
This PR will be closed in favor "chore/e2e-infra" according to the renewed e2e strategy |
Target a non-decentraland.* deployment (e.g. interconnected.online) by resolving every backend host through DecentralandUrlsSource.ResolveDomain, which swaps the whole decentraland.{ENV} host token for a custom base domain supplied by the --base-domain app arg (AppArgsFlags.BASE_DOMAIN). The default path is byte-identical, swapping only the {ENV} TLD.
Consumers that follow the resolved domain: teleport validation (ChatEnvironmentValidator), realm trust (DeepLinkAllowlist), the main-realm comms fallback (RealmController), the realm-name server list (RealmNamesMap), the pre-login feature-flag whitelist URL (GetFeatureFlagsUrl), the smart-wearable content fallback (SmartWearableCache), and the local scene adapter (LocalGateKeeperSceneAdapter). Gateway routing already follows it: the transform runs on the {ENV} template and ResolveDomain rewrites the whole token, gateway host included. The default "Empty place" no longer hardcodes a peer.decentraland.org thumbnail and falls back to the built-in placeholder.
Characterization tests pin every DecentralandUrl across org/zone/custom domains and gateway routing (gatekeeper family included); unit tests cover custom-domain teleport validation and deep-link realm trust.
QA: Full automated testing should not raise any errors or changes -- this is internal only. Test --base-domain interconnected.online to see if it works on a different catalyst setup