UNPKG

convex

Version:

Client for the Convex Cloud

210 lines (193 loc) 5.36 kB
/** * Help the developer store the CONVEX_URL environment variable. */ import chalk from "chalk"; import * as dotenv from "dotenv"; import inquirer from "inquirer"; import { Context } from "./context"; import { loadPackageJson } from "./utils"; export async function suggestedEnvVarName(ctx: Context): Promise<{ appearToBeUsing?: string; envVar: string; }> { // no package.json, that's fine, just guess if (!ctx.fs.exists("package.json")) { return { envVar: "CONVEX_URL", }; } const packages = await loadPackageJson(ctx); // Is it create-react-app? const isCreateReactApp = !!packages.filter( ({ name }) => name === "react-scripts" ).length; if (isCreateReactApp) { return { appearToBeUsing: "create-react-app", envVar: "REACT_APP_CONVEX_URL", }; } const isNextJs = !!packages.filter(({ name }) => name === "next").length; if (isNextJs) { return { appearToBeUsing: "Next.js", envVar: "NEXT_PUBLIC_CONVEX_URL", }; } const isVite = !!packages.filter(({ name }) => name === "vite"); if (isVite) { return { appearToBeUsing: "Vite", envVar: "VITE_CONVEX_URL", }; } return { envVar: "CONVEX_URL", }; } function suggestedProdEnvFile(ctx: Context): { existing: boolean; envFile: string; } { // The most prod-looking env file that exists, or .env if (ctx.fs.exists(".env.production")) { return { existing: true, envFile: ".env.production", }; } if (ctx.fs.exists(".env")) { return { existing: true, envFile: ".env", }; } return { existing: false, envFile: ".env", }; } function suggestedDevEnvFile(ctx: Context): { existing: boolean; envFile: string; } { // The most dev-looking env file that exists, or .env.local return { existing: ctx.fs.exists(".env.local"), envFile: ".env.local", }; } const EXPECTED_NAMES = new Set([ "CONVEX_URL", "NEXT_PUBLIC_CONVEX_URL", "VITE_CONVEX_URL", "REACT_APP_CONVEX_URL", ]); export async function offerToWriteToEnv( ctx: Context, type: "dev" | "prod", value: string, saveUrl: "yes" | "no" | "ask" = "ask" as const ) { if (saveUrl === "no") return; const { envFile, existing } = type === "dev" ? suggestedDevEnvFile(ctx) : suggestedProdEnvFile(ctx); if (existing) { const config = dotenv.parse(ctx.fs.readUtf8File(envFile)); console.error(`Found ${envFile} file.`); const matching = Object.keys(config).filter(key => EXPECTED_NAMES.has(key)); if (matching.length > 1) { console.error( chalk.yellow( `Found multiple CONVEX_URL environment variables in ${envFile} so cannot update automatically.` ) ); return; } if (matching.length === 1) { const [envVar, oldValue] = [matching[0], config[matching[0]]]; if (oldValue === value) { console.error( chalk.green(`${envVar} in ${envFile} is already ${value}`) ); return; } if (Object.values(config).filter(v => v === oldValue).length !== 1) { chalk.yellow(`Can't safely modify ${envFile}, please edit manually.`); return; } if ( saveUrl === "yes" || ( await inquirer.prompt([ { type: "confirm", name: "updateEnvFile", message: `Update ${envVar} in ${envFile} to ${value} to save ${type} URL?`, default: true, }, ]) ).updateEnvFile ) { const modified = ctx.fs.readUtf8File(envFile).replace(oldValue, value); ctx.fs.writeUtf8File(envFile, modified); console.error( chalk.green(`Updated ${envFile} with ${envVar}="${value}"`) ); return; } console.error( chalk.yellow(`Please update ${envFile} with ${envVar}="${value}"`) ); return; } const { appearToBeUsing, envVar } = await suggestedEnvVarName(ctx); if (appearToBeUsing) { console.error(`Detected ${appearToBeUsing} project.`); } if ( saveUrl === "yes" || ( await inquirer.prompt([ { type: "confirm", name: "updateEnvFile", message: `Add ${envVar} to ${envFile} to save ${type} URL?`, default: true, }, ]) ).updateEnvFile ) { const orig = ctx.fs.readUtf8File(envFile); const modified = `${orig}\n${envVar}="${value}"\n`; ctx.fs.writeUtf8File(envFile, modified); console.error( chalk.green(`Updated ${envFile} with ${envVar}="${value}"`) ); } return; } // Finally, offer to create a new .env file const { appearToBeUsing, envVar } = await suggestedEnvVarName(ctx); if (appearToBeUsing) { console.error(chalk.green(`Detected ${appearToBeUsing} project.`)); } if ( saveUrl === "yes" || ( await inquirer.prompt([ { type: "confirm", name: "updateEnvFile", message: `Create a ${envFile} file and add ${envVar} to save ${type} URL?`, default: true, }, ]) ).updateEnvFile ) { const contents = `${envVar}="${value}"\n`; ctx.fs.writeUtf8File(envFile, contents); console.error(chalk.green(`Wrote ${envFile} file to save ${envVar}.`)); return; } }