@zerodeploy/cli 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +44 -584
  2. package/dist/cli.js +155 -17
  3. package/package.json +1 -1
  4. package/dist/index.js +0 -6915
package/dist/cli.js CHANGED
@@ -4977,8 +4977,7 @@ var usageCommand = new Command2("usage").description("Show current usage and lim
4977
4977
  }
4978
4978
  console.log();
4979
4979
  console.log("Account Usage:");
4980
- console.log(formatUsageLine("Organizations", data.usage.orgs, data.limits.max_orgs));
4981
- console.log(formatUsageLine("Total Sites", data.usage.sites, data.limits.max_orgs * data.limits.max_sites_per_org));
4980
+ console.log(formatUsageLine("Total Sites", data.usage.sites, data.limits.max_sites_per_org));
4982
4981
  console.log(formatUsageLine("Deployments (month)", data.usage.deployments_this_month, data.limits.max_deployments_per_month));
4983
4982
  console.log();
4984
4983
  console.log("Limits:");
@@ -7086,7 +7085,7 @@ var deployPromoteCommand = new Command2("promote").description("Promote a previe
7086
7085
  });
7087
7086
 
7088
7087
  // src/lib/version.ts
7089
- var VERSION = "0.1.13";
7088
+ var VERSION = "0.1.15";
7090
7089
 
7091
7090
  // src/commands/deploy/index.ts
7092
7091
  function slugify(input) {
@@ -7544,6 +7543,7 @@ Error: Build failed`);
7544
7543
  body: JSON.stringify({ preview: isPreview, mode: options.append ? "append" : "replace" })
7545
7544
  }, {
7546
7545
  maxRetries: 3,
7546
+ timeoutMs: 120000,
7547
7547
  onRetry: (attempt, error, delayMs) => {
7548
7548
  finalizeSpinner.update(`Finalizing... ${formatRetryMessage(attempt, 3, error)}, retrying in ${Math.round(delayMs / 1000)}s`);
7549
7549
  }
@@ -7819,8 +7819,77 @@ var deploymentsShowCommand = new Command2("show").description("View deployment d
7819
7819
  }
7820
7820
  });
7821
7821
 
7822
+ // src/commands/deployments/logs.ts
7823
+ function colorLevel(level) {
7824
+ switch (level) {
7825
+ case "error":
7826
+ return `\x1B[31m${level}\x1B[0m`;
7827
+ case "warn":
7828
+ return `\x1B[33m${level}\x1B[0m`;
7829
+ case "info":
7830
+ return `\x1B[36m${level}\x1B[0m`;
7831
+ default:
7832
+ return level;
7833
+ }
7834
+ }
7835
+ function formatTime(timestamp) {
7836
+ const d = new Date(timestamp);
7837
+ return d.toLocaleTimeString(undefined, { hour12: false, fractionalSecondDigits: 3 });
7838
+ }
7839
+ var deploymentsLogsCommand = new Command2("logs").description("View deployment finalize logs").argument("<id>", "Deployment ID (full or short)").option("--json", "Output as JSON").action(async (id, options) => {
7840
+ const token = loadToken();
7841
+ if (!token) {
7842
+ handleAuthError();
7843
+ }
7844
+ try {
7845
+ const client = getClient(token);
7846
+ const res = await client.deployments[":id"].logs.$get({
7847
+ param: { id }
7848
+ });
7849
+ if (!res.ok) {
7850
+ if (res.status === 404) {
7851
+ displayError({
7852
+ code: "not_found",
7853
+ message: `Deployment not found: ${id}`,
7854
+ hint: "Use the full deployment ID or at least 8 characters."
7855
+ });
7856
+ process.exit(ExitCode.NOT_FOUND);
7857
+ }
7858
+ await handleApiError(res);
7859
+ }
7860
+ const { data: entries } = await res.json();
7861
+ if (options.json) {
7862
+ console.log(JSON.stringify(entries, null, 2));
7863
+ return;
7864
+ }
7865
+ if (entries.length === 0) {
7866
+ console.log("No logs available for this deployment.");
7867
+ console.log("Logs are only available for deployments created after this feature was enabled.");
7868
+ return;
7869
+ }
7870
+ console.log("Deployment Logs");
7871
+ console.log("=".repeat(60));
7872
+ console.log();
7873
+ for (const entry of entries) {
7874
+ const time = formatTime(entry.timestamp);
7875
+ const level = colorLevel(entry.level);
7876
+ const phase = `\x1B[90m[${entry.phase}]\x1B[0m`;
7877
+ const duration = entry.duration_ms !== undefined ? ` \x1B[90m(${entry.duration_ms}ms)\x1B[0m` : "";
7878
+ console.log(`${time} ${level} ${phase} ${entry.message}${duration}`);
7879
+ if (entry.metadata && Object.keys(entry.metadata).length > 0) {
7880
+ const meta = Object.entries(entry.metadata).map(([k, v]) => `${k}=${v}`).join(" ");
7881
+ console.log(` \x1B[90m${meta}\x1B[0m`);
7882
+ }
7883
+ }
7884
+ } catch (err) {
7885
+ const message = err instanceof Error ? err.message : String(err);
7886
+ displayError({ code: "network_error", message: `Failed to get deployment logs: ${message}` });
7887
+ process.exit(ExitCode.NETWORK_ERROR);
7888
+ }
7889
+ });
7890
+
7822
7891
  // src/commands/deployments/index.ts
7823
- var deploymentsCommand = new Command2("deployments").description("Manage deployments").addCommand(deploymentsListCommand).addCommand(deploymentsShowCommand);
7892
+ var deploymentsCommand = new Command2("deployments").description("Manage deployments").addCommand(deploymentsListCommand).addCommand(deploymentsShowCommand).addCommand(deploymentsLogsCommand);
7824
7893
 
7825
7894
  // src/commands/rollback.ts
7826
7895
  var rollbackCommand = new Command2("rollback").description("Rollback a site to a previous deployment").argument("<site>", "Site slug").requiredOption("--org <org>", "Organization slug").option("--to <deploymentId>", "Deployment ID to rollback to (defaults to previous deployment)").action(async (site, options) => {
@@ -8543,11 +8612,10 @@ function createInspectCommand(rootProgram) {
8543
8612
  });
8544
8613
  }
8545
8614
 
8546
- // src/lib/version.ts
8547
- var VERSION2 = "0.1.13";
8615
+ // src/commands/update.ts
8616
+ import { execSync } from "child_process";
8548
8617
 
8549
8618
  // src/lib/update-check.ts
8550
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
8551
8619
  import { homedir } from "os";
8552
8620
  import { join as join2 } from "path";
8553
8621
  var PACKAGE_NAME = "@zerodeploy/cli";
@@ -8566,11 +8634,80 @@ function compareVersions(current, latest) {
8566
8634
  }
8567
8635
  return 0;
8568
8636
  }
8637
+ async function fetchLatestVersion() {
8638
+ try {
8639
+ const controller = new AbortController;
8640
+ const timeout = setTimeout(() => controller.abort(), 3000);
8641
+ const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
8642
+ signal: controller.signal,
8643
+ headers: { Accept: "application/json" }
8644
+ });
8645
+ clearTimeout(timeout);
8646
+ if (!res.ok)
8647
+ return null;
8648
+ const data = await res.json();
8649
+ return data.version || null;
8650
+ } catch {
8651
+ return null;
8652
+ }
8653
+ }
8654
+
8655
+ // src/commands/update.ts
8656
+ var updateCommand = new Command2("update").description("Update ZeroDeploy CLI to the latest version").action(async () => {
8657
+ console.log(`Current version: ${VERSION}`);
8658
+ console.log("Checking for updates...");
8659
+ const latest = await fetchLatestVersion();
8660
+ if (!latest) {
8661
+ console.error("Failed to check for updates. Please try again later.");
8662
+ process.exit(6);
8663
+ }
8664
+ if (compareVersions(VERSION, latest) >= 0) {
8665
+ console.log(`Already up to date (${VERSION}).`);
8666
+ return;
8667
+ }
8668
+ console.log(`New version available: ${latest}`);
8669
+ console.log(`Updating...
8670
+ `);
8671
+ try {
8672
+ execSync("npm update -g @zerodeploy/cli", { stdio: "inherit" });
8673
+ console.log(`
8674
+ Updated to ${latest}.`);
8675
+ } catch {
8676
+ console.error(`
8677
+ Update failed. Try manually:`);
8678
+ console.error(" npm update -g @zerodeploy/cli");
8679
+ process.exit(1);
8680
+ }
8681
+ });
8682
+
8683
+ // src/lib/version.ts
8684
+ var VERSION2 = "0.1.15";
8685
+
8686
+ // src/lib/update-check.ts
8687
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
8688
+ import { homedir as homedir2 } from "os";
8689
+ import { join as join3 } from "path";
8690
+ var PACKAGE_NAME2 = "@zerodeploy/cli";
8691
+ var CACHE_FILE2 = join3(homedir2(), ".zerodeploy", "update-check.json");
8692
+ var CACHE_TTL_MS2 = 24 * 60 * 60 * 1000;
8693
+ function compareVersions2(current, latest) {
8694
+ const currentParts = current.split(".").map(Number);
8695
+ const latestParts = latest.split(".").map(Number);
8696
+ for (let i2 = 0;i2 < Math.max(currentParts.length, latestParts.length); i2++) {
8697
+ const a = currentParts[i2] || 0;
8698
+ const b = latestParts[i2] || 0;
8699
+ if (a < b)
8700
+ return -1;
8701
+ if (a > b)
8702
+ return 1;
8703
+ }
8704
+ return 0;
8705
+ }
8569
8706
  function readCache() {
8570
8707
  try {
8571
- if (!existsSync3(CACHE_FILE))
8708
+ if (!existsSync3(CACHE_FILE2))
8572
8709
  return null;
8573
- const data = JSON.parse(readFileSync2(CACHE_FILE, "utf-8"));
8710
+ const data = JSON.parse(readFileSync2(CACHE_FILE2, "utf-8"));
8574
8711
  if (typeof data.latestVersion !== "string" || typeof data.checkedAt !== "number") {
8575
8712
  return null;
8576
8713
  }
@@ -8581,18 +8718,18 @@ function readCache() {
8581
8718
  }
8582
8719
  function writeCache(cache) {
8583
8720
  try {
8584
- const dir = join2(homedir(), ".zerodeploy");
8721
+ const dir = join3(homedir2(), ".zerodeploy");
8585
8722
  if (!existsSync3(dir)) {
8586
8723
  mkdirSync(dir, { recursive: true });
8587
8724
  }
8588
- writeFileSync2(CACHE_FILE, JSON.stringify(cache), "utf-8");
8725
+ writeFileSync2(CACHE_FILE2, JSON.stringify(cache), "utf-8");
8589
8726
  } catch {}
8590
8727
  }
8591
- async function fetchLatestVersion() {
8728
+ async function fetchLatestVersion2() {
8592
8729
  try {
8593
8730
  const controller = new AbortController;
8594
8731
  const timeout = setTimeout(() => controller.abort(), 3000);
8595
- const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
8732
+ const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME2}/latest`, {
8596
8733
  signal: controller.signal,
8597
8734
  headers: { Accept: "application/json" }
8598
8735
  });
@@ -8613,10 +8750,10 @@ async function checkForUpdates() {
8613
8750
  const cache = readCache();
8614
8751
  const now = Date.now();
8615
8752
  let latestVersion = null;
8616
- if (cache && now - cache.checkedAt < CACHE_TTL_MS) {
8753
+ if (cache && now - cache.checkedAt < CACHE_TTL_MS2) {
8617
8754
  latestVersion = cache.latestVersion;
8618
8755
  } else {
8619
- latestVersion = await fetchLatestVersion();
8756
+ latestVersion = await fetchLatestVersion2();
8620
8757
  if (latestVersion) {
8621
8758
  writeCache({ latestVersion, checkedAt: now });
8622
8759
  } else if (cache) {
@@ -8625,14 +8762,14 @@ async function checkForUpdates() {
8625
8762
  }
8626
8763
  if (!latestVersion)
8627
8764
  return;
8628
- if (compareVersions(VERSION, latestVersion) < 0) {
8765
+ if (compareVersions2(VERSION, latestVersion) < 0) {
8629
8766
  printUpdateBanner(latestVersion);
8630
8767
  }
8631
8768
  } catch {}
8632
8769
  }
8633
8770
  function printUpdateBanner(latestVersion) {
8634
8771
  const message = `Update available: ${VERSION} → ${latestVersion}`;
8635
- const command = "Run `npm update -g @zerodeploy/cli` to update";
8772
+ const command = "Run `zerodeploy update` to update";
8636
8773
  const width = Math.max(message.length, command.length) + 4;
8637
8774
  const top = "╭" + "─".repeat(width) + "╮";
8638
8775
  const bottom = "╰" + "─".repeat(width) + "╯";
@@ -8662,6 +8799,7 @@ program3.addCommand(tokenCommand);
8662
8799
  program3.addCommand(billingCommand);
8663
8800
  program3.addCommand(initCommand);
8664
8801
  program3.addCommand(accountCommand);
8802
+ program3.addCommand(updateCommand);
8665
8803
  program3.addCommand(createInspectCommand(program3));
8666
8804
  await program3.parseAsync(process.argv);
8667
8805
  await checkForUpdates();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerodeploy/cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "zerodeploy": "dist/cli.js"