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

Code before:
	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):
I think it's important to note in docs/changeset that this only affects `import.meta.env` when the value is taken from `process.env` (ie. doesn't happen if you set a var in `.env`, but happens if you set it inline while running the command)

Code after:
	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>;