UNPKG

convex

Version:

Client for the Convex Cloud

447 lines (446 loc) 14.2 kB
"use strict"; 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( isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var utils_exports = {}; __export(utils_exports, { bigBrainAPI: () => bigBrainAPI, bigBrainClient: () => bigBrainClient, deprecationCheckWarning: () => deprecationCheckWarning, ensureHasConvexDependency: () => ensureHasConvexDependency, ensureProjectDirectory: () => ensureProjectDirectory, fatalServerErr: () => fatalServerErr, formatDuration: () => formatDuration, formatSize: () => formatSize, functionsDir: () => functionsDir, getAuthHeader: () => getAuthHeader, globalConfigPath: () => globalConfigPath, loadPackageJson: () => loadPackageJson, poll: () => poll, productionProvisionHost: () => productionProvisionHost, prompt: () => prompt, provisionHost: () => provisionHost, rootDirectory: () => rootDirectory, sorted: () => sorted, validateOrSelectProject: () => validateOrSelectProject, validateOrSelectTeam: () => validateOrSelectTeam }); module.exports = __toCommonJS(utils_exports); var import_axios = __toESM(require("axios")); var import_chalk = __toESM(require("chalk")); var import_inquirer = __toESM(require("inquirer")); var readline = __toESM(require("readline")); var import_path = __toESM(require("path")); var import_os = __toESM(require("os")); var import_zod = require("zod"); var import_config = require("./config.js"); var import_init = require("./init.js"); var import__ = require("../../index.js"); const productionProvisionHost = "https://provision.convex.dev"; const provisionHost = process.env.CONVEX_PROVISION_HOST || productionProvisionHost; const BIG_BRAIN_URL = `${provisionHost}/api/${import__.version}`; function prompt(query) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); return new Promise( (resolve) => rl.question(query, (answer) => { rl.close(); resolve(answer); }) ); } async function fatalServerErr(ctx, err) { if (ctx.spinner) { ctx.spinner.fail(); } const res = err.response; if (res) { await deprecationCheckError(ctx, res); console.error( import_chalk.default.gray( `${res.status} ${res.statusText}: ${res.data.code}: ${res.data.message}` ) ); if (res.status == 401) { console.error( import_chalk.default.red("Log in to get an access token with `npx convex login`.") ); } } else { console.error(import_chalk.default.gray(err)); } return await ctx.fatalError(1, "network", err); } async function deprecationCheckError(ctx, resp) { if (ctx.deprecationMessagePrinted) { return; } const headers = resp.headers; if (headers) { const deprecationState = headers["x-convex-deprecation-state"]; const deprecationMessage = headers["x-convex-deprecation-message"]; switch (deprecationState) { case void 0: break; case "Upgradable": console.log(import_chalk.default.yellow(deprecationMessage)); break; case "Deprecated": case "UpgradeCritical": console.log(import_chalk.default.red(deprecationMessage)); return await ctx.fatalError(1, "network"); default: console.log(deprecationMessage); break; } } ctx.deprecationMessagePrinted = true; } function deprecationCheckWarning(ctx, resp) { if (ctx.deprecationMessagePrinted) { return; } const headers = resp.headers; if (headers) { const deprecationState = headers["x-convex-deprecation-state"]; const deprecationMessage = headers["x-convex-deprecation-message"]; switch (deprecationState) { case void 0: break; case "Deprecated": case "UpgradeCritical": throw new Error( "Called deprecationCheckWarning on a fatal error. This is a bug." ); case "Upgradable": console.log(import_chalk.default.yellow(deprecationMessage)); break; default: console.log(deprecationMessage); break; } } ctx.deprecationMessagePrinted = true; } async function validateOrSelectTeam(ctx, teamSlug, promptMessage) { const teams = await bigBrainAPI(ctx, "GET", "teams"); if (teams.length == 0) { console.error(import_chalk.default.red("Error: No teams found")); throw new Error("No teams found"); } if (!teamSlug) { switch (teams.length) { case 1: return teams[0].slug; default: return (await import_inquirer.default.prompt([ { name: "teamSlug", message: promptMessage, type: "list", choices: teams.map((team) => ({ name: `${team.name} (${team.slug})`, value: team.slug })) } ])).teamSlug; } } else { if (!teams.find((team) => team.slug == teamSlug)) { console.error(import_chalk.default.red(`Error: Team ${teamSlug} not found`)); throw new Error("Team not found"); } return teamSlug; } } async function validateOrSelectProject(ctx, projectSlug, teamSlug, singleProjectPrompt, multiProjectPrompt) { const projects = await bigBrainAPI(ctx, "GET", `/teams/${teamSlug}/projects`); if (projects.length == 0) { console.error(import_chalk.default.red("Error: No projects found")); throw new Error("No projects found"); } if (!projectSlug) { switch (projects.length) { case 1: { console.log("Found 1 project."); const project = projects[0]; const confirmed = (await import_inquirer.default.prompt([ { type: "confirm", name: "confirmed", message: `${singleProjectPrompt} ${project.name} (${project.slug})?` } ])).confirmed; if (!confirmed) { return null; } return projects[0].slug; } default: console.log(`Found ${projects.length} projects.`); return (await import_inquirer.default.prompt([ { name: "project", message: multiProjectPrompt, type: "list", choices: projects.map((project) => ({ name: `${project.name} (${project.slug})`, value: project.slug })) } ])).project; } } else { if (!projects.find((project) => project.slug == projectSlug)) { console.error(import_chalk.default.red(`Error: Project ${projectSlug} not found`)); throw new Error("Project not found"); } return projectSlug; } } class PackageJsonLoadError extends Error { } async function loadPackageJson(ctx) { let packageJson; try { packageJson = ctx.fs.readUtf8File("package.json"); } catch (err) { console.error( import_chalk.default.red( `Unable to read your package.json: ${err}. Make sure you're running this command from the root directory of a Convex app that contains the package.json` ) ); return await ctx.fatalError(1, "fs"); } let obj; try { obj = JSON.parse(packageJson); } catch (err) { console.error(import_chalk.default.red(`Unable to parse package.json: ${err}`)); return await ctx.fatalError(1, "fs", err); } if (typeof obj !== "object") { throw new PackageJsonLoadError( "Expected to parse an object from package.json" ); } const packages = []; if (obj.dependencies) { for (const dep in obj.dependencies) { packages.push({ name: dep, version: obj.dependencies[dep] }); } } if (obj.devDependencies) { for (const dep in obj.devDependencies) { packages.push({ name: dep, version: obj.devDependencies[dep] }); } } return packages; } async function ensureHasConvexDependency(ctx, cmd) { const packages = await loadPackageJson(ctx); const hasConvexDependency = !!packages.filter(({ name }) => name === "convex").length; if (!hasConvexDependency) { console.error( import_chalk.default.red( `In order to ${cmd}, add \`convex\` to your package.json dependencies.` ) ); return await ctx.fatalError(1, "fs"); } } const sorted = (arr, key) => { const newArr = [...arr]; const cmp = (a, b) => { if (key(a) < key(b)) return -1; if (key(a) > key(b)) return 1; return 0; }; return newArr.sort(cmp); }; function functionsDir(configPath, projectConfig) { return import_path.default.join(import_path.default.dirname(configPath), projectConfig.functions); } function rootDirectory() { let dirName; if (process.env.CONVEX_PROVISION_HOST) { dirName = ".convex-test"; } else { dirName = ".convex"; } return import_path.default.join(import_os.default.homedir(), dirName); } function globalConfigPath() { return import_path.default.join(rootDirectory(), "config.json"); } async function readGlobalConfig(ctx) { const configPath = globalConfigPath(); let configFile; try { configFile = ctx.fs.readUtf8File(configPath); } catch (err) { return null; } try { const schema = import_zod.z.object({ accessToken: import_zod.z.string().min(1) }); const config = schema.parse(JSON.parse(configFile)); return config; } catch (err) { console.error( import_chalk.default.red( `Failed to parse global config in ${configPath} with error ${err}.` ) ); return null; } } async function getAuthHeader(ctx) { if (process.env.CONVEX_OVERRIDE_ACCESS_TOKEN) { return `Bearer ${process.env.CONVEX_OVERRIDE_ACCESS_TOKEN}`; } const globalConfig = await readGlobalConfig(ctx); if (globalConfig) { return `Bearer ${globalConfig.accessToken}`; } return null; } async function bigBrainClient(ctx) { const authHeader = await getAuthHeader(ctx); const headers = authHeader ? { Authorization: authHeader } : {}; return import_axios.default.create({ headers, baseURL: BIG_BRAIN_URL }); } async function bigBrainAPI(ctx, method, url, data) { let res; try { const client = await bigBrainClient(ctx); res = await client.request({ url, method, data }); deprecationCheckWarning(ctx, res); return res.data; } catch (err) { return await fatalServerErr(ctx, err); } } const poll = async function(fetch, condition, waitMs = 1e3) { let result = await fetch(); while (!condition(result)) { await wait(waitMs); result = await fetch(); } return result; }; const wait = function(waitMs) { return new Promise((resolve) => { setTimeout(resolve, waitMs); }); }; function formatSize(n) { if (n < 1024) { return `${n} B`; } if (n < 1024 * 1024) { return `${Math.floor(n / 1024)} KB`; } if (n < 1024 * 1024 * 1024) { return `${Math.floor(n / 1024 / 1024)} MB`; } return `${n} B`; } function formatDuration(ms) { const twoDigits = (n, unit) => `${n.toLocaleString("en-US", { maximumFractionDigits: 2 })}${unit}`; if (ms < 1e-3) { return twoDigits(ms * 1e9, "ns"); } if (ms < 1) { return twoDigits(ms * 1e3, "\xB5s"); } if (ms < 1e3) { return twoDigits(ms, "ms"); } const s = ms / 1e3; if (s < 60) { return twoDigits(ms / 1e3, "s"); } return twoDigits(s / 60, "m"); } function findParentConfigs(ctx) { const parentPackageJson = findUp(ctx, "package.json"); const candidateConvexJson = parentPackageJson && import_path.default.join(import_path.default.dirname(parentPackageJson), "convex.json"); const parentConvexJson = candidateConvexJson && ctx.fs.exists(candidateConvexJson) ? candidateConvexJson : void 0; return { parentPackageJson, parentConvexJson }; } function findUp(ctx, filename) { let curDir = import_path.default.resolve("."); let parentDir = curDir; do { const candidate = import_path.default.join(curDir, filename); if (ctx.fs.exists(candidate)) { return candidate; } curDir = parentDir; parentDir = import_path.default.dirname(curDir); } while (parentDir !== curDir); return; } async function ensureProjectDirectory(ctx, ensureConvexJson = false) { const { parentPackageJson, parentConvexJson } = findParentConfigs(ctx); if (!parentPackageJson) { console.error( "No package.json found. If you meant to create a new project, try" ); console.error(`npx create-next-app@latest -e convex my-convex-app`); await ctx.fatalError(1); } if (parentPackageJson !== import_path.default.resolve("package.json")) { console.error("Run this command from the root directory of a project."); return await ctx.fatalError(1, "fs"); } if (ensureConvexJson && parentPackageJson && !parentConvexJson) { const expected = await (0, import_config.configFilepath)(ctx); console.error(`No convex.json file found at ${expected}`); const { confirmed } = await import_inquirer.default.prompt([ { type: "confirm", name: "confirmed", message: `Would you like to create a new Convex project here? (\`npx convex init\`)` } ]); if (!confirmed) { console.error("Run `npx convex dev` in a directory with a convex.json."); return await ctx.fatalError(1, "fs"); } await (0, import_init.init)(ctx, null, null); } } //# sourceMappingURL=utils.js.map