Fix runtime env detection for SIT domains (#634)

This commit is contained in:
shenlan 2025-11-02 11:00:56 +08:00 committed by GitHub
parent 4a03a0e783
commit bdc3dc405f

View File

@ -33,6 +33,8 @@ const YAML_SOURCES: Record<RuntimeSourceKey, string | undefined> = {
const parsedYamlCache: Partial<Record<RuntimeSourceKey, Record<string, unknown>>> = {}
const runtimeConfigCache = new Map<string, RuntimeConfig>()
const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '[::1]'])
function isPlainRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value)
}
@ -159,6 +161,15 @@ function detectHostname(hostnameOverride?: string): { hostname?: string; detecte
for (const candidate of envCandidates) {
const hostname = sanitizeHostname(candidate.value)
if (!hostname) {
continue
}
const likelyMachineHostname = !hostname.includes('.') && !LOCAL_HOSTNAMES.has(hostname)
if (likelyMachineHostname) {
continue
}
if (hostname) {
return { hostname, detectedBy: candidate.source }
}
@ -167,15 +178,129 @@ function detectHostname(hostnameOverride?: string): { hostname?: string; detecte
return { hostname: undefined, detectedBy: 'default' }
}
function normalizeEnvironmentKey(value?: string): RuntimeEnvironment | undefined {
if (!value) {
return undefined
}
const normalized = value
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, '_')
.replace(/^_+|_+$/g, '')
const mapping: Record<string, RuntimeEnvironment> = {
prod: 'prod',
production: 'prod',
release: 'prod',
main: 'prod',
live: 'prod',
sit: 'sit',
staging: 'sit',
test: 'sit',
qa: 'sit',
uat: 'sit',
dev: 'sit',
development: 'sit',
preview: 'sit',
preprod: 'sit',
}
return mapping[normalized]
}
function detectEnvironmentFromEnvVars(): { environment: RuntimeEnvironment; matchedRule: string } | undefined {
const envCandidates: Array<{ source: string; value?: string; allowProd?: boolean }> = [
{ source: 'RUNTIME_ENV', value: process.env.RUNTIME_ENV },
{ source: 'NEXT_RUNTIME_ENV', value: process.env.NEXT_RUNTIME_ENV },
{ source: 'APP_ENV', value: process.env.APP_ENV },
{ source: 'ENVIRONMENT', value: process.env.ENVIRONMENT },
{ source: 'STAGE', value: process.env.STAGE },
{ source: 'NODE_ENV', value: process.env.NODE_ENV, allowProd: false },
]
for (const candidate of envCandidates) {
const normalized = normalizeEnvironmentKey(candidate.value)
if (!normalized) {
continue
}
if (!candidate.allowProd && normalized === 'prod') {
continue
}
return { environment: normalized, matchedRule: `env:${candidate.source}` }
}
return undefined
}
function detectEnvironmentFromHostnamePattern(hostname: string):
| { environment: RuntimeEnvironment; matchedRule: string }
| undefined {
const normalized = hostname.toLowerCase()
if (normalized.startsWith('dev.') || normalized.startsWith('dev-') || normalized.includes('.dev.')) {
return { environment: 'sit', matchedRule: 'dev-subdomain' }
}
return undefined
}
function detectEnvironmentFromUrlHints(): { environment: RuntimeEnvironment; matchedRule: string } | undefined {
const urlCandidates = [
{ source: 'RUNTIME_HOSTNAME', value: process.env.RUNTIME_HOSTNAME },
{ source: 'NEXT_RUNTIME_HOSTNAME', value: process.env.NEXT_RUNTIME_HOSTNAME },
{ source: 'RUNTIME_DASHBOARD_URL', value: process.env.RUNTIME_DASHBOARD_URL },
{ source: 'NEXT_PUBLIC_DASHBOARD_URL', value: process.env.NEXT_PUBLIC_DASHBOARD_URL },
{ source: 'DASHBOARD_URL', value: process.env.DASHBOARD_URL },
{ source: 'ACCOUNT_SERVICE_URL', value: process.env.ACCOUNT_SERVICE_URL },
{ source: 'NEXT_PUBLIC_ACCOUNT_SERVICE_URL', value: process.env.NEXT_PUBLIC_ACCOUNT_SERVICE_URL },
{ source: 'SERVER_SERVICE_URL', value: process.env.SERVER_SERVICE_URL },
{ source: 'NEXT_PUBLIC_SERVER_SERVICE_URL', value: process.env.NEXT_PUBLIC_SERVER_SERVICE_URL },
{ source: 'NEXT_PUBLIC_API_BASE_URL', value: process.env.NEXT_PUBLIC_API_BASE_URL },
{ source: 'API_BASE_URL', value: process.env.API_BASE_URL },
{ source: 'AUTH_URL', value: process.env.AUTH_URL },
{ source: 'NEXT_PUBLIC_AUTH_URL', value: process.env.NEXT_PUBLIC_AUTH_URL },
]
for (const candidate of urlCandidates) {
const hostname = sanitizeHostname(candidate.value)
if (!hostname) {
continue
}
const detected = detectEnvironmentFromHostnamePattern(hostname)
if (detected) {
return { ...detected, matchedRule: `env-url:${candidate.source}` }
}
}
return undefined
}
function detectEnvironment(hostname?: string): { environment: RuntimeEnvironment; region: RuntimeRegion; matchedRule: string } {
const normalized = hostname?.toLowerCase() ?? ''
let environment: RuntimeEnvironment = 'prod'
let matchedRule = 'default'
if (normalized.startsWith('dev.') || normalized.startsWith('dev-') || normalized.includes('.dev.')) {
environment = 'sit'
matchedRule = 'dev-subdomain'
const envOverride = detectEnvironmentFromEnvVars()
if (envOverride) {
environment = envOverride.environment
matchedRule = envOverride.matchedRule
} else {
const hostnameMatch = normalized ? detectEnvironmentFromHostnamePattern(normalized) : undefined
if (hostnameMatch) {
environment = hostnameMatch.environment
matchedRule = hostnameMatch.matchedRule
} else {
const hintMatch = detectEnvironmentFromUrlHints()
if (hintMatch) {
environment = hintMatch.environment
matchedRule = hintMatch.matchedRule
}
}
}
let region: RuntimeRegion = 'default'