diff --git a/npm-packages/convex/src/bundler/external.ts b/npm-packages/convex/src/bundler/external.ts index 0e795c92..33100946 100644 --- a/npm-packages/convex/src/bundler/external.ts +++ b/npm-packages/convex/src/bundler/external.ts @@ -4,7 +4,7 @@ import { Context } from "./context.js"; import path from "path"; import { findUp } from "find-up"; -import { findParentConfigs } from "../cli/lib/utils.js"; +import { findParentConfigs } from "../cli/lib/utils/utils.js"; /** * Mimics Node.js node_modules resolution. Ideally we would be able to diff --git a/npm-packages/convex/src/cli/configure.ts b/npm-packages/convex/src/cli/configure.ts index 59ab8f51..5d07351b 100644 --- a/npm-packages/convex/src/cli/configure.ts +++ b/npm-packages/convex/src/cli/configure.ts @@ -1,5 +1,4 @@ import chalk from "chalk"; -import inquirer from "inquirer"; import { Context, logFailure, @@ -37,12 +36,13 @@ import { ThrowingFetchError, validateOrSelectProject, validateOrSelectTeam, -} from "./lib/utils.js"; +} from "./lib/utils/utils.js"; import { writeConvexUrlToEnvFile } from "./lib/envvars.js"; import path from "path"; import { projectDashboardUrl } from "./dashboard.js"; import { doCodegen, doInitCodegen } from "./lib/codegen.js"; import { handleLocalDeployment } from "./lib/localDeployment/localDeployment.js"; +import { promptOptions, promptString } from "./lib/utils/prompts.js"; type DeploymentCredentials = { url: string; @@ -288,17 +288,11 @@ async function selectNewProject( const { teamSlug: selectedTeam, chosen: didChooseBetweenTeams } = await validateOrSelectTeam(ctx, config.team, "Team:"); let projectName: string = config.project || cwd; - if (process.stdin.isTTY && !config.project) { - projectName = ( - await inquirer.prompt([ - { - type: "input", - name: "project", - message: "Project name:", - default: cwd, - }, - ]) - ).project; + if (!config.project) { + projectName = await promptString(ctx, { + message: "Project name:", + default: cwd, + }); } showSpinner(ctx, "Creating new Convex project..."); @@ -386,31 +380,16 @@ async function askToConfigure( if (!(await hasProjects(ctx))) { return "new"; } - return await promptToInitWithProjects(reconfigure); -} - -async function promptToInitWithProjects( - reconfigure: boolean, -): Promise<"new" | "existing"> { - const { choice } = await inquirer.prompt([ - { - // In the Convex mono-repo, `list` seems to cause the command to not - // respond to CTRL+C while `search-list` does not. - type: process.env.CONVEX_RUNNING_LIVE_IN_MONOREPO - ? "search-list" - : "list", - name: "choice", - message: reconfigure - ? "Configure a different project?" - : "What would you like to configure?", - default: "new", - choices: [ - { name: "create a new project", value: "new" }, - { name: "choose an existing project", value: "existing" }, - ], - }, - ]); - return choice; + return await promptOptions(ctx, { + message: reconfigure + ? "Configure a different project?" + : "What would you like to configure?", + default: "new", + choices: [ + { name: "create a new project", value: "new" }, + { name: "choose an existing project", value: "existing" }, + ], + }); } type DeploymentOptions = diff --git a/npm-packages/convex/src/cli/convexExport.ts b/npm-packages/convex/src/cli/convexExport.ts index bdbff70b..35aacb6e 100644 --- a/npm-packages/convex/src/cli/convexExport.ts +++ b/npm-packages/convex/src/cli/convexExport.ts @@ -5,7 +5,7 @@ import { waitUntilCalled, deploymentFetch, logAndHandleFetchError, -} from "./lib/utils.js"; +} from "./lib/utils/utils.js"; import { logFailure, oneoffContext, diff --git a/npm-packages/convex/src/cli/convexImport.ts b/npm-packages/convex/src/cli/convexImport.ts index 8072c4b3..d0cac9ab 100644 --- a/npm-packages/convex/src/cli/convexImport.ts +++ b/npm-packages/convex/src/cli/convexImport.ts @@ -1,12 +1,11 @@ import chalk from "chalk"; -import inquirer from "inquirer"; import { ensureHasConvexDependency, formatSize, waitUntilCalled, deploymentFetch, logAndHandleFetchError, -} from "./lib/utils.js"; +} from "./lib/utils/utils.js"; import { logFailure, oneoffContext, @@ -29,6 +28,7 @@ import { actionDescription } from "./lib/command.js"; import { ConvexHttpClient } from "../browser/http_client.js"; import { makeFunctionReference } from "../server/index.js"; import { deploymentDashboardUrlPage } from "./dashboard.js"; +import { promptYesNo } from "./lib/utils/prompts.js"; // Backend has minimum chunk size of 5MiB except for the last chunk, // so we use 5MiB as highWaterMark which makes fs.ReadStream[asyncIterator] @@ -279,14 +279,10 @@ async function askToConfirmImport( } logMessage(ctx, messageToConfirm); if (requireManualConfirmation !== false && !yes) { - const { confirmed } = await inquirer.prompt([ - { - type: "confirm", - name: "confirmed", - message: `Perform the import?`, - default: true, - }, - ]); + const confirmed = await promptYesNo(ctx, { + message: "Perform import?", + default: true, + }); if (!confirmed) { return await ctx.crash({ exitCode: 1, @@ -315,14 +311,10 @@ async function askToConfirmImportWithExistingImports( if (yes) { return; } - const { confirmed } = await inquirer.prompt([ - { - type: "confirm", - name: "confirmed", - message: `Start another import?`, - default: true, - }, - ]); + const confirmed = await promptYesNo(ctx, { + message: "Start another import?", + default: true, + }); if (!confirmed) { return await ctx.crash({ exitCode: 1, diff --git a/npm-packages/convex/src/cli/data.ts b/npm-packages/convex/src/cli/data.ts index 5ce17047..01b8372d 100644 --- a/npm-packages/convex/src/cli/data.ts +++ b/npm-packages/convex/src/cli/data.ts @@ -14,7 +14,7 @@ import { fetchDeploymentCredentialsProvisionProd, } from "./lib/api.js"; import { runPaginatedQuery } from "./lib/run.js"; -import { parsePositiveInteger } from "./lib/utils.js"; +import { parsePositiveInteger } from "./lib/utils/utils.js"; import { Command } from "@commander-js/extra-typings"; import { actionDescription } from "./lib/command.js"; diff --git a/npm-packages/convex/src/cli/deploy.ts b/npm-packages/convex/src/cli/deploy.ts index b0bd3d5c..8ab02974 100644 --- a/npm-packages/convex/src/cli/deploy.ts +++ b/npm-packages/convex/src/cli/deploy.ts @@ -1,6 +1,5 @@ import chalk from "chalk"; import { Command, Option } from "@commander-js/extra-typings"; -import inquirer from "inquirer"; import { Context, logFinishedStep, @@ -25,7 +24,7 @@ import { bigBrainAPI, getConfiguredDeploymentName, readAdminKeyFromEnvVar, -} from "./lib/utils.js"; +} from "./lib/utils/utils.js"; import { spawnSync } from "child_process"; import { runFunctionAndLog } from "./lib/run.js"; import { usageStateWarning } from "./lib/usage.js"; @@ -35,6 +34,7 @@ import { isPreviewDeployKey, } from "./lib/deployment.js"; import { runPush } from "./lib/components.js"; +import { promptYesNo } from "./lib/utils/prompts.js"; export const deploy = new Command("deploy") .summary("Deploy to your prod deployment") @@ -413,14 +413,8 @@ Your ${chalk.bold(deployment.requestedType)} deployment ${chalk.bold( Make sure that your published client is configured with this URL (for instructions see https://docs.convex.dev/hosting)\n`, ); - return ( - await inquirer.prompt([ - { - type: "confirm", - name: "shouldPush", - message: `Do you want to push your code to your ${deployment.requestedType} deployment ${deployment.requestedName} now?`, - default: true, - }, - ]) - ).shouldPush; + return promptYesNo(ctx, { + message: `Do you want to push your code to your ${deployment.requestedType} deployment ${deployment.requestedName} now?`, + default: true, + }); } diff --git a/npm-packages/convex/src/cli/deployments.ts b/npm-packages/convex/src/cli/deployments.ts index fc2d57d7..41423dc5 100644 --- a/npm-packages/convex/src/cli/deployments.ts +++ b/npm-packages/convex/src/cli/deployments.ts @@ -1,7 +1,7 @@ import { Command } from "@commander-js/extra-typings"; import { readProjectConfig } from "./lib/config.js"; import chalk from "chalk"; -import { bigBrainAPI } from "./lib/utils.js"; +import { bigBrainAPI } from "./lib/utils/utils.js"; import { logError, logMessage, oneoffContext } from "../bundler/context.js"; type Deployment = { diff --git a/npm-packages/convex/src/cli/dev.ts b/npm-packages/convex/src/cli/dev.ts index 8c82ca0a..5d15b734 100644 --- a/npm-packages/convex/src/cli/dev.ts +++ b/npm-packages/convex/src/cli/dev.ts @@ -21,7 +21,7 @@ import { getCurrentTimeString, waitForever, waitUntilCalled, -} from "./lib/utils.js"; +} from "./lib/utils/utils.js"; import { Crash, WatchContext, Watcher } from "./lib/watch.js"; import { watchLogs } from "./lib/logs.js"; import { subscribe } from "./lib/run.js"; diff --git a/npm-packages/convex/src/cli/docs.ts b/npm-packages/convex/src/cli/docs.ts index 7a9b051f..f57d73c6 100644 --- a/npm-packages/convex/src/cli/docs.ts +++ b/npm-packages/convex/src/cli/docs.ts @@ -3,7 +3,7 @@ import chalk from "chalk"; import open from "open"; import { oneoffContext } from "../bundler/context.js"; import { getTargetDeploymentName } from "./lib/deployment.js"; -import { bigBrainFetch, deprecationCheckWarning } from "./lib/utils.js"; +import { bigBrainFetch, deprecationCheckWarning } from "./lib/utils/utils.js"; export const docs = new Command("docs") .description("Open the docs in the browser") diff --git a/npm-packages/convex/src/cli/env.ts b/npm-packages/convex/src/cli/env.ts index 5f200cdd..a6cfcf93 100644 --- a/npm-packages/convex/src/cli/env.ts +++ b/npm-packages/convex/src/cli/env.ts @@ -19,7 +19,7 @@ import { deploymentFetch, ensureHasConvexDependency, logAndHandleFetchError, -} from "./lib/utils.js"; +} from "./lib/utils/utils.js"; const envSet = new Command("set") // Pretend value is required diff --git a/npm-packages/convex/src/cli/lib/api.ts b/npm-packages/convex/src/cli/lib/api.ts index 6a9b72e6..97966340 100644 --- a/npm-packages/convex/src/cli/lib/api.ts +++ b/npm-packages/convex/src/cli/lib/api.ts @@ -16,7 +16,7 @@ import { getConfiguredDeploymentName, getConfiguredDeploymentOrCrash, readAdminKeyFromEnvVar, -} from "./utils.js"; +} from "./utils/utils.js"; export type DeploymentName = string; export type DeploymentType = "dev" | "prod" | "local"; diff --git a/npm-packages/convex/src/cli/lib/components.ts b/npm-packages/convex/src/cli/lib/components.ts index 6d5b6efc..81210644 100644 --- a/npm-packages/convex/src/cli/lib/components.ts +++ b/npm-packages/convex/src/cli/lib/components.ts @@ -9,7 +9,7 @@ import { import { finishPush, startPush, waitForSchema } from "./deploy2.js"; import { version } from "../version.js"; import { PushOptions, runNonComponentsPush } from "./push.js"; -import { ensureHasConvexDependency, functionsDir } from "./utils.js"; +import { ensureHasConvexDependency, functionsDir } from "./utils/utils.js"; import { bundleDefinitions, bundleImplementations, diff --git a/npm-packages/convex/src/cli/lib/config.ts b/npm-packages/convex/src/cli/lib/config.ts index 3f131124..e9f858b8 100644 --- a/npm-packages/convex/src/cli/lib/config.ts +++ b/npm-packages/convex/src/cli/lib/config.ts @@ -29,14 +29,14 @@ import { deprecationCheckWarning, logAndHandleFetchError, ThrowingFetchError, -} from "./utils.js"; +} from "./utils/utils.js"; import { getTargetDeploymentName } from "./deployment.js"; import { createHash } from "crypto"; import { promisify } from "util"; import zlib from "zlib"; import { recursivelyDelete } from "./fsUtils.js"; import { NodeDependency } from "./deployApi/modules.js"; -export { productionProvisionHost, provisionHost } from "./utils.js"; +export { productionProvisionHost, provisionHost } from "./utils/utils.js"; const brotli = promisify(zlib.brotliCompress); diff --git a/npm-packages/convex/src/cli/lib/deploy2.ts b/npm-packages/convex/src/cli/lib/deploy2.ts index 35323c76..ff264424 100644 --- a/npm-packages/convex/src/cli/lib/deploy2.ts +++ b/npm-packages/convex/src/cli/lib/deploy2.ts @@ -1,5 +1,5 @@ import { changeSpinner, Context, logFailure } from "../../bundler/context.js"; -import { deploymentFetch, logAndHandleFetchError } from "./utils.js"; +import { deploymentFetch, logAndHandleFetchError } from "./utils/utils.js"; import { StartPushRequest, startPushResponse, diff --git a/npm-packages/convex/src/cli/lib/deployment.ts b/npm-packages/convex/src/cli/lib/deployment.ts index 53cf6d8a..d5affaf5 100644 --- a/npm-packages/convex/src/cli/lib/deployment.ts +++ b/npm-packages/convex/src/cli/lib/deployment.ts @@ -4,7 +4,7 @@ import { changedEnvVarFile, getEnvVarRegex } from "./envvars.js"; import { CONVEX_DEPLOY_KEY_ENV_VAR_NAME, readAdminKeyFromEnvVar, -} from "./utils.js"; +} from "./utils/utils.js"; import { DeploymentType } from "./api.js"; const ENV_VAR_FILE_PATH = ".env.local"; diff --git a/npm-packages/convex/src/cli/lib/envvars.ts b/npm-packages/convex/src/cli/lib/envvars.ts index d5081cc3..bb17b7e4 100644 --- a/npm-packages/convex/src/cli/lib/envvars.ts +++ b/npm-packages/convex/src/cli/lib/envvars.ts @@ -5,7 +5,7 @@ import chalk from "chalk"; import * as dotenv from "dotenv"; import { Context, logWarning } from "../../bundler/context.js"; -import { loadPackageJson } from "./utils.js"; +import { loadPackageJson } from "./utils/utils.js"; const FRAMEWORKS = [ "create-react-app", diff --git a/npm-packages/convex/src/cli/lib/indexes.ts b/npm-packages/convex/src/cli/lib/indexes.ts index 445cf9e1..4a78ad1c 100644 --- a/npm-packages/convex/src/cli/lib/indexes.ts +++ b/npm-packages/convex/src/cli/lib/indexes.ts @@ -13,7 +13,7 @@ import { logAndHandleFetchError, deploymentFetch, deprecationCheckWarning, -} from "./utils.js"; +} from "./utils/utils.js"; type IndexMetadata = { table: string; diff --git a/npm-packages/convex/src/cli/lib/localDeployment/bigBrain.ts b/npm-packages/convex/src/cli/lib/localDeployment/bigBrain.ts index b1f76cbd..9cc14341 100644 --- a/npm-packages/convex/src/cli/lib/localDeployment/bigBrain.ts +++ b/npm-packages/convex/src/cli/lib/localDeployment/bigBrain.ts @@ -3,7 +3,7 @@ import { bigBrainAPI, bigBrainFetch, logAndHandleFetchError, -} from "../utils.js"; +} from "../utils/utils.js"; export async function bigBrainStart( ctx: Context, diff --git a/npm-packages/convex/src/cli/lib/localDeployment/filePaths.ts b/npm-packages/convex/src/cli/lib/localDeployment/filePaths.ts index 7f1346c9..0fea6bee 100644 --- a/npm-packages/convex/src/cli/lib/localDeployment/filePaths.ts +++ b/npm-packages/convex/src/cli/lib/localDeployment/filePaths.ts @@ -18,7 +18,7 @@ */ import path from "path"; -import { rootDirectory } from "../utils.js"; +import { rootDirectory } from "../utils/utils.js"; import { Context } from "../../../bundler/context.js"; export function rootDeploymentStateDir() { diff --git a/npm-packages/convex/src/cli/lib/localDeployment/localDeployment.ts b/npm-packages/convex/src/cli/lib/localDeployment/localDeployment.ts index a53f3224..bc18e42c 100644 --- a/npm-packages/convex/src/cli/lib/localDeployment/localDeployment.ts +++ b/npm-packages/convex/src/cli/lib/localDeployment/localDeployment.ts @@ -1,6 +1,5 @@ import { Context, logVerbose } from "../../../bundler/context.js"; import detect from "detect-port"; -import inquirer from "inquirer"; import { bigBrainPause, bigBrainRecordActivity, @@ -24,6 +23,7 @@ import { CleanupDeploymentFunc, OnDeploymentActivityFunc, } from "../deployment.js"; +import { promptSearch } from "../utils/prompts.js"; export type DeploymentDetails = { deploymentName: string; @@ -218,18 +218,13 @@ async function chooseFromExistingLocalDeployments(ctx: Context): Promise<{ config: LocalDeploymentConfig; }> { const localDeployments = await getLocalDeployments(ctx); - const { choice } = await inquirer.prompt([ - { - type: "search-list", - name: "choice", - message: "Choose from an existing local deployment?", - choices: localDeployments.map((d) => ({ - name: d.deploymentName, - value: d, - })), - }, - ]); - return choice; + return promptSearch(ctx, { + message: "Choose from an existing local deployment?", + choices: localDeployments.map((d) => ({ + name: d.deploymentName, + value: d, + })), + }); } async function choosePorts( diff --git a/npm-packages/convex/src/cli/lib/localDeployment/upgrade.ts b/npm-packages/convex/src/cli/lib/localDeployment/upgrade.ts index 9bd40b1a..e4c12128 100644 --- a/npm-packages/convex/src/cli/lib/localDeployment/upgrade.ts +++ b/npm-packages/convex/src/cli/lib/localDeployment/upgrade.ts @@ -13,17 +13,17 @@ import { localDeploymentUrl, runLocalBackend, } from "./run.js"; -import inquirer from "inquirer"; import { downloadSnapshotExport, startSnapshotExport, } from "../../convexExport.js"; -import { deploymentFetch, logAndHandleFetchError } from "../utils.js"; +import { deploymentFetch, logAndHandleFetchError } from "../utils/utils.js"; import { confirmImport, uploadForImport, waitForStableImportState, } from "../../convexImport.js"; +import { promptOptions, promptYesNo } from "../utils/prompts.js"; export async function handlePotentialUpgrade( ctx: Context, @@ -56,16 +56,10 @@ export async function handlePotentialUpgrade( } const confirmed = args.forceUpgrade || - ( - await inquirer.prompt([ - { - type: "confirm", - name: "confirmed", - message: `This deployment is using an older version of the Convex backend. Upgrade now?`, - default: true, - }, - ]) - ).confirmed; + (await promptYesNo(ctx, { + message: `This deployment is using an older version of the Convex backend. Upgrade now?`, + default: true, + })); if (!confirmed) { const { binaryPath: oldBinaryPath } = await ensureBackendBinaryDownloaded( ctx, @@ -85,24 +79,16 @@ export async function handlePotentialUpgrade( deploymentName: args.deploymentName, }); } - const { choice } = args.forceUpgrade - ? { choice: "transfer" } - : await inquirer.prompt([ - { - // In the Convex mono-repo, `list` seems to cause the command to not - // respond to CTRL+C while `search-list` does not. - type: process.env.CONVEX_RUNNING_LIVE_IN_MONOREPO - ? "search-list" - : "list", - name: "choice", - message: "Transfer data from existing deployment?", - default: "transfer", - choices: [ - { name: "transfer data", value: "transfer" }, - { name: "start fresh", value: "reset" }, - ], - }, - ]); + const choice = args.forceUpgrade + ? "transfer" + : await promptOptions(ctx, { + message: "Transfer data from existing deployment?", + default: "transfer", + choices: [ + { name: "transfer data", value: "transfer" }, + { name: "start fresh", value: "reset" }, + ], + }); const deploymentStatePath = deploymentStateDir(args.deploymentName); if (choice === "reset") { ctx.fs.rmdir(deploymentStatePath); diff --git a/npm-packages/convex/src/cli/lib/login.ts b/npm-packages/convex/src/cli/lib/login.ts index e38812a5..0cec37ae 100644 --- a/npm-packages/convex/src/cli/lib/login.ts +++ b/npm-packages/convex/src/cli/lib/login.ts @@ -7,7 +7,7 @@ import { bigBrainAPI, logAndHandleFetchError, throwingFetch, -} from "./utils.js"; +} from "./utils/utils.js"; import open from "open"; import chalk from "chalk"; import { provisionHost } from "./config.js"; @@ -22,10 +22,10 @@ import { showSpinner, } from "../../bundler/context.js"; import { Issuer } from "openid-client"; -import inquirer from "inquirer"; import { hostname } from "os"; import { execSync } from "child_process"; import os from "os"; +import { promptString, promptYesNo } from "./utils/prompts.js"; const SCOPE = "openid email profile"; /// This value was created long ago, and cannot be changed easily. @@ -150,15 +150,10 @@ async function performDeviceAuthorization( }); } catch (error) { // We couldn't get verification URL from Auth0, proceed with manual auth - const answers = await inquirer.prompt([ - { - type: "input", - name: "authToken", - message: - "Open https://dashboard.convex.dev/auth, log in and paste the token here:", - }, - ]); - return answers.authToken; + return promptString(ctx, { + message: + "Open https://dashboard.convex.dev/auth, log in and paste the token here:", + }); } // Device Authorization Response - https://tools.ietf.org/html/rfc8628#section-3.2 @@ -174,16 +169,10 @@ async function performDeviceAuthorization( }: ${user_code}`, ); if (shouldOpen) { - shouldOpen = ( - await inquirer.prompt([ - { - name: "openBrowser", - message: `Open the browser?`, - type: "confirm", - default: true, - }, - ]) - ).openBrowser; + shouldOpen = await promptYesNo(ctx, { + message: `Open the browser?`, + default: true, + }); } if (shouldOpen) { @@ -340,20 +329,15 @@ export async function performLogin( if (!deviceName) { deviceName = hostname(); } - if (process.stdin.isTTY && !deviceNameOverride) { + if (!deviceNameOverride) { logMessage( ctx, chalk.bold(`Welcome to developing with Convex, let's get you logged in.`), ); - const answers = await inquirer.prompt([ - { - type: "input", - name: "deviceName", - message: "Device name:", - default: deviceName, - }, - ]); - deviceName = answers.deviceName; + deviceName = await promptString(ctx, { + message: "Device name:", + default: deviceName, + }); } const issuer = overrideAuthUrl ?? "https://auth.convex.dev"; @@ -455,16 +439,9 @@ async function optins(ctx: Context, acceptOptIns: boolean): Promise { for (const optInToAccept of data.optInsToAccept) { const confirmed = acceptOptIns || - ( - await inquirer.prompt([ - { - type: "confirm", - name: "confirmed", - message: optInToAccept.message, - }, - ]) - ).confirmed; - + (await promptYesNo(ctx, { + message: optInToAccept.message, + })); if (!confirmed) { logFailure(ctx, "Please accept the Terms of Service to use Convex."); return Promise.resolve(false); diff --git a/npm-packages/convex/src/cli/lib/logs.ts b/npm-packages/convex/src/cli/lib/logs.ts index 7f0bb41a..69e024d6 100644 --- a/npm-packages/convex/src/cli/lib/logs.ts +++ b/npm-packages/convex/src/cli/lib/logs.ts @@ -6,7 +6,7 @@ import { } from "../../bundler/context.js"; import { nextBackoff } from "../dev.js"; import chalk from "chalk"; -import { deploymentFetch } from "./utils.js"; +import { deploymentFetch } from "./utils/utils.js"; const MAX_UDF_STREAM_FAILURE_COUNT = 5; diff --git a/npm-packages/convex/src/cli/lib/push.ts b/npm-packages/convex/src/cli/lib/push.ts index 73826987..0f117594 100644 --- a/npm-packages/convex/src/cli/lib/push.ts +++ b/npm-packages/convex/src/cli/lib/push.ts @@ -10,7 +10,7 @@ import { } from "./config.js"; import { pushSchema } from "./indexes.js"; import { typeCheckFunctionsInMode } from "./typecheck.js"; -import { ensureHasConvexDependency, functionsDir } from "./utils.js"; +import { ensureHasConvexDependency, functionsDir } from "./utils/utils.js"; import { handleDebugBundlePath } from "./debugBundlePath.js"; import { CleanupDeploymentFunc } from "./deployment.js"; diff --git a/npm-packages/convex/src/cli/lib/run.ts b/npm-packages/convex/src/cli/lib/run.ts index 1f7cacac..6f207576 100644 --- a/npm-packages/convex/src/cli/lib/run.ts +++ b/npm-packages/convex/src/cli/lib/run.ts @@ -11,7 +11,7 @@ import { logMessage, logOutput, } from "../../bundler/context.js"; -import { waitForever, waitUntilCalled } from "./utils.js"; +import { waitForever, waitUntilCalled } from "./utils/utils.js"; export async function runFunctionAndLog( ctx: Context, diff --git a/npm-packages/convex/src/cli/lib/typecheck.ts b/npm-packages/convex/src/cli/lib/typecheck.ts index b53bed36..aea57dc5 100644 --- a/npm-packages/convex/src/cli/lib/typecheck.ts +++ b/npm-packages/convex/src/cli/lib/typecheck.ts @@ -8,7 +8,7 @@ import { } from "../../bundler/context.js"; import * as Sentry from "@sentry/node"; import * as semver from "semver"; -import { spawnAsync } from "./utils.js"; +import { spawnAsync } from "./utils/utils.js"; export type TypecheckResult = "cantTypeCheck" | "success" | "typecheckFailed"; diff --git a/npm-packages/convex/src/cli/lib/usage.ts b/npm-packages/convex/src/cli/lib/usage.ts index 26362305..d87f1540 100644 --- a/npm-packages/convex/src/cli/lib/usage.ts +++ b/npm-packages/convex/src/cli/lib/usage.ts @@ -7,7 +7,7 @@ import { getAuthHeaderForBigBrain, getConfiguredDeploymentName, getConfiguredDeploymentOrCrash, -} from "./utils.js"; +} from "./utils/utils.js"; async function warn(ctx: Context, title: string, subtitle: string) { const configuredDeployment = await getConfiguredDeploymentOrCrash(ctx); diff --git a/npm-packages/convex/src/cli/lib/utils/prompts.ts b/npm-packages/convex/src/cli/lib/utils/prompts.ts new file mode 100644 index 00000000..5f0f3c62 --- /dev/null +++ b/npm-packages/convex/src/cli/lib/utils/prompts.ts @@ -0,0 +1,118 @@ +import inquirer from "inquirer"; +import { Context, logOutput } from "../../../bundler/context.js"; + +export const promptString = async ( + ctx: Context, + options: { + message: string; + default?: string; + }, +): Promise => { + if (process.stdin.isTTY) { + const result = ( + await inquirer.prompt([ + { + type: "input", + name: "result", + message: options.message, + default: options.default, + }, + ]) + ).result; + return result; + } else { + return ctx.crash({ + exitCode: 1, + errorType: "fatal", + printedMessage: "Cannot prompt for input in non-interactive terminals.", + }); + } +}; + +export const promptOptions = async ( + ctx: Context, + options: { + message: string; + choices: Array<{ name: string; value: V }>; + default?: V; + }, +): Promise => { + if (process.stdin.isTTY) { + const result = ( + await inquirer.prompt([ + { + // In the Convex mono-repo, `list` seems to cause the command to not + // respond to CTRL+C while `search-list` does not. + type: process.env.CONVEX_RUNNING_LIVE_IN_MONOREPO + ? "search-list" + : "list", + name: "result", + message: options.message, + choices: options.choices, + default: options.default, + }, + ]) + ).result; + return result; + } else { + return ctx.crash({ + exitCode: 1, + errorType: "fatal", + printedMessage: "Cannot prompt for input in non-interactive terminals.", + }); + } +}; + +export const promptSearch = async ( + ctx: Context, + options: { + message: string; + choices: Array<{ name: string; value: V }>; + default?: V; + }, +): Promise => { + if (process.stdin.isTTY) { + const result = ( + await inquirer.prompt([ + { + type: "search-list", + name: "result", + message: options.message, + choices: options.choices, + default: options.default, + }, + ]) + ).result; + return result; + } else { + return ctx.crash({ + exitCode: 1, + errorType: "fatal", + printedMessage: "Cannot prompt for input in non-interactive terminals.", + }); + } +}; + +export const promptYesNo = async ( + ctx: Context, + options: { message: string; default?: boolean }, +): Promise => { + if (process.stdin.isTTY) { + const { result } = await inquirer.prompt([ + { + type: "confirm", + name: "result", + message: options.message, + default: options.default, + }, + ]); + return result; + } else { + logOutput(ctx, options.message); + return ctx.crash({ + exitCode: 1, + errorType: "fatal", + printedMessage: "Cannot prompt for input in non-interactive terminals.", + }); + } +}; diff --git a/npm-packages/convex/src/cli/lib/utils.ts b/npm-packages/convex/src/cli/lib/utils/utils.ts similarity index 94% rename from npm-packages/convex/src/cli/lib/utils.ts rename to npm-packages/convex/src/cli/lib/utils/utils.ts index 97a6c284..5ec11d88 100644 --- a/npm-packages/convex/src/cli/lib/utils.ts +++ b/npm-packages/convex/src/cli/lib/utils/utils.ts @@ -1,11 +1,9 @@ import chalk from "chalk"; -import inquirer from "inquirer"; import os from "os"; import path from "path"; -import * as readline from "readline"; import { z } from "zod"; -import { ProjectConfig } from "./config.js"; +import { ProjectConfig } from "../config.js"; import { spawn } from "child_process"; import { InvalidArgumentError } from "commander"; @@ -16,13 +14,14 @@ import { logError, logMessage, logWarning, -} from "../../bundler/context.js"; -import { version } from "../version.js"; -import { Project } from "./api.js"; +} from "../../../bundler/context.js"; +import { version } from "../../version.js"; +import { Project } from "../api.js"; import { getConfiguredDeploymentFromEnvVar, isPreviewDeployKey, -} from "./deployment.js"; +} from "../deployment.js"; +import { promptSearch, promptYesNo } from "./prompts.js"; const retryingFetch = fetchRetryFactory(fetch); @@ -50,21 +49,6 @@ export function parseInteger(value: string) { return parsedValue; } -/** Prompt for keyboard input with the given `query` string and return a promise - * that resolves to the input. */ -export function prompt(query: string) { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stderr, - }); - return new Promise((resolve) => - rl.question(query, (answer) => { - rl.close(); - resolve(answer); - }), - ); -} - export type ErrorData = { code: string; message: string; @@ -293,19 +277,13 @@ export async function validateOrSelectTeam( return { teamSlug: teams[0].slug, chosen: false }; default: return { - teamSlug: ( - await inquirer.prompt([ - { - name: "teamSlug", - message: promptMessage, - type: "search-list", - choices: teams.map((team: Team) => ({ - name: `${team.name} (${team.slug})`, - value: team.slug, - })), - }, - ]) - ).teamSlug, + teamSlug: await promptSearch(ctx, { + message: promptMessage, + choices: teams.map((team: Team) => ({ + name: `${team.name} (${team.slug})`, + value: team.slug, + })), + }), chosen: true, }; } @@ -371,15 +349,9 @@ export async function validateOrSelectProject( switch (nonDemoProjects.length) { case 1: { const project = nonDemoProjects[0]; - const confirmed = ( - await inquirer.prompt([ - { - type: "confirm", - name: "confirmed", - message: `${singleProjectPrompt} ${project.name} (${project.slug})?`, - }, - ]) - ).confirmed; + const confirmed = await promptYesNo(ctx, { + message: `${singleProjectPrompt} ${project.name} (${project.slug})?`, + }); if (!confirmed) { return null; @@ -387,19 +359,13 @@ export async function validateOrSelectProject( return nonDemoProjects[0].slug; } default: - return ( - await inquirer.prompt([ - { - name: "project", - message: multiProjectPrompt, - type: "search-list", - choices: nonDemoProjects.map((project: Project) => ({ - name: `${project.name} (${project.slug})`, - value: project.slug, - })), - }, - ]) - ).project; + return await promptSearch(ctx, { + message: multiProjectPrompt, + choices: nonDemoProjects.map((project: Project) => ({ + name: `${project.name} (${project.slug})`, + value: project.slug, + })), + }); } } else { // Validate the chosen project. diff --git a/npm-packages/convex/src/cli/logout.ts b/npm-packages/convex/src/cli/logout.ts index 80b2a38d..fcd6e760 100644 --- a/npm-packages/convex/src/cli/logout.ts +++ b/npm-packages/convex/src/cli/logout.ts @@ -1,6 +1,6 @@ import { Command } from "@commander-js/extra-typings"; import { logFinishedStep, oneoffContext } from "../bundler/context.js"; -import { globalConfigPath } from "./lib/utils.js"; +import { globalConfigPath } from "./lib/utils/utils.js"; import { recursivelyDelete } from "./lib/fsUtils.js"; export const logout = new Command("logout") diff --git a/npm-packages/convex/src/cli/logs.ts b/npm-packages/convex/src/cli/logs.ts index 489da21f..f580c8ea 100644 --- a/npm-packages/convex/src/cli/logs.ts +++ b/npm-packages/convex/src/cli/logs.ts @@ -7,7 +7,7 @@ import { } from "./lib/api.js"; import { actionDescription } from "./lib/command.js"; import { watchLogs } from "./lib/logs.js"; -import { parseInteger } from "./lib/utils.js"; +import { parseInteger } from "./lib/utils/utils.js"; export const logs = new Command("logs") .summary("Watch logs from your deployment") diff --git a/npm-packages/convex/src/cli/network_test.ts b/npm-packages/convex/src/cli/network_test.ts index ca98ab08..536ee969 100644 --- a/npm-packages/convex/src/cli/network_test.ts +++ b/npm-packages/convex/src/cli/network_test.ts @@ -19,7 +19,7 @@ import { bareDeploymentFetch, formatDuration, formatSize, -} from "./lib/utils.js"; +} from "./lib/utils/utils.js"; import chalk from "chalk"; const ipFamilyNumbers = { ipv4: 4, ipv6: 6, auto: 0 } as const; diff --git a/npm-packages/convex/src/cli/run.ts b/npm-packages/convex/src/cli/run.ts index f57a0057..ec989e84 100644 --- a/npm-packages/convex/src/cli/run.ts +++ b/npm-packages/convex/src/cli/run.ts @@ -7,7 +7,7 @@ import { } from "./lib/api.js"; import { actionDescription } from "./lib/command.js"; import { runFunctionAndLog, subscribeAndLog } from "./lib/run.js"; -import { ensureHasConvexDependency } from "./lib/utils.js"; +import { ensureHasConvexDependency } from "./lib/utils/utils.js"; export const run = new Command("run") .description("Run a function (query, mutation, or action) on your deployment") diff --git a/npm-packages/convex/src/cli/typecheck.ts b/npm-packages/convex/src/cli/typecheck.ts index 368a97a7..78ee04f5 100644 --- a/npm-packages/convex/src/cli/typecheck.ts +++ b/npm-packages/convex/src/cli/typecheck.ts @@ -1,5 +1,5 @@ import chalk from "chalk"; -import { functionsDir, ensureHasConvexDependency } from "./lib/utils.js"; +import { functionsDir, ensureHasConvexDependency } from "./lib/utils/utils.js"; import { Command } from "@commander-js/extra-typings"; import { readConfig } from "./lib/config.js"; import { typeCheckFunctions } from "./lib/typecheck.js"; diff --git a/npm-packages/convex/src/cli/update.ts b/npm-packages/convex/src/cli/update.ts index 18a83086..252fbd36 100644 --- a/npm-packages/convex/src/cli/update.ts +++ b/npm-packages/convex/src/cli/update.ts @@ -1,7 +1,7 @@ import chalk from "chalk"; import { Command } from "@commander-js/extra-typings"; import { oneoffContext } from "../bundler/context.js"; -import { loadPackageJson } from "./lib/utils.js"; +import { loadPackageJson } from "./lib/utils/utils.js"; export const update = new Command("update") .description("Print instructions for updating the convex package")