Skip to main content
Glama

Convex MCP server

Official
by get-convex
deploy.ts11.9 kB
import chalk from "chalk"; import { Command, Option } from "@commander-js/extra-typings"; import { Context, oneoffContext } from "../bundler/context.js"; import { logFinishedStep, logMessage, showSpinner } from "../bundler/log.js"; import { deploymentSelectionWithinProjectFromOptions, loadSelectedDeploymentCredentials, } from "./lib/api.js"; import { gitBranchFromEnvironment, isNonProdBuildEnvironment, suggestedEnvVarName, } from "./lib/envvars.js"; import { PushOptions } from "./lib/push.js"; import { CONVEX_DEPLOY_KEY_ENV_VAR_NAME, CONVEX_SELF_HOSTED_URL_VAR_NAME, CONVEX_DEPLOYMENT_ENV_VAR_NAME, bigBrainAPI, } from "./lib/utils/utils.js"; import { runFunctionAndLog } from "./lib/run.js"; import { usageStateWarning } from "./lib/usage.js"; import { getTeamAndProjectFromPreviewAdminKey } from "./lib/deployment.js"; import { runPush } from "./lib/components.js"; import { promptYesNo } from "./lib/utils/prompts.js"; import { deployToDeployment, runCommand } from "./lib/deploy2.js"; import { getDeploymentSelection } from "./lib/deploymentSelection.js"; import { deploymentNameAndTypeFromSelection } from "./lib/deploymentSelection.js"; import { checkVersion } from "./lib/updates.js"; export const deploy = new Command("deploy") .summary("Deploy to your prod deployment") .description( "Deploy to your deployment. By default, this deploys to your prod deployment.\n\n" + `Deploys to a preview deployment if the \`${CONVEX_DEPLOY_KEY_ENV_VAR_NAME}\` environment variable is set to a Preview Deploy Key.`, ) .allowExcessArguments(false) .addDeployOptions() .addOption( new Option( "--preview-run <functionName>", "Function to run if deploying to a preview deployment. This is ignored if deploying to a production deployment.", ), ) .addOption( new Option( "--preview-create <name>", "The name to associate with this deployment if deploying to a newly created preview deployment. Defaults to the current Git branch name in Vercel, Netlify and GitHub CI. This is ignored if deploying to a production deployment.", ).conflicts("preview-name"), ) .addOption( new Option( "--check-build-environment <mode>", "Whether to check for a non-production build environment before deploying to a production Convex deployment.", ) .choices(["enable", "disable"] as const) .default("enable" as const) .hideHelp(), ) // Hidden options to pass in admin key and url for tests and local development .addOption(new Option("--admin-key <adminKey>").hideHelp()) .addOption(new Option("--url <url>").hideHelp()) .addOption( new Option( "--preview-name <name>", "[deprecated] Use `--preview-create` instead. The name to associate with this deployment if deploying to a preview deployment.", ) .hideHelp() .conflicts("preview-create"), ) .addOption( new Option( "--env-file <envFile>", `Path to a custom file of environment variables, for choosing the \ deployment, e.g. ${CONVEX_DEPLOYMENT_ENV_VAR_NAME} or ${CONVEX_SELF_HOSTED_URL_VAR_NAME}. \ Same format as .env.local or .env files, and overrides them.`, ), ) .showHelpAfterError() .action(async (cmdOptions) => { const ctx = await oneoffContext(cmdOptions); const deploymentSelection = await getDeploymentSelection(ctx, cmdOptions); if ( cmdOptions.checkBuildEnvironment === "enable" && isNonProdBuildEnvironment() && deploymentSelection.kind === "existingDeployment" && deploymentSelection.deploymentToActOn.source === "deployKey" && deploymentSelection.deploymentToActOn.deploymentFields?.deploymentType === "prod" ) { await ctx.crash({ exitCode: 1, errorType: "invalid filesystem data", printedMessage: `Detected a non-production build environment and "${CONVEX_DEPLOY_KEY_ENV_VAR_NAME}" for a production Convex deployment.\n This is probably unintentional. `, }); } if (deploymentSelection.kind === "anonymous") { logMessage( "You are currently developing anonymously with a locally running project.\n" + "To deploy your Convex app to the cloud, log in by running `npx convex login`.\n" + "See https://docs.convex.dev/production for more information on how Convex cloud works and instructions on how to set up hosting.", ); return await ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: null, }); } if (deploymentSelection.kind === "preview") { // TODO -- add usage state warnings here too once we can do it without a deployment name // await usageStateWarning(ctx); if (cmdOptions.previewName !== undefined) { await ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: "The `--preview-name` flag has been deprecated in favor of `--preview-create`. Please re-run the command using `--preview-create` instead.", }); } const teamAndProjectSlugs = await getTeamAndProjectFromPreviewAdminKey( ctx, deploymentSelection.previewDeployKey, ); await deployToNewPreviewDeployment( ctx, { previewDeployKey: deploymentSelection.previewDeployKey, projectSelection: { kind: "teamAndProjectSlugs", teamSlug: teamAndProjectSlugs.teamSlug, projectSlug: teamAndProjectSlugs.projectSlug, }, }, { ...cmdOptions, }, ); } else { await deployToExistingDeployment(ctx, cmdOptions); } }); async function deployToNewPreviewDeployment( ctx: Context, deploymentSelection: { previewDeployKey: string; projectSelection: { kind: "teamAndProjectSlugs"; teamSlug: string; projectSlug: string; }; }, options: { dryRun?: boolean | undefined; previewCreate?: string | undefined; previewRun?: string | undefined; cmdUrlEnvVarName?: string | undefined; cmd?: string | undefined; verbose?: boolean | undefined; typecheck: "enable" | "try" | "disable"; typecheckComponents: boolean; codegen: "enable" | "disable"; debug?: boolean | undefined; debugBundlePath?: string | undefined; }, ) { const previewName = options.previewCreate ?? gitBranchFromEnvironment(); if (previewName === null) { await ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: "`npx convex deploy` to a preview deployment could not determine the preview name. Provide one using `--preview-create`", }); } if (options.dryRun) { logFinishedStep( `Would have claimed preview deployment for "${previewName}"`, ); await runCommand(ctx, { cmdUrlEnvVarName: options.cmdUrlEnvVarName, cmd: options.cmd, dryRun: !!options.dryRun, url: "https://<PREVIEW DEPLOYMENT>.convex.cloud", adminKey: "preview-deployment-admin-key", }); logFinishedStep( `Would have deployed Convex functions to preview deployment for "${previewName}"`, ); if (options.previewRun !== undefined) { logMessage(`Would have run function "${options.previewRun}"`); } return; } const data = await bigBrainAPI({ ctx, method: "POST", url: "claim_preview_deployment", data: { projectSelection: deploymentSelection.projectSelection, identifier: previewName, }, }); const previewAdminKey = data.adminKey; const previewUrl = data.instanceUrl; await runCommand(ctx, { ...options, url: previewUrl, adminKey: previewAdminKey, }); const pushOptions: PushOptions = { deploymentName: data.deploymentName, adminKey: previewAdminKey, verbose: !!options.verbose, dryRun: false, typecheck: options.typecheck, typecheckComponents: options.typecheckComponents, debug: !!options.debug, debugBundlePath: options.debugBundlePath, debugNodeApis: false, codegen: options.codegen === "enable", url: previewUrl, liveComponentSources: false, }; showSpinner(`Deploying to ${previewUrl}...`); await runPush(ctx, pushOptions); logFinishedStep(`Deployed Convex functions to ${previewUrl}`); if (options.previewRun !== undefined) { await runFunctionAndLog(ctx, { deploymentUrl: previewUrl, adminKey: previewAdminKey, functionName: options.previewRun, argsString: "{}", componentPath: undefined, callbacks: { onSuccess: () => { logFinishedStep(`Finished running function "${options.previewRun}"`); }, }, }); } } async function deployToExistingDeployment( ctx: Context, options: { verbose?: boolean | undefined; dryRun?: boolean | undefined; yes?: boolean | undefined; typecheck: "enable" | "try" | "disable"; typecheckComponents: boolean; codegen: "enable" | "disable"; cmd?: string | undefined; cmdUrlEnvVarName?: string | undefined; debugBundlePath?: string | undefined; debug?: boolean | undefined; adminKey?: string | undefined; url?: string | undefined; writePushRequest?: string | undefined; liveComponentSources?: boolean | undefined; envFile?: string | undefined; }, ) { const selectionWithinProject = deploymentSelectionWithinProjectFromOptions({ ...options, implicitProd: true, }); const deploymentSelection = await getDeploymentSelection(ctx, options); const deploymentToActOn = await loadSelectedDeploymentCredentials( ctx, deploymentSelection, selectionWithinProject, ); const { deploymentFields } = deploymentToActOn; const configuredDeployment = deploymentNameAndTypeFromSelection(deploymentSelection); if (configuredDeployment !== null && configuredDeployment.name !== null) { const shouldPushToProd = configuredDeployment.name === deploymentFields?.deploymentName || (options.yes ?? (await askToConfirmPush( ctx, { configuredName: configuredDeployment.name, configuredType: configuredDeployment.type, requestedName: deploymentFields?.deploymentName!, requestedType: deploymentFields?.deploymentType!, }, deploymentToActOn.url, ))); if (!shouldPushToProd) { await ctx.crash({ exitCode: 1, printedMessage: null, errorType: "fatal", }); } } const isCloudDeployment = deploymentFields !== null; await Promise.all([ deployToDeployment( ctx, { url: deploymentToActOn.url, adminKey: deploymentToActOn.adminKey, deploymentName: deploymentFields?.deploymentName ?? null, }, options, ), ...(isCloudDeployment ? [ usageStateWarning(ctx, deploymentFields.deploymentName), checkVersion(), ] : []), ]); } async function askToConfirmPush( ctx: Context, deployment: { configuredName: string; configuredType: string | null; requestedName: string; requestedType: string; }, prodUrl: string, ) { logMessage( `\ You're currently developing against your ${chalk.bold( deployment.configuredType ?? "dev", )} deployment ${deployment.configuredName} (set in CONVEX_DEPLOYMENT) Your ${chalk.bold(deployment.requestedType)} deployment ${chalk.bold( deployment.requestedName, )} serves traffic at: ${(await suggestedEnvVarName(ctx)).envVar}=${chalk.bold(prodUrl)} Make sure that your published client is configured with this URL (for instructions see https://docs.convex.dev/hosting)\n`, ); return promptYesNo(ctx, { message: `Do you want to push your code to your ${deployment.requestedType} deployment ${deployment.requestedName} now?`, default: true, }); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server