UNPKG

convex

Version:

Client for the Convex Cloud

216 lines (204 loc) 6.42 kB
import { Command } from "@commander-js/extra-typings"; import chalk from "chalk"; import { Context, logFailure, logFinishedStep, logMessage, logOutput, oneoffContext, } from "../bundler/context.js"; import { DeploymentSelectionOptions, deploymentSelectionFromOptions, fetchDeploymentCredentialsWithinCurrentProject, } from "./lib/api.js"; import { actionDescription } from "./lib/command.js"; import { runQuery } from "./lib/run.js"; import { deploymentFetch, ensureHasConvexDependency, logAndHandleFetchError, } from "./lib/utils/utils.js"; const envSet = new Command("set") // Pretend value is required .usage("[options] <name> <value>") .arguments("<name> [value]") .summary("Set a variable") .description( "Set a variable: `npx convex env set NAME value`\n" + "If the variable already exists, its value is updated.\n\n" + "A single `NAME=value` argument is also supported.", ) .configureHelp({ showGlobalOptions: true }) .allowExcessArguments(false) .action(async (originalName, originalValue, _options, cmd) => { const options = cmd.optsWithGlobals(); const ctx = oneoffContext; await ensureHasConvexDependency(ctx, "env set"); const [name, value] = await allowEqualsSyntax( ctx, originalName, originalValue, ); const where = await callUpdateEnvironmentVariables(ctx, options, [ { name, value }, ]); const formatted = /\s/.test(value) ? `"${value}"` : value; logFinishedStep( ctx, `Successfully set ${chalk.bold(name)} to ${chalk.bold(formatted)}${where}`, ); }); async function allowEqualsSyntax( ctx: Context, name: string, value: string | undefined, ) { if (value === undefined) { if (/^[a-zA-Z][a-zA-Z0-9_]+=/.test(name)) { return name.split("=", 2); } else { return await ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: "error: missing required argument 'value'", }); } } return [name, value]; } const envGet = new Command("get") .arguments("<name>") .summary("Print a variable's value") .description("Print a variable's value: `npx convex env get NAME`") .configureHelp({ showGlobalOptions: true }) .allowExcessArguments(false) .action(async (envVarName, _options, cmd) => { const ctx = oneoffContext; await ensureHasConvexDependency(ctx, "env get"); const options = cmd.optsWithGlobals(); const deploymentSelection = deploymentSelectionFromOptions(options); const { adminKey, url } = await fetchDeploymentCredentialsWithinCurrentProject( ctx, deploymentSelection, ); const envVar = (await runQuery( ctx, url, adminKey, "_system/cli/queryEnvironmentVariables:get", { name: envVarName }, )) as EnvVar | null; if (envVar === null) { logFailure(ctx, `Environment variable "${envVarName}" not found.`); return; } const { value } = envVar; logOutput(ctx, `${value}`); }); const envRemove = new Command("remove") .alias("rm") .alias("unset") .arguments("<name>") .summary("Unset a variable") .description( "Unset a variable: `npx convex env remove NAME`\n" + "If the variable doesn't exist, the command doesn't do anything and succeeds.", ) .configureHelp({ showGlobalOptions: true }) .allowExcessArguments(false) .action(async (name, _options, cmd) => { const ctx = oneoffContext; const options = cmd.optsWithGlobals(); await ensureHasConvexDependency(ctx, "env remove"); const where = await callUpdateEnvironmentVariables(ctx, options, [ { name }, ]); logFinishedStep(ctx, `Successfully unset ${chalk.bold(name)}${where}`); }); const envList = new Command("list") .summary("List all variables") .description("List all variables: `npx convex env list`") .configureHelp({ showGlobalOptions: true }) .allowExcessArguments(false) .action(async (_options, cmd) => { const ctx = oneoffContext; await ensureHasConvexDependency(ctx, "env list"); const options = cmd.optsWithGlobals(); const deploymentSelection = deploymentSelectionFromOptions(options); const { adminKey, url } = await fetchDeploymentCredentialsWithinCurrentProject( ctx, deploymentSelection, ); const envs = (await runQuery( ctx, url, adminKey, "_system/cli/queryEnvironmentVariables", {}, )) as EnvVar[]; if (envs.length === 0) { logMessage(ctx, "No environment variables set."); return; } for (const { name, value } of envs) { logOutput(ctx, `${name}=${value}`); } }); type EnvVarChange = { name: string; value?: string; }; type EnvVar = { name: string; value: string; }; async function callUpdateEnvironmentVariables( ctx: Context, options: DeploymentSelectionOptions, changes: EnvVarChange[], ) { const deploymentSelection = deploymentSelectionFromOptions(options); const { adminKey, url, deploymentName, deploymentType } = await fetchDeploymentCredentialsWithinCurrentProject( ctx, deploymentSelection, ); const fetch = deploymentFetch(url, adminKey); try { await fetch("/api/update_environment_variables", { body: JSON.stringify({ changes }), method: "POST", }); return deploymentType !== undefined || deploymentName !== undefined ? ` (on${ deploymentType !== undefined ? " " + chalk.bold(deploymentType) : "" } deployment${ deploymentName !== undefined ? " " + chalk.bold(deploymentName) : "" })` : ""; } catch (e) { return await logAndHandleFetchError(ctx, e); } } export const env = new Command("env") .summary("Set and view environment variables") .description( "Set and view environment variables on your deployment\n\n" + " Set a variable: `npx convex env set NAME value`\n" + " Unset a variable: `npx convex env remove NAME`\n" + " List all variables: `npx convex env list`\n" + " Print a variable's value: `npx convex env get NAME`\n\n" + "By default, this sets and views variables on your dev deployment.", ) .addCommand(envSet) .addCommand(envGet) .addCommand(envRemove) .addCommand(envList) .addHelpCommand(false) .addDeploymentSelectionOptions( actionDescription("Set and view environment variables on"), );