/* eslint-env node */ /* * Env file to load and validate env variables * Be cautious; this file should not be imported into your source folder. * We split the env variables into two parts: * 1. Client variables: These variables are used in the client-side code (src folder). * 2. Build-time variables: These variables are used in the build process (app.config.ts file). * Import this file into the `app.config.ts` file to use environment variables during the build process. The client variables can then be passed to the client-side using the extra field in the `app.config.ts` file. * To access the client environment variables in your `src` folder, you can import them from `@env`. For example: `import Env from '@env'`. */ /** * 1st part: Import packages and Load your env variables * we use dotenv to load the correct variables from the .env file based on the APP_ENV variable (default is development) * APP_ENV is passed as an inline variable while executing the command, for example: APP_ENV=staging pnpm build:android */ const z = require('zod') const packageJSON = require('./package.json') const path = require('path') const APP_ENV = process.env.APP_ENV ?? 'development' const envPath = path.resolve(__dirname, `.env.${APP_ENV}`) require('dotenv').config({ path: envPath, }) /** * 2nd part: Define some static variables for the app * Such as: bundle id, package name, app name. * * You can add them to the .env file but we think it's better to keep them here as as we use prefix to generate this values based on the APP_ENV * for example: if the APP_ENV is staging, the bundle id will be com.busybarui.staging */ // TODO: Replace these values with your own const BUNDLE_ID = 'com.busybar' // ios bundle id const PACKAGE = 'com.busybar' // android package name const NAME = 'BusyBar' // app name const EXPO_ACCOUNT_OWNER = 'expo-owner' // expo account owner const EAS_PROJECT_ID = 'c3ef31c4-0e68-4ad3-bbdc-33c4ba50d0bf' // eas project id const SCHEME = 'busybar' // app scheme /** * We declare a function withEnvSuffix that will add a suffix to the variable name based on the APP_ENV * Add a suffix to variable env based on APP_ENV * @param {string} name * @returns {string} */ const withEnvSuffix = (name) => { return APP_ENV === 'production' ? name : `${name}.${APP_ENV}` } /** * 2nd part: Define your env variables schema * we use zod to define our env variables schema * * we split the env variables into two parts: * 1. client: These variables are used in the client-side code (`src` folder). * 2. buildTime: These variables are used in the build process (app.config.ts file). You can think of them as server-side variables. * * Main rules: * 1. If you need your variable on the client-side, you should add it to the client schema; otherwise, you should add it to the buildTime schema. * 2. Whenever you want to add a new variable, you should add it to the correct schema based on the previous rule, then you should add it to the corresponding object (_clientEnv or _buildTimeEnv). * * Note: `z.string()` means that the variable exists and can be an empty string, but not `undefined`. * If you want to make the variable required, you should use `z.string().min(1)` instead. * Read more about zod here: https://zod.dev/?id=strings * */ const client = z.object({ APP_ENV: z.enum(['development', 'staging', 'production']), NAME: z.string(), SCHEME: z.string(), BUNDLE_ID: z.string(), PACKAGE: z.string(), VERSION: z.string(), // ADD YOUR CLIENT ENV VARS HERE API_URL: z.string(), }) const buildTime = z.object({ EXPO_ACCOUNT_OWNER: z.string(), EAS_PROJECT_ID: z.string(), }) /** * @type {Record , unknown>} */ const _clientEnv = { APP_ENV, NAME: NAME, SCHEME: SCHEME, BUNDLE_ID: withEnvSuffix(BUNDLE_ID), PACKAGE: withEnvSuffix(PACKAGE), VERSION: packageJSON.version, // ADD YOUR ENV VARS HERE TOO API_URL: process.env.API_URL, } /** * @type {Record , unknown>} */ const _buildTimeEnv = { EXPO_ACCOUNT_OWNER, EAS_PROJECT_ID, } /** * 3rd part: Merge and Validate your env variables * We use zod to validate our env variables based on the schema we defined above * If the validation fails we throw an error and log the error to the console with a detailed message about missed variables * If the validation passes we export the merged and parsed env variables to be used in the app.config.ts file as well as a ClientEnv object to be used in the client-side code **/ const _env = { ..._clientEnv, ..._buildTimeEnv, } const merged = buildTime.merge(client) const parsed = merged.safeParse(_env) if (parsed.success === false) { console.error( 'āŒ Invalid environment variables:', parsed.error.flatten().fieldErrors, `\nāŒ Missing variables in .env.${APP_ENV} file, Make sure all required variables are defined in the .env.${APP_ENV} file.`, `\nšŸ’” Tip: If you recently updated the .env.${APP_ENV} file and the error still persists, try restarting the server with the -c flag to clear the cache.` ) throw new Error('Invalid environment variables, Check terminal for more details ') } const Env = parsed.data const ClientEnv = client.parse(_clientEnv) module.exports = { Env, ClientEnv, withEnvSuffix, }