UNPKG

convex

Version:

Client for the Convex Cloud

227 lines (226 loc) 8.57 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 dev_exports = {}; __export(dev_exports, { dev: () => dev }); module.exports = __toCommonJS(dev_exports); var import_boxen = __toESM(require("boxen")); var import_chalk = __toESM(require("chalk")); var import_commander = require("commander"); var import_http_proxy = __toESM(require("http-proxy")); var import_path = __toESM(require("path")); var import_perf_hooks = require("perf_hooks"); var import_clientConfig = require("./codegen_templates/clientConfig"); var import_api = require("./lib/api"); var import_config = require("./lib/config"); var import_context = require("./lib/context"); var import_login = require("./lib/login"); var import_push = require("./lib/push"); var import_utils = require("./lib/utils"); var import_watch = require("./lib/watch"); const dev = new import_commander.Command("dev").description( "Watch the local filesystem. When your Convex functions change, push them to your dev deployment and update generated code." ).option("-v, --verbose", "Show full listing of changes").addOption( new import_commander.Option( "--typecheck <mode>", `Check TypeScript files with \`tsc --noEmit\`.` ).choices(["enable", "try", "disable"]).default("try") ).addOption(new import_commander.Option("--trace-events").hideHelp()).addOption(new import_commander.Option("--once").hideHelp()).addOption(new import_commander.Option("--admin-key <adminKey>").hideHelp()).addOption(new import_commander.Option("--url <url>").hideHelp()).addOption( new import_commander.Option("--codegen <mode>", "Regenerate code in `convex/_generated/`").choices(["enable", "disable"]).default("enable") ).action(async (cmdOptions) => { const ctx = import_context.oneoffContext; if (!cmdOptions.url || !cmdOptions.adminKey) { if (!await (0, import_login.checkAuthorization)(ctx)) { await (0, import_login.performLogin)(ctx); } } await (0, import_utils.ensureProjectDirectory)(ctx, true); const config = await (0, import_config.readProjectConfig)(import_context.oneoffContext); const projectSlug = config.projectConfig.project; const teamSlug = config.projectConfig.team; let devDeployment; if (!cmdOptions.url || !cmdOptions.adminKey) { devDeployment = await (0, import_api.getDevDeployment)(import_context.oneoffContext, { projectSlug, teamSlug }); } const adminKey = cmdOptions.adminKey ?? devDeployment?.adminKey; const url = cmdOptions.url ?? devDeployment?.url; const options = { adminKey, verbose: !!cmdOptions.verbose, dryRun: false, typecheck: cmdOptions.typecheck, debug: false, codegen: cmdOptions.codegen === "enable", deploymentType: "dev", url }; let watcher; let numFailures = 0; import_http_proxy.default.createProxyServer({ target: url, ws: true, changeOrigin: true }).on("error", (err) => { console.log( `Network error connecting to dev deployment: ${err.message}` ); }).listen(import_clientConfig.LOCALHOST_PORT); const boxedText = import_chalk.default.whiteBright.bold("Personal dev deployment ready!") + import_chalk.default.white( "\n\nKeep this command running to sync Convex functions when they change." ); const boxenOptions = { align: "center", padding: 1, margin: 1, borderColor: "green", backgroundColor: "#555555" }; if (!cmdOptions.once) { console.log((0, import_boxen.default)(boxedText, boxenOptions)); } while (true) { console.log("Preparing Convex functions..."); const start = import_perf_hooks.performance.now(); const ctx2 = new import_watch.WatchContext(cmdOptions.traceEvents); const config2 = await (0, import_config.readProjectConfig)(ctx2); if (projectSlug !== config2.projectConfig.project || teamSlug !== config2.projectConfig.team) { console.log("Detected a change in your `convex.json`. Exiting..."); return await ctx2.fatalError(1, "fs"); } try { await (0, import_push.runPush)(ctx2, options); const end = import_perf_hooks.performance.now(); numFailures = 0; console.log( import_chalk.default.green( `Convex functions ready! (${(0, import_utils.formatDuration)(end - start)})` ) ); } catch (e) { if (!(e instanceof import_watch.FatalError) || !e.reason) { throw e; } if (e.reason === "network") { const delay = nextBackoff(numFailures); numFailures += 1; console.log( import_chalk.default.yellow( `Failed due to network error, retrying in ${(0, import_utils.formatDuration)( delay )}...` ) ); await new Promise((resolve) => setTimeout(resolve, delay)); continue; } console.assert(e.reason === "fs"); if (cmdOptions.once) { await ctx2.fatalError(1, "fs"); } } if (cmdOptions.once) { return; } const observations = ctx2.fs.finalize(); if (observations === "invalidated") { console.log("Filesystem changed during push, retrying..."); continue; } if (!watcher) { watcher = new import_watch.Watcher(observations); await watcher.ready(); } watcher.update(observations); let anyChanges = false; do { await watcher.waitForEvent(); for (const event of watcher.drainEvents()) { if (cmdOptions.traceEvents) { console.log( "Processing", event.name, import_path.default.relative("", event.absPath) ); } const result = observations.overlaps(event); if (result.overlaps) { const relPath = import_path.default.relative("", event.absPath); if (cmdOptions.traceEvents) { console.log(`${relPath} ${result.reason}, rebuilding...`); } anyChanges = true; break; } } } while (!anyChanges); let deadline = import_perf_hooks.performance.now() + quiescenceDelay; while (true) { const now = import_perf_hooks.performance.now(); if (now >= deadline) { break; } const remaining = deadline - now; if (cmdOptions.traceEvents) { console.log(`Waiting for ${(0, import_utils.formatDuration)(remaining)} to quiesce...`); } const remainingWait = new Promise( (resolve) => setTimeout(() => resolve("timeout"), deadline - now) ); const result = await Promise.race([ remainingWait, watcher.waitForEvent().then(() => "newEvents") ]); if (result === "newEvents") { for (const event of watcher.drainEvents()) { const result2 = observations.overlaps(event); if (result2.overlaps) { if (cmdOptions.traceEvents) { console.log( `Received an overlapping event at ${event.absPath}, delaying push.` ); } deadline = import_perf_hooks.performance.now() + quiescenceDelay; } } } else { console.assert(result === "timeout"); } } } }); const initialBackoff = 500; const maxBackoff = 16e3; const quiescenceDelay = 500; function nextBackoff(prevFailures) { const baseBackoff = initialBackoff * Math.pow(2, prevFailures); const actualBackoff = Math.min(baseBackoff, maxBackoff); const jitter = actualBackoff * (Math.random() - 0.5); return actualBackoff + jitter; } //# sourceMappingURL=dev.js.map