@get-dx/cli 0.6.0 → 0.6.1

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.
@@ -367,9 +367,9 @@ function studioReportToYaml(report) {
367
367
  description: report.description ?? "",
368
368
  markdown_notes: report.markdown_notes ?? "",
369
369
  view_access_type: report.view_access_type,
370
- viewer_emails: [],
370
+ viewer_emails: report.viewer_emails ?? [],
371
371
  edit_access_type: report.edit_access_type,
372
- editor_emails: [],
372
+ editor_emails: report.editor_emails ?? [],
373
373
  tiles: report.tiles.map((tile) => ({
374
374
  id: tile.id,
375
375
  title: tile.title,
package/dist/config.js CHANGED
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { CliError, EXIT_CODES } from "./errors.js";
5
- const DEFAULT_API_BASE_URL = "https://api.getdx.com";
5
+ export const DEFAULT_API_BASE_URL = "https://api.getdx.com";
6
6
  const DEFAULT_WEB_BASE_URL = "https://app.getdx.com";
7
7
  // --- Config file I/O ---------------------------------------------------------
8
8
  export function getConfigPath() {
@@ -14,7 +14,16 @@ export function readConfig() {
14
14
  return {};
15
15
  }
16
16
  const content = fs.readFileSync(configPath, "utf8");
17
- const raw = JSON.parse(content);
17
+ let raw;
18
+ try {
19
+ raw = JSON.parse(content);
20
+ }
21
+ catch {
22
+ // The config file can be left empty or truncated if a previous `dx`
23
+ // process was killed mid-write, or two processes wrote concurrently.
24
+ // Treat it like a missing config rather than crashing every command.
25
+ return {};
26
+ }
18
27
  const stored = {};
19
28
  if (typeof raw.webBaseUrl === "string") {
20
29
  stored.webBaseUrl = raw.webBaseUrl;
@@ -46,8 +55,15 @@ export function persistVersionPromptSelection(prompt) {
46
55
  writeConfig(config);
47
56
  }
48
57
  export function writeConfig(config) {
49
- fs.mkdirSync(getConfigDir(), { recursive: true });
50
- fs.writeFileSync(getConfigPath(), JSON.stringify(config, null, 2) + "\n", "utf8");
58
+ const configDir = getConfigDir();
59
+ fs.mkdirSync(configDir, { recursive: true });
60
+ const configPath = getConfigPath();
61
+ // Write to a temp file and rename into place so a crash or a race between
62
+ // concurrent `dx` processes can't leave config.json empty or truncated —
63
+ // renames are atomic, so readers always see either the old or new content.
64
+ const tempPath = path.join(configDir, `.config.json.${process.pid}.${Date.now()}.tmp`);
65
+ fs.writeFileSync(tempPath, JSON.stringify(config, null, 2) + "\n", "utf8");
66
+ fs.renameSync(tempPath, configPath);
51
67
  }
52
68
  export function persistBaseUrls(apiBaseUrl, webBaseUrl) {
53
69
  writeConfig({
@@ -49,7 +49,16 @@ export async function loginViaBrowser(webBaseUrl) {
49
49
  error: new CliError(`Authentication failed: token exchange failed with status ${tokenExchangeResponse.status}`),
50
50
  };
51
51
  }
52
- const body = (await tokenExchangeResponse.json());
52
+ let body;
53
+ try {
54
+ body = (await tokenExchangeResponse.json());
55
+ }
56
+ catch {
57
+ return {
58
+ type: "ERROR",
59
+ error: new CliError("Authentication failed: token exchange returned an invalid response"),
60
+ };
61
+ }
53
62
  return {
54
63
  type: "SUCCESS",
55
64
  token: body.access_token,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@get-dx/cli",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "DX CLI",
5
5
  "author": "DX <developers@getdx.com>",
6
6
  "bugs": {