Files
flights_web/src/env/index.ts
T
gnezim e20ef940f8 Default API_BASE_URL and PROD_ORIGIN to the test environment
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.
2026-04-17 15:31:03 +03:00

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;
}