convex
Version:
Client for the Convex Cloud
100 lines (91 loc) • 3.34 kB
text/typescript
import { Command, Option } from "@commander-js/extra-typings";
import { oneoffContext } from "../bundler/context.js";
import { logFinishedStep, logMessage, showSpinner } from "../bundler/log.js";
import { chalkStderr } from "chalk";
import { createProject } from "./lib/api.js";
import { ensureAuthCanCreateDeployment } from "./lib/deploymentSelection.js";
import { validateOrSelectTeam } from "./lib/utils/utils.js";
import { promptString } from "./lib/utils/prompts.js";
import { projectDashboardUrl } from "./lib/dashboard.js";
type ProjectCreateOptions = {
team?: string | undefined;
};
async function runProjectCreate(
nameArg: string | undefined,
options: ProjectCreateOptions,
): Promise<void> {
const ctx = await oneoffContext({
url: undefined,
adminKey: undefined,
envFile: undefined,
});
// Creating a project goes through the platform API, which accepts personal
// access tokens and project keys but not deployment/preview deploy keys.
// Fail fast (and clearly) for the unsupported keys rather than surfacing an
// opaque error later.
await ensureAuthCanCreateDeployment(ctx);
const { team } = await validateOrSelectTeam(ctx, options.team, "Team:");
let projectName = nameArg;
if (!projectName) {
if (!process.stdin.isTTY) {
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage:
"Specify a project name:\n" + " `npx convex project create my-app`",
});
}
projectName = await promptString(ctx, {
message: "Project name:",
});
}
showSpinner(`Creating project ${projectName}...`);
// `project create` only creates the project. Provisioning a deployment is a
// separate, explicit step (`npx convex deployment create`) so this command
// doesn't have to mirror every deployment setting (region, class, ...).
const { projectSlug } = await createProject(ctx, {
teamId: team.id,
projectName,
deploymentToProvision: null,
});
logFinishedStep(
`Created project ${chalkStderr.bold(projectSlug)} in team ` +
`${chalkStderr.bold(team.slug)}, manage it at ${chalkStderr.bold(
projectDashboardUrl(team.slug, projectSlug),
)}`,
);
logMessage(
chalkStderr.gray(
`Next, add a deployment with ` +
`\`npx convex deployment create ${team.slug}:${projectSlug}:dev --type dev\` ` +
`(pass \`--region us\` to choose a region).`,
),
);
}
export const projectCreate = new Command("create")
.summary("Create a new project")
.description(
[
"Create a new project.",
"",
"Provisioning a deployment is a separate step — after creating the",
"project, run `npx convex deployment create` to add one.",
"",
"• Create a project in your only team: `npx convex project create my-app`",
"• Pick the team: `npx convex project create my-app --team my-team`",
].join("\n"),
)
.allowExcessArguments(false)
.argument(
"[name]",
"The name of the new project. Prompted for when omitted in an " +
"interactive terminal; required otherwise.",
)
.addOption(
new Option(
"--team <team_slug>",
"The team to create the project in. Defaults to your only team, or " +
"prompts when you belong to several.",
),
)
.action(runProjectCreate);