e20ef940f8
Previously API_BASE_URL defaulted to http://localhost:8080/api, which only works inside the dev server proxy. For standalone/SSR runs without the proxy, the default now points to https://flights.test.aeroflot.ru. Dev continues to use the same-origin proxy because scripts/dev-server.mjs explicitly injects API_BASE_URL=http://localhost:8080/api into the Modern.js child process env, keeping browser fetches CORS/WAF safe.
104 lines
3.7 KiB
TypeScript
104 lines
3.7 KiB
TypeScript
import { z } from "zod";
|
|
import type { AnalyticsProviders } from "@/observability/analytics/types";
|
|
|
|
const boolish = z
|
|
.enum(["true", "false", "1", "0"])
|
|
.transform((v) => v === "true" || v === "1");
|
|
|
|
const EnvSchema = z.object({
|
|
NODE_ENV: z.enum(["development", "test", "testing", "staging", "production"]).default("development"),
|
|
BUILD_TARGET: z.enum(["standalone", "remote"]).default("standalone"),
|
|
PROD_ORIGIN: z.string().url().default("https://flights.test.aeroflot.ru"),
|
|
// Defaults to the test environment. In dev, scripts/dev-server.mjs injects
|
|
// API_BASE_URL=http://localhost:8080/api so browser calls route through the
|
|
// same-origin curl-based WAF-bypass proxy. In production, a deployment-time
|
|
// env var should set this to the live API host.
|
|
API_BASE_URL: z.string().url().default("https://flights.test.aeroflot.ru/api"),
|
|
SIGNALR_HUB_URL: z.string().url().default("http://platform.yc.webzavod.ru/tracker/hub"),
|
|
OTEL_EXPORTER_OTLP_ENDPOINT: z.string().url().optional(),
|
|
OTEL_EXPORTER_OTLP_HEADERS: z.string().optional(),
|
|
LOGS_ENDPOINT: z.string().url().optional(),
|
|
ANALYTICS_METRICA: boolish.default("false"),
|
|
ANALYTICS_CTM: boolish.default("false"),
|
|
ANALYTICS_VARIOCUBE: boolish.default("false"),
|
|
ANALYTICS_DYNATRACE: boolish.default("false"),
|
|
FEATURE_FLIGHTS_MAP: boolish.default("true"),
|
|
VERSION: z.string().min(1).default("dev"),
|
|
});
|
|
|
|
type RawEnv = z.infer<typeof EnvSchema>;
|
|
|
|
export interface Env {
|
|
NODE_ENV: RawEnv["NODE_ENV"];
|
|
BUILD_TARGET: RawEnv["BUILD_TARGET"];
|
|
PROD_ORIGIN: string;
|
|
API_BASE_URL: string;
|
|
SIGNALR_HUB_URL: string;
|
|
OTEL_EXPORTER_OTLP_ENDPOINT?: string;
|
|
OTEL_EXPORTER_OTLP_HEADERS?: string;
|
|
LOGS_ENDPOINT?: string;
|
|
ANALYTICS_ENABLED: AnalyticsProviders;
|
|
FEATURE_FLIGHTS_MAP: boolean;
|
|
VERSION: string;
|
|
}
|
|
|
|
let cached: Env | undefined;
|
|
|
|
export function getEnv(): Env {
|
|
if (cached) return cached;
|
|
|
|
// In the browser, process.env is not available (Rspack doesn't replace
|
|
// bracket-notation access). Fall back to an SSR-injected window.__ENV__
|
|
// or sensible development defaults.
|
|
const envSource =
|
|
typeof process !== "undefined" && process.env
|
|
? process.env
|
|
: typeof window !== "undefined" && (window as unknown as Record<string, unknown>)["__ENV__"]
|
|
? (window as unknown as Record<string, unknown>)["__ENV__"] as Record<string, string>
|
|
: {};
|
|
|
|
const parsed = EnvSchema.safeParse(envSource);
|
|
if (!parsed.success) {
|
|
const details = parsed.error.issues
|
|
.map((i) => `${i.path.join(".")}: ${i.message}`)
|
|
.join("; ");
|
|
throw new Error(`Invalid environment configuration: ${details}`);
|
|
}
|
|
|
|
const raw = parsed.data;
|
|
const result: Env = {
|
|
NODE_ENV: raw.NODE_ENV,
|
|
BUILD_TARGET: raw.BUILD_TARGET,
|
|
PROD_ORIGIN: raw.PROD_ORIGIN,
|
|
API_BASE_URL: raw.API_BASE_URL,
|
|
SIGNALR_HUB_URL: raw.SIGNALR_HUB_URL,
|
|
ANALYTICS_ENABLED: {
|
|
metrica: raw.ANALYTICS_METRICA,
|
|
ctm: raw.ANALYTICS_CTM,
|
|
variocube: raw.ANALYTICS_VARIOCUBE,
|
|
dynatrace: raw.ANALYTICS_DYNATRACE,
|
|
},
|
|
FEATURE_FLIGHTS_MAP: raw.FEATURE_FLIGHTS_MAP,
|
|
VERSION: raw.VERSION,
|
|
};
|
|
if (raw.OTEL_EXPORTER_OTLP_ENDPOINT !== undefined) {
|
|
result.OTEL_EXPORTER_OTLP_ENDPOINT = raw.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
}
|
|
if (raw.OTEL_EXPORTER_OTLP_HEADERS !== undefined) {
|
|
result.OTEL_EXPORTER_OTLP_HEADERS = raw.OTEL_EXPORTER_OTLP_HEADERS;
|
|
}
|
|
if (raw.LOGS_ENDPOINT !== undefined) {
|
|
result.LOGS_ENDPOINT = raw.LOGS_ENDPOINT;
|
|
}
|
|
cached = result;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Test-only: resets the module-level cache so tests can mutate process.env
|
|
* and re-read. Do NOT call this from production code.
|
|
*/
|
|
export function __resetEnvCacheForTests(): void {
|
|
cached = undefined;
|
|
}
|