convex
Version:
Client for the Convex Cloud
511 lines (510 loc) • 19.6 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var configure_exports = {};
__export(configure_exports, {
_deploymentCredentialsOrConfigure: () => _deploymentCredentialsOrConfigure,
deploymentCredentialsOrConfigure: () => deploymentCredentialsOrConfigure,
handleManuallySetUrlAndAdminKey: () => handleManuallySetUrlAndAdminKey,
selectProject: () => selectProject,
updateEnvAndConfigForDeploymentSelection: () => updateEnvAndConfigForDeploymentSelection
});
module.exports = __toCommonJS(configure_exports);
var import_chalk = require("chalk");
var import_log = require("../bundler/log.js");
var import_api = require("./lib/api.js");
var import_config = require("./lib/config.js");
var import_deployment = require("./lib/deployment.js");
var import_init = require("./lib/init.js");
var import_utils = require("./lib/utils/utils.js");
var import_envvars = require("./lib/envvars.js");
var import_path = __toESM(require("path"), 1);
var import_dashboard = require("./lib/dashboard.js");
var import_codegen = require("./lib/codegen.js");
var import_localDeployment = require("./lib/localDeployment/localDeployment.js");
var import_prompts = require("./lib/utils/prompts.js");
var import_globalConfig = require("./lib/utils/globalConfig.js");
var import_deploymentSelection = require("./lib/deploymentSelection.js");
var import_login = require("./lib/login.js");
var import_anonymous = require("./lib/localDeployment/anonymous.js");
async function deploymentCredentialsOrConfigure(ctx, deploymentSelection, chosenConfiguration, cmdOptions) {
const selectedDeployment = await _deploymentCredentialsOrConfigure(
ctx,
deploymentSelection,
chosenConfiguration,
cmdOptions
);
if (selectedDeployment.deploymentFields !== null) {
await updateEnvAndConfigForDeploymentSelection(
ctx,
{
url: selectedDeployment.url,
deploymentName: selectedDeployment.deploymentFields.deploymentName,
teamSlug: selectedDeployment.deploymentFields.teamSlug,
projectSlug: selectedDeployment.deploymentFields.projectSlug,
deploymentType: selectedDeployment.deploymentFields.deploymentType
},
(0, import_deploymentSelection.deploymentNameFromSelection)(deploymentSelection)
);
} else {
await handleManuallySetUrlAndAdminKey(ctx, {
url: selectedDeployment.url,
adminKey: selectedDeployment.adminKey
});
}
return {
url: selectedDeployment.url,
adminKey: selectedDeployment.adminKey,
deploymentFields: selectedDeployment.deploymentFields
};
}
async function _deploymentCredentialsOrConfigure(ctx, deploymentSelection, chosenConfiguration, cmdOptions) {
const config = (0, import_globalConfig.readGlobalConfig)(ctx);
const globallyForceCloud = !!config?.optOutOfLocalDevDeploymentsUntilBetaOver;
if (globallyForceCloud && cmdOptions.local) {
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: "Can't specify --local when local deployments are disabled on this machine. Run `npx convex disable-local-deployments --undo-global` to allow use of --local."
});
}
switch (deploymentSelection.kind) {
case "existingDeployment":
await (0, import_api.validateDeploymentSelectionForExistingDeployment)(
ctx,
cmdOptions.selectionWithinProject,
deploymentSelection.deploymentToActOn.source
);
if (deploymentSelection.deploymentToActOn.deploymentFields === null) {
await handleManuallySetUrlAndAdminKey(ctx, {
url: deploymentSelection.deploymentToActOn.url,
adminKey: deploymentSelection.deploymentToActOn.adminKey
});
}
return {
url: deploymentSelection.deploymentToActOn.url,
adminKey: deploymentSelection.deploymentToActOn.adminKey,
deploymentFields: deploymentSelection.deploymentToActOn.deploymentFields
};
case "chooseProject": {
await (0, import_login.ensureLoggedIn)(ctx, {
overrideAuthUrl: cmdOptions.overrideAuthUrl,
overrideAuthClient: cmdOptions.overrideAuthClient,
overrideAuthUsername: cmdOptions.overrideAuthUsername,
overrideAuthPassword: cmdOptions.overrideAuthPassword
});
return await handleChooseProject(
ctx,
chosenConfiguration,
{
globallyForceCloud
},
cmdOptions
);
}
case "preview":
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: "Use `npx convex deploy` to use preview deployments."
});
case "deploymentWithinProject": {
return await handleDeploymentWithinProject(ctx, {
chosenConfiguration,
targetProject: deploymentSelection.targetProject,
cmdOptions,
globallyForceCloud
});
}
case "anonymous": {
const hasAuth = ctx.bigBrainAuth() !== null;
if (hasAuth && deploymentSelection.deploymentName !== null) {
const shouldConfigure = chosenConfiguration !== null || await (0, import_prompts.promptYesNo)(ctx, {
message: `${import_utils.CONVEX_DEPLOYMENT_ENV_VAR_NAME} is configured with deployment ${deploymentSelection.deploymentName}, which is not linked with your account. Would you like to choose a different project instead?`
});
if (!shouldConfigure) {
return await ctx.crash({
exitCode: 0,
errorType: "fatal",
printedMessage: `Run \`npx convex login --link-deployments\` first to link this deployment to your account, and then run \`npx convex dev\` again.`
});
}
return await handleChooseProject(
ctx,
chosenConfiguration,
{
globallyForceCloud
},
cmdOptions
);
}
const alreadyHasConfiguredAnonymousDeployment = deploymentSelection.deploymentName !== null && chosenConfiguration === null;
const forceAnonymous = process.env.CONVEX_AGENT_MODE === "anonymous";
if (forceAnonymous) {
(0, import_log.logWarning)(
import_chalk.chalkStderr.yellow.bold(
"CONVEX_AGENT_MODE=anonymous mode is in beta, functionality may change in the future."
)
);
}
const shouldPromptForLogin = forceAnonymous ? "no" : alreadyHasConfiguredAnonymousDeployment ? "no" : await (0, import_prompts.promptOptions)(ctx, {
message: "Welcome to Convex! Would you like to login to your account?",
choices: [
{
name: "Start without an account (run Convex locally)",
value: "no"
},
{ name: "Login or create an account", value: "yes" }
],
default: "no"
});
if (shouldPromptForLogin === "no") {
const result = await (0, import_anonymous.handleAnonymousDeployment)(ctx, {
chosenConfiguration,
deploymentName: deploymentSelection.deploymentName,
...cmdOptions.localOptions
});
return {
adminKey: result.adminKey,
url: result.deploymentUrl,
deploymentFields: {
deploymentName: result.deploymentName,
deploymentType: "anonymous",
projectSlug: null,
teamSlug: null
}
};
}
return await handleChooseProject(
ctx,
chosenConfiguration,
{
globallyForceCloud
},
cmdOptions
);
}
}
}
async function handleDeploymentWithinProject(ctx, {
chosenConfiguration,
targetProject,
cmdOptions,
globallyForceCloud
}) {
const hasAuth = ctx.bigBrainAuth() !== null;
const loginMessage = hasAuth && (0, import_deploymentSelection.shouldAllowAnonymousDevelopment)() ? void 0 : `Tip: You can try out Convex without creating an account by clearing the ${import_utils.CONVEX_DEPLOYMENT_ENV_VAR_NAME} environment variable.`;
await (0, import_login.ensureLoggedIn)(ctx, {
message: loginMessage,
overrideAuthUrl: cmdOptions.overrideAuthUrl,
overrideAuthClient: cmdOptions.overrideAuthClient,
overrideAuthUsername: cmdOptions.overrideAuthUsername,
overrideAuthPassword: cmdOptions.overrideAuthPassword
});
if (chosenConfiguration !== null) {
const result = await handleChooseProject(
ctx,
chosenConfiguration,
{
globallyForceCloud
},
cmdOptions
);
return result;
}
const accessResult = await (0, import_api.checkAccessToSelectedProject)(ctx, targetProject);
if (accessResult.kind === "noAccess") {
(0, import_log.logMessage)("You don't have access to the selected project.");
const result = await handleChooseProject(
ctx,
chosenConfiguration,
{
globallyForceCloud
},
cmdOptions
);
return result;
}
const selectedDeployment = await (0, import_api.loadSelectedDeploymentCredentials)(
ctx,
{
kind: "deploymentWithinProject",
targetProject
},
cmdOptions.selectionWithinProject,
// We'll start running it below
{ ensureLocalRunning: false }
);
if (selectedDeployment.deploymentFields !== null && selectedDeployment.deploymentFields.deploymentType === "local") {
await (0, import_localDeployment.handleLocalDeployment)(ctx, {
teamSlug: selectedDeployment.deploymentFields.teamSlug,
projectSlug: selectedDeployment.deploymentFields.projectSlug,
forceUpgrade: cmdOptions.localOptions.forceUpgrade,
ports: cmdOptions.localOptions.ports,
backendVersion: cmdOptions.localOptions.backendVersion
});
}
return {
url: selectedDeployment.url,
adminKey: selectedDeployment.adminKey,
deploymentFields: selectedDeployment.deploymentFields
};
}
async function handleChooseProject(ctx, chosenConfiguration, args, cmdOptions) {
await (0, import_login.ensureLoggedIn)(ctx, {
overrideAuthUrl: cmdOptions.overrideAuthUrl,
overrideAuthClient: cmdOptions.overrideAuthClient,
overrideAuthUsername: cmdOptions.overrideAuthUsername,
overrideAuthPassword: cmdOptions.overrideAuthPassword
});
const project = await selectProject(ctx, chosenConfiguration, {
team: cmdOptions.team,
project: cmdOptions.project,
devDeployment: cmdOptions.devDeployment,
local: args.globallyForceCloud ? false : cmdOptions.local,
cloud: args.globallyForceCloud ? true : cmdOptions.cloud
});
const deploymentOptions = cmdOptions.selectionWithinProject.kind === "prod" ? { kind: "prod" } : project.devDeployment === "local" ? { kind: "local", ...cmdOptions.localOptions } : { kind: "dev" };
const {
deploymentName,
deploymentUrl: url,
adminKey
} = await ensureDeploymentProvisioned(ctx, {
teamSlug: project.teamSlug,
projectSlug: project.projectSlug,
deploymentOptions
});
return {
url,
adminKey,
deploymentFields: {
deploymentName,
deploymentType: deploymentOptions.kind,
projectSlug: project.projectSlug,
teamSlug: project.teamSlug
}
};
}
async function handleManuallySetUrlAndAdminKey(ctx, cmdOptions) {
const { url, adminKey } = cmdOptions;
const didErase = await (0, import_deployment.eraseDeploymentEnvVar)(ctx);
if (didErase) {
(0, import_log.logMessage)(
import_chalk.chalkStderr.yellowBright(
`Removed the CONVEX_DEPLOYMENT environment variable from .env.local`
)
);
}
const envVarWrite = await (0, import_envvars.writeConvexUrlToEnvFile)(ctx, url);
if (envVarWrite !== null) {
(0, import_log.logMessage)(
import_chalk.chalkStderr.green(
`Saved the given --url as ${envVarWrite.envVar} to ${envVarWrite.envFile}`
)
);
}
return { url, adminKey };
}
async function selectProject(ctx, chosenConfiguration, cmdOptions) {
const choice = chosenConfiguration !== "ask" && chosenConfiguration !== null ? chosenConfiguration : await askToConfigure(ctx);
switch (choice) {
case "new":
return selectNewProject(ctx, chosenConfiguration, cmdOptions);
case "existing":
return selectExistingProject(ctx, chosenConfiguration, cmdOptions);
default:
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: "No project selected."
});
}
}
const cwd = import_path.default.basename(process.cwd());
async function selectNewProject(ctx, chosenConfiguration, config) {
const { teamSlug: selectedTeam, chosen: didChooseBetweenTeams } = await (0, import_utils.validateOrSelectTeam)(ctx, config.team, "Team:");
let projectName = config.project || cwd;
let choseProjectInteractively = false;
if (!config.project) {
projectName = await (0, import_prompts.promptString)(ctx, {
message: "Project name:",
default: config.defaultProjectName || cwd
});
choseProjectInteractively = true;
}
const { devDeployment } = await (0, import_utils.selectDevDeploymentType)(ctx, {
chosenConfiguration,
newOrExisting: "new",
teamSlug: selectedTeam,
userHasChosenSomethingInteractively: didChooseBetweenTeams || choseProjectInteractively,
projectSlug: void 0,
devDeploymentFromFlag: config.devDeployment,
forceDevDeployment: config.local ? "local" : config.cloud ? "cloud" : void 0
});
(0, import_log.showSpinner)("Creating new Convex project...");
let projectSlug, teamSlug, projectsRemaining;
try {
({ projectSlug, teamSlug, projectsRemaining } = await (0, import_api.createProject)(ctx, {
teamSlug: selectedTeam,
projectName,
// We have to create some deployment initially for a project.
deploymentTypeToProvision: devDeployment === "local" ? "prod" : "dev"
}));
} catch (err) {
(0, import_log.logFailure)("Unable to create project.");
return await (0, import_utils.logAndHandleFetchError)(ctx, err);
}
const teamMessage = didChooseBetweenTeams ? " in team " + import_chalk.chalkStderr.bold(teamSlug) : "";
(0, import_log.logFinishedStep)(
`Created project ${import_chalk.chalkStderr.bold(
projectSlug
)}${teamMessage}, manage it at ${import_chalk.chalkStderr.bold(
(0, import_dashboard.projectDashboardUrl)(teamSlug, projectSlug)
)}`
);
if (projectsRemaining <= 2) {
(0, import_log.logWarning)(
import_chalk.chalkStderr.yellow.bold(
`Your account now has ${projectsRemaining} project${projectsRemaining === 1 ? "" : "s"} remaining.`
)
);
}
await (0, import_codegen.doInitConvexFolder)(ctx);
return { teamSlug, projectSlug, devDeployment };
}
async function selectExistingProject(ctx, chosenConfiguration, config) {
const { teamSlug, chosen } = await (0, import_utils.validateOrSelectTeam)(
ctx,
config.team,
"Team:"
);
const projectSlug = await (0, import_utils.validateOrSelectProject)(
ctx,
config.project,
teamSlug,
"Configure project",
"Project:"
);
if (projectSlug === null) {
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: "Run the command again to create a new project instead."
});
}
const { devDeployment } = await (0, import_utils.selectDevDeploymentType)(ctx, {
chosenConfiguration,
newOrExisting: "existing",
teamSlug,
projectSlug,
userHasChosenSomethingInteractively: chosen || !config.project,
devDeploymentFromFlag: config.devDeployment,
forceDevDeployment: config.local ? "local" : config.cloud ? "cloud" : void 0
});
(0, import_log.logFinishedStep)(`Reinitialized project ${import_chalk.chalkStderr.bold(projectSlug)}`);
return { teamSlug, projectSlug, devDeployment };
}
async function askToConfigure(ctx) {
if (!await (0, import_utils.hasProjects)(ctx)) {
return "new";
}
return await (0, import_prompts.promptOptions)(ctx, {
message: "What would you like to configure?",
default: "new",
choices: [
{ name: "create a new project", value: "new" },
{ name: "choose an existing project", value: "existing" }
]
});
}
async function ensureDeploymentProvisioned(ctx, options) {
switch (options.deploymentOptions.kind) {
case "dev":
case "prod": {
const credentials = await (0, import_api.fetchDeploymentCredentialsProvisioningDevOrProdMaybeThrows)(
ctx,
{
kind: "teamAndProjectSlugs",
teamSlug: options.teamSlug,
projectSlug: options.projectSlug
},
options.deploymentOptions.kind
);
return {
...credentials,
onActivity: null
};
}
case "local": {
const credentials = await (0, import_localDeployment.handleLocalDeployment)(ctx, {
teamSlug: options.teamSlug,
projectSlug: options.projectSlug,
...options.deploymentOptions
});
return credentials;
}
default:
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: `Invalid deployment type: ${options.deploymentOptions.kind}`,
errForSentry: `Invalid deployment type: ${options.deploymentOptions.kind}`
});
}
}
async function updateEnvAndConfigForDeploymentSelection(ctx, options, existingValue) {
const { configPath, projectConfig: existingProjectConfig } = await (0, import_config.readProjectConfig)(ctx);
const functionsPath = (0, import_utils.functionsDir)((0, import_config.configName)(), existingProjectConfig);
const { wroteToGitIgnore, changedDeploymentEnvVar } = await (0, import_deployment.writeDeploymentEnvVar)(
ctx,
options.deploymentType,
{
team: options.teamSlug,
project: options.projectSlug,
deploymentName: options.deploymentName
},
existingValue
);
const projectConfig = await (0, import_config.upgradeOldAuthInfoToAuthConfig)(
ctx,
existingProjectConfig,
functionsPath
);
await (0, import_config.writeProjectConfig)(ctx, projectConfig, {
deleteIfAllDefault: true
});
await (0, import_init.finalizeConfiguration)(ctx, {
deploymentType: options.deploymentType,
deploymentName: options.deploymentName,
url: options.url,
wroteToGitIgnore,
changedDeploymentEnvVar,
functionsPath: (0, import_utils.functionsDir)(configPath, projectConfig)
});
}
//# sourceMappingURL=configure.js.map