fix: prefer primary Tenant.domain in get_user/get_version matching

When multiple tenants claim the same host via domains aliases, resolve the tenant whose primary domain matches first so branding edits apply to the expected version.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-09 16:36:10 +03:30
co-authored by Cursor
parent be50c99f65
commit 501bcd0894
2 changed files with 69 additions and 24 deletions
+42 -10
View File
@@ -17,7 +17,7 @@ export class GetUserService {
where: { isActive: true }, where: { isActive: true },
}); });
const tenant = tenants.find((item) => this.matchesHost(item, host)); const tenant = this.findTenantForHost(tenants, host);
if (!tenant) { if (!tenant) {
throw new NotFoundException('tenant not found for domain'); throw new NotFoundException('tenant not found for domain');
} }
@@ -181,6 +181,46 @@ export class GetUserService {
return out; return out;
} }
/**
* اول دامنهٔ اصلی (Tenant.domain)، بعد aliases داخل domains[].
* اگر چند نسخه یک دامنه را داشته باشند، نسخهٔ primary برنده است.
*/
private findTenantForHost<
T extends {
domain: string;
domains: unknown;
},
>(tenants: T[], host: string): T | undefined {
const normalizedHost = this.normalizeHost(host);
const hostNoWww = normalizedHost.replace(/^www\./, '');
const primary = tenants.find((item) => {
const d = this.normalizeHost(item.domain);
return d === normalizedHost || d.replace(/^www\./, '') === hostNoWww;
});
if (primary) return primary;
return tenants.find((item) => this.matchesAliasHost(item, normalizedHost));
}
private matchesAliasHost(
tenant: {
domain: string;
domains: unknown;
},
host: string,
) {
const hostNoWww = host.replace(/^www\./, '');
for (const value of this.readDomains(tenant.domains)) {
const normalized = this.normalizeHost(value);
if (!normalized) continue;
if (normalized === host || normalized.replace(/^www\./, '') === hostNoWww) {
return true;
}
}
return false;
}
private matchesHost( private matchesHost(
tenant: { tenant: {
domain: string; domain: string;
@@ -188,15 +228,7 @@ export class GetUserService {
}, },
host: string, host: string,
) { ) {
const candidates = new Set<string>(); return Boolean(this.findTenantForHost([tenant], host));
for (const value of [tenant.domain, ...this.readDomains(tenant.domains)]) {
const normalized = this.normalizeHost(value);
if (!normalized) continue;
candidates.add(normalized);
candidates.add(normalized.replace(/^www\./, ''));
candidates.add(`www.${normalized.replace(/^www\./, '')}`);
}
return candidates.has(host) || candidates.has(host.replace(/^www\./, ''));
} }
private readDomains(raw: unknown): string[] { private readDomains(raw: unknown): string[] {
+24 -11
View File
@@ -20,7 +20,7 @@ export class GetVersionService {
}, },
}); });
const tenant = tenants.find((item) => this.matchesHost(item, host)); const tenant = this.findTenantForHost(tenants, host);
if (!tenant) { if (!tenant) {
throw new NotFoundException('tenant not found for domain'); throw new NotFoundException('tenant not found for domain');
} }
@@ -28,22 +28,35 @@ export class GetVersionService {
return { version: tenant.appVersion || '1' }; return { version: tenant.appVersion || '1' };
} }
private matchesHost( /** هم‌راستا با GetUserService: اول Tenant.domain، بعد aliases */
tenant: { private findTenantForHost<
T extends {
domain: string; domain: string;
domains: unknown; domains: unknown;
}, },
host: string, >(tenants: T[], host: string): T | undefined {
) { const normalizedHost = this.normalizeHost(host);
const candidates = new Set<string>(); const hostNoWww = normalizedHost.replace(/^www\./, '');
for (const value of [tenant.domain, ...this.readDomains(tenant.domains)]) {
const primary = tenants.find((item) => {
const d = this.normalizeHost(item.domain);
return d === normalizedHost || d.replace(/^www\./, '') === hostNoWww;
});
if (primary) return primary;
return tenants.find((item) => {
for (const value of this.readDomains(item.domains)) {
const normalized = this.normalizeHost(value); const normalized = this.normalizeHost(value);
if (!normalized) continue; if (!normalized) continue;
candidates.add(normalized); if (
candidates.add(normalized.replace(/^www\./, '')); normalized === normalizedHost ||
candidates.add(`www.${normalized.replace(/^www\./, '')}`); normalized.replace(/^www\./, '') === hostNoWww
) {
return true;
} }
return candidates.has(host) || candidates.has(host.replace(/^www\./, '')); }
return false;
});
} }
private readDomains(raw: unknown): string[] { private readDomains(raw: unknown): string[] {