Repository: withastro/astro
File: packages/astro/src/env/env-loader.ts (TypeScript)

Code before:
function getPrivateEnv(
	fullEnv: Record<string, string>,
	astroConfig: AstroConfig,
	coerceValues: boolean
): Record<string, string> {
	const viteConfig = astroConfig.vite;
	let envPrefixes: string[] = ['PUBLIC_'];
	if (viteConfig.envPrefix) {
		envPrefixes = Array.isArray(viteConfig.envPrefix)
			? viteConfig.envPrefix
			: [viteConfig.envPrefix];
	}

	const privateEnv: Record<string, string> = {};
	for (const key in fullEnv) {
		// Ignore public env var
		if (isValidIdentifierRe.test(key) && envPrefixes.every((prefix) => !key.startsWith(prefix))) {
			if (typeof process.env[key] !== 'undefined') {
				let value = process.env[key];
				// Replacements are always strings, so try to convert to strings here first
				if (typeof value !== 'string') {
					value = `${value}`;
				}
				// Boolean values should be inlined to support `export const prerender`
				// We already know that these are NOT sensitive values, so inlining is safe
				if (coerceValues && (value === '0' || value === '1' || value === 'true' || value === 'false')) {
					privateEnv[key] = value;
				} else {
					privateEnv[key] = `process.env.${key}`;
				}
			} else {
				privateEnv[key] = JSON.stringify(fullEnv[key]);
			}
		}
	}
	return privateEnv;
}

export const createEnvLoader = (mode: string, config: AstroConfig, coerceValues: boolean) => {
	const loaded = loadEnv(mode, config.vite.envDir ?? fileURLToPath(config.root), '');
	const privateEnv = getPrivateEnv(loaded, config, coerceValues);
	return {
		get: () => loaded,
		getPrivateEnv: () => privateEnv,
	};
};

export type EnvLoader = ReturnType<typeof createEnvLoader>;


Review comment (suggestion):
FYI this code existed before `astro:env` so I'm afraid this change would be a breaking one. It would be great if you could test on an older version of Astro. To be sure, in `4.9`since `astro:env` was introduced in `4.10`

Code after:
function getPrivateEnv(
	fullEnv: Record<string, string>,
	astroConfig: AstroConfig,
	useRawValues: boolean,
): Record<string, string> {
	const viteConfig = astroConfig.vite;
	let envPrefixes: string[] = ['PUBLIC_'];
	if (viteConfig.envPrefix) {
		envPrefixes = Array.isArray(viteConfig.envPrefix)
			? viteConfig.envPrefix
			: [viteConfig.envPrefix];
	}

	const privateEnv: Record<string, string> = {};
	for (const key in fullEnv) {
		// Ignore public env var
		if (isValidIdentifierRe.test(key) && envPrefixes.every((prefix) => !key.startsWith(prefix))) {
			if (typeof process.env[key] !== 'undefined') {
				let value = process.env[key];
				// Replacements are always strings, so try to convert to strings here first
				if (typeof value !== 'string') {
					value = `${value}`;
				}
				// Boolean values should be inlined to support `export const prerender`
				// We already know that these are NOT sensitive values, so inlining is safe
				if (
					!useRawValues &&
					(value === '0' || value === '1' || value === 'true' || value === 'false')
				) {
					privateEnv[key] = value;
				} else {
					privateEnv[key] = `process.env.${key}`;
				}
			} else {
				privateEnv[key] = JSON.stringify(fullEnv[key]);
			}
		}
	}
	return privateEnv;
}

export const createEnvLoader = (mode: string, config: AstroConfig, useRawValues: boolean) => {
	const loaded = loadEnv(mode, config.vite.envDir ?? fileURLToPath(config.root), '');
	const privateEnv = getPrivateEnv(loaded, config, useRawValues);
	return {
		get: () => loaded,
		getPrivateEnv: () => privateEnv,
	};
};

export type EnvLoader = ReturnType<typeof createEnvLoader>;