convex
Version:
Client for the Convex Cloud
306 lines (305 loc) • 11.5 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 download_exports = {};
__export(download_exports, {
ensureBackendBinaryDownloaded: () => ensureBackendBinaryDownloaded,
ensureDashboardDownloaded: () => ensureDashboardDownloaded,
findLatestVersionWithBinary: () => findLatestVersionWithBinary
});
module.exports = __toCommonJS(download_exports);
var import_adm_zip = __toESM(require("adm-zip"), 1);
var import_context = require("../../../bundler/context.js");
var import_filePaths = require("./filePaths.js");
var import_child_process = __toESM(require("child_process"), 1);
var import_util = require("util");
var import_stream = require("stream");
var import_fs = require("../../../bundler/fs.js");
var import_fsUtils = require("../fsUtils.js");
var import_errors = require("./errors.js");
var import_path = __toESM(require("path"), 1);
async function makeExecutable(p) {
switch (process.platform) {
case "darwin":
case "linux": {
await (0, import_util.promisify)(import_child_process.default.exec)(`chmod +x ${p}`);
}
}
}
async function ensureBackendBinaryDownloaded(ctx, version) {
if (version.kind === "version") {
return _ensureBackendBinaryDownloaded(ctx, version.version);
}
const latestVersionWithBinary = await findLatestVersionWithBinary(ctx);
return _ensureBackendBinaryDownloaded(ctx, latestVersionWithBinary);
}
async function _ensureBackendBinaryDownloaded(ctx, version) {
(0, import_context.logVerbose)(ctx, `Ensuring backend binary downloaded for version ${version}`);
const existingDownload = await checkForExistingDownload(ctx, version);
if (existingDownload !== null) {
(0, import_context.logVerbose)(ctx, `Using existing download at ${existingDownload}`);
return {
binaryPath: existingDownload,
version
};
}
const binaryPath = await downloadBackendBinary(ctx, version);
return { version, binaryPath };
}
function parseLinkHeader(header) {
const links = {};
const parts = header.split(",");
for (const part of parts) {
const section = part.split(";");
if (section.length !== 2) {
continue;
}
const url = section[0].trim().slice(1, -1);
const rel = section[1].trim().slice(5, -1);
links[rel] = url;
}
return links;
}
async function findLatestVersionWithBinary(ctx) {
const targetName = getDownloadPath();
(0, import_context.logVerbose)(
ctx,
`Finding latest stable release containing binary named ${targetName}`
);
let latestVersion;
let nextUrl = "https://api.github.com/repos/get-convex/convex-backend/releases?per_page=30";
try {
while (nextUrl) {
const response = await fetch(nextUrl);
if (!response.ok) {
const text = await response.text();
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: `GitHub API returned ${response.status}: ${text}`,
errForSentry: new import_errors.LocalDeploymentError(
`GitHub API returned ${response.status}: ${text}`
)
});
}
const releases = await response.json();
if (releases.length === 0) {
break;
}
for (const release of releases) {
if (!latestVersion && !release.prerelease && !release.draft) {
latestVersion = release.tag_name;
(0, import_context.logVerbose)(ctx, `Latest stable version is ${latestVersion}`);
}
if (!release.prerelease && !release.draft) {
if (release.assets.find((asset) => asset.name === targetName)) {
(0, import_context.logVerbose)(
ctx,
`Latest stable version with appropriate binary is ${release.tag_name}`
);
return release.tag_name;
}
(0, import_context.logVerbose)(
ctx,
`Version ${release.tag_name} does not contain a ${targetName}, checking previous version`
);
}
}
const linkHeader = response.headers.get("Link");
if (!linkHeader) {
break;
}
const links = parseLinkHeader(linkHeader);
nextUrl = links["next"] || "";
}
if (!latestVersion) {
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: "Found no non-draft, non-prerelease convex backend releases.",
errForSentry: new import_errors.LocalDeploymentError(
"Found no non-draft, non-prerelease convex backend releases."
)
});
}
const message = `Failed to find a convex backend release that contained ${targetName}.`;
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: message,
errForSentry: new import_errors.LocalDeploymentError(message)
});
} catch (e) {
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: "Failed to get latest convex backend releases",
errForSentry: new import_errors.LocalDeploymentError(e?.toString())
});
}
}
async function checkForExistingDownload(ctx, version) {
const destDir = (0, import_filePaths.versionedBinaryDir)(version);
if (!ctx.fs.exists(destDir)) {
return null;
}
const p = (0, import_filePaths.executablePath)(version);
if (!ctx.fs.exists(p)) {
(0, import_fsUtils.recursivelyDelete)(ctx, destDir, { force: true });
return null;
}
await makeExecutable(p);
return p;
}
async function downloadBackendBinary(ctx, version) {
const downloadPath = getDownloadPath();
if (downloadPath === null) {
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: `Unsupported platform ${process.platform} and architecture ${process.arch} for local deployment.`
});
}
await downloadZipFile(ctx, {
version,
filename: downloadPath,
nameForLogging: "Convex backend binary",
onDownloadComplete: async (ctx2, unzippedPath) => {
const name = (0, import_filePaths.executableName)();
const tempExecPath = import_path.default.join(unzippedPath, name);
await makeExecutable(tempExecPath);
(0, import_context.logVerbose)(ctx2, "Marked as executable");
ctx2.fs.mkdir((0, import_filePaths.versionedBinaryDir)(version), { recursive: true });
ctx2.fs.swapTmpFile(tempExecPath, (0, import_filePaths.executablePath)(version));
}
});
return (0, import_filePaths.executablePath)(version);
}
function getDownloadPath() {
switch (process.platform) {
case "darwin":
if (process.arch === "arm64") {
return "convex-local-backend-aarch64-apple-darwin.zip";
} else if (process.arch === "x64") {
return "convex-local-backend-x86_64-apple-darwin.zip";
}
break;
case "linux":
if (process.arch === "arm64") {
return "convex-local-backend-aarch64-unknown-linux-gnu.zip";
} else if (process.arch === "x64") {
return "convex-local-backend-x86_64-unknown-linux-gnu.zip";
}
break;
case "win32":
return "convex-local-backend-x86_64-pc-windows-msvc.zip";
}
return null;
}
function getGithubDownloadUrl(version, filename) {
return `https://github.com/get-convex/convex-backend/releases/download/${version}/${filename}`;
}
async function downloadZipFile(ctx, args) {
const { version, filename, nameForLogging } = args;
const url = getGithubDownloadUrl(version, filename);
const response = await fetch(url);
const contentLength = parseInt(
response.headers.get("content-length") ?? "",
10
);
let progressBar = null;
if (!isNaN(contentLength) && contentLength !== 0 && process.stdout.isTTY) {
progressBar = (0, import_context.startLogProgress)(
ctx,
`Downloading ${nameForLogging} [:bar] :percent :etas`,
{
width: 40,
total: contentLength,
clear: true
}
);
} else {
(0, import_context.logMessage)(ctx, `Downloading ${nameForLogging}`);
}
if (response.status !== 200) {
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: `File not found at ${url}.`
});
}
await (0, import_fs.withTmpDir)(async (tmpDir) => {
(0, import_context.logVerbose)(ctx, `Created tmp dir ${tmpDir.path}`);
const zipLocation = tmpDir.registerTempPath(null);
const readable = import_stream.Readable.fromWeb(response.body);
await tmpDir.writeFileStream(zipLocation, readable, (chunk) => {
if (progressBar !== null) {
progressBar.tick(chunk.length);
}
});
if (progressBar) {
progressBar.terminate();
(0, import_context.logFinishedStep)(ctx, `Downloaded ${nameForLogging}`);
}
(0, import_context.logVerbose)(ctx, "Downloaded zip file");
const zip = new import_adm_zip.default(zipLocation);
await (0, import_fs.withTmpDir)(async (versionDir) => {
(0, import_context.logVerbose)(ctx, `Created tmp dir ${versionDir.path}`);
zip.extractAllTo(versionDir.path, true);
(0, import_context.logVerbose)(ctx, "Extracted from zip file");
await args.onDownloadComplete(ctx, versionDir.path);
});
});
return (0, import_filePaths.executablePath)(version);
}
async function ensureDashboardDownloaded(ctx, version) {
const config = (0, import_filePaths.loadDashboardConfig)(ctx);
if (config !== null && config.version === version) {
return;
}
await (0, import_filePaths.resetDashboardDir)(ctx);
await _ensureDashboardDownloaded(ctx, version);
}
async function _ensureDashboardDownloaded(ctx, version) {
const zipLocation = (0, import_filePaths.dashboardZip)();
if (ctx.fs.exists(zipLocation)) {
ctx.fs.unlink(zipLocation);
}
const outDir = (0, import_filePaths.dashboardOutDir)();
await downloadZipFile(ctx, {
version,
filename: "dashboard.zip",
nameForLogging: "Convex dashboard",
onDownloadComplete: async (ctx2, unzippedPath) => {
await (0, import_fsUtils.recursivelyCopy)(ctx2, import_fs.nodeFs, unzippedPath, outDir);
(0, import_context.logVerbose)(ctx2, "Copied into out dir");
}
});
return outDir;
}
//# sourceMappingURL=download.js.map