@devicecloud.dev/dcd 5.0.0-beta.0 → 5.0.0-beta.2

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 (104) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +52 -0
  3. package/dist/commands/artifacts.d.ts +28 -28
  4. package/dist/commands/artifacts.js +20 -23
  5. package/dist/commands/cloud.d.ts +57 -57
  6. package/dist/commands/cloud.js +224 -192
  7. package/dist/commands/list.d.ts +22 -22
  8. package/dist/commands/list.js +43 -40
  9. package/dist/commands/live.js +134 -127
  10. package/dist/commands/login.d.ts +11 -11
  11. package/dist/commands/login.js +46 -44
  12. package/dist/commands/logout.js +16 -18
  13. package/dist/commands/status.d.ts +11 -11
  14. package/dist/commands/status.js +53 -44
  15. package/dist/commands/switch-org.d.ts +7 -7
  16. package/dist/commands/switch-org.js +19 -21
  17. package/dist/commands/upgrade.js +41 -33
  18. package/dist/commands/upload.d.ts +10 -10
  19. package/dist/commands/upload.js +42 -43
  20. package/dist/commands/whoami.js +17 -20
  21. package/dist/config/environments.js +6 -12
  22. package/dist/config/flags/api.flags.js +1 -4
  23. package/dist/config/flags/binary.flags.js +1 -4
  24. package/dist/config/flags/device.flags.js +6 -9
  25. package/dist/config/flags/environment.flags.js +1 -4
  26. package/dist/config/flags/execution.flags.js +1 -4
  27. package/dist/config/flags/github.flags.js +1 -4
  28. package/dist/config/flags/output.flags.js +1 -4
  29. package/dist/constants.js +15 -18
  30. package/dist/gateways/api-gateway.d.ts +31 -6
  31. package/dist/gateways/api-gateway.js +70 -16
  32. package/dist/gateways/cli-auth-gateway.d.ts +1 -1
  33. package/dist/gateways/cli-auth-gateway.js +3 -6
  34. package/dist/gateways/realtime-gateway.d.ts +32 -0
  35. package/dist/gateways/realtime-gateway.js +103 -0
  36. package/dist/gateways/supabase-gateway.d.ts +1 -1
  37. package/dist/gateways/supabase-gateway.js +10 -14
  38. package/dist/index.js +41 -38
  39. package/dist/mcp/context.d.ts +33 -0
  40. package/dist/mcp/context.js +33 -0
  41. package/dist/mcp/helpers.d.ts +16 -0
  42. package/dist/mcp/helpers.js +34 -0
  43. package/dist/mcp/index.d.ts +2 -0
  44. package/dist/mcp/index.js +24 -0
  45. package/dist/mcp/server.d.ts +7 -0
  46. package/dist/mcp/server.js +27 -0
  47. package/dist/mcp/tools/download-artifacts.d.ts +11 -0
  48. package/dist/mcp/tools/download-artifacts.js +84 -0
  49. package/dist/mcp/tools/get-status.d.ts +7 -0
  50. package/dist/mcp/tools/get-status.js +39 -0
  51. package/dist/mcp/tools/list-devices.d.ts +7 -0
  52. package/dist/mcp/tools/list-devices.js +27 -0
  53. package/dist/mcp/tools/list-runs.d.ts +3 -0
  54. package/dist/mcp/tools/list-runs.js +60 -0
  55. package/dist/mcp/tools/run-cloud-test.d.ts +14 -0
  56. package/dist/mcp/tools/run-cloud-test.js +233 -0
  57. package/dist/methods.d.ts +32 -1
  58. package/dist/methods.js +133 -79
  59. package/dist/services/device-validation.service.d.ts +1 -1
  60. package/dist/services/device-validation.service.js +1 -5
  61. package/dist/services/execution-plan.service.js +14 -17
  62. package/dist/services/execution-plan.utils.js +15 -23
  63. package/dist/services/flow-paths.d.ts +17 -0
  64. package/dist/services/flow-paths.js +52 -0
  65. package/dist/services/metadata-extractor.service.js +22 -25
  66. package/dist/services/moropo.service.js +18 -20
  67. package/dist/services/report-download.service.d.ts +1 -1
  68. package/dist/services/report-download.service.js +5 -9
  69. package/dist/services/results-polling.service.d.ts +18 -3
  70. package/dist/services/results-polling.service.js +211 -108
  71. package/dist/services/telemetry.service.d.ts +10 -1
  72. package/dist/services/telemetry.service.js +40 -18
  73. package/dist/services/test-submission.service.d.ts +21 -4
  74. package/dist/services/test-submission.service.js +51 -34
  75. package/dist/services/version.service.d.ts +30 -7
  76. package/dist/services/version.service.js +88 -32
  77. package/dist/types/domain/auth.types.d.ts +8 -0
  78. package/dist/types/domain/auth.types.js +1 -2
  79. package/dist/types/domain/device.types.js +8 -11
  80. package/dist/types/domain/live.types.js +1 -2
  81. package/dist/types/generated/schema.types.js +1 -2
  82. package/dist/types/index.d.ts +2 -2
  83. package/dist/types/index.js +2 -18
  84. package/dist/types.js +1 -2
  85. package/dist/utils/auth.d.ts +1 -1
  86. package/dist/utils/auth.js +27 -28
  87. package/dist/utils/ci.d.ts +12 -0
  88. package/dist/utils/ci.js +39 -0
  89. package/dist/utils/cli.d.ts +16 -2
  90. package/dist/utils/cli.js +57 -29
  91. package/dist/utils/compatibility.d.ts +1 -1
  92. package/dist/utils/compatibility.js +5 -7
  93. package/dist/utils/config-store.js +33 -43
  94. package/dist/utils/connectivity.js +1 -4
  95. package/dist/utils/expo.js +15 -21
  96. package/dist/utils/orgs.js +8 -12
  97. package/dist/utils/paths.js +2 -5
  98. package/dist/utils/progress.d.ts +3 -0
  99. package/dist/utils/progress.js +47 -8
  100. package/dist/utils/styling.d.ts +35 -37
  101. package/dist/utils/styling.js +52 -86
  102. package/dist/utils/ui.d.ts +41 -0
  103. package/dist/utils/ui.js +95 -0
  104. package/package.json +27 -24
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Best-effort detection of non-interactive / CI environments. Used to suppress
3
+ * interactive niceties (e.g. the `dcd login` nudge) that only make sense for a
4
+ * human at a terminal. Dependency-free on purpose — these are the env vars the
5
+ * major providers set, plus a TTY check for piped/redirected output.
6
+ */
7
+ /**
8
+ * Returns true when running under CI or otherwise non-interactively (no TTY on
9
+ * stdout, e.g. output piped to a file). A truthy value for any known CI env var
10
+ * counts — providers set `CI=true`, but a bare presence check is the safe net.
11
+ */
12
+ export declare function isCI(): boolean;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Best-effort detection of non-interactive / CI environments. Used to suppress
3
+ * interactive niceties (e.g. the `dcd login` nudge) that only make sense for a
4
+ * human at a terminal. Dependency-free on purpose — these are the env vars the
5
+ * major providers set, plus a TTY check for piped/redirected output.
6
+ */
7
+ // Generic + per-provider markers. `CI` is set by virtually every provider;
8
+ // the rest cover platforms that historically didn't set it.
9
+ const CI_ENV_VARS = [
10
+ 'CI',
11
+ 'CONTINUOUS_INTEGRATION',
12
+ 'BUILD_NUMBER',
13
+ 'GITHUB_ACTIONS',
14
+ 'GITLAB_CI',
15
+ 'CIRCLECI',
16
+ 'TRAVIS',
17
+ 'BUILDKITE',
18
+ 'DRONE',
19
+ 'TEAMCITY_VERSION',
20
+ 'TF_BUILD', // Azure Pipelines
21
+ 'JENKINS_URL',
22
+ 'BITBUCKET_BUILD_NUMBER',
23
+ 'APPVEYOR',
24
+ 'CODEBUILD_BUILD_ID',
25
+ ];
26
+ /**
27
+ * Returns true when running under CI or otherwise non-interactively (no TTY on
28
+ * stdout, e.g. output piped to a file). A truthy value for any known CI env var
29
+ * counts — providers set `CI=true`, but a bare presence check is the safe net.
30
+ */
31
+ export function isCI() {
32
+ for (const name of CI_ENV_VARS) {
33
+ const value = process.env[name];
34
+ if (value !== undefined && value !== '' && value !== 'false' && value !== '0') {
35
+ return true;
36
+ }
37
+ }
38
+ return !process.stdout.isTTY;
39
+ }
@@ -24,10 +24,24 @@ export declare function validateEnum<T extends string>(value: string | undefined
24
24
  /**
25
25
  * Coerce a flag value (possibly a single string, array, or undefined) into a
26
26
  * flat string array. Comma-separated values inside each entry are split out.
27
- * Used for repeatable flags like --include-tags, --env, --metadata where citty
28
- * surfaces a string (single use) or string[] (repeated).
27
+ * Pair with {@link collectRepeatedFlag} for repeatable flags.
29
28
  */
30
29
  export declare function coerceArray(value: string | string[] | undefined, split?: boolean): string[];
30
+ /**
31
+ * Collect every occurrence of a repeatable flag from raw argv, in order.
32
+ *
33
+ * citty 0.2.2 delegates to Node's `parseArgs`, which — without `multiple: true`
34
+ * (unsupported by citty's ArgsDef) — keeps only the LAST value of a repeated
35
+ * `type: 'string'` flag. So `-e A=1 -e B=2` collapses to just `B=2`. We recover
36
+ * all occurrences by scanning rawArgs ourselves (same approach as
37
+ * `recoverFlagValue` in commands/live.ts).
38
+ *
39
+ * `names` lists every spelling of one logical flag, e.g. ['--env', '-e'].
40
+ * Handles both `--flag value` (consuming the next token, so values starting
41
+ * with `-` survive) and `--flag=value`. Feed the result through
42
+ * {@link coerceArray} for comma-splitting where appropriate.
43
+ */
44
+ export declare function collectRepeatedFlag(rawArgs: string[], names: string[]): string[];
31
45
  /**
32
46
  * Parse an integer flag. Returns undefined if the value is undefined/empty.
33
47
  * Throws CliError if the value is not a valid integer.
package/dist/utils/cli.js CHANGED
@@ -1,12 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.logger = exports.CliError = void 0;
4
- exports.getCliVersion = getCliVersion;
5
- exports.getInstallMethod = getInstallMethod;
6
- exports.getUpgradeCommand = getUpgradeCommand;
7
- exports.validateEnum = validateEnum;
8
- exports.coerceArray = coerceArray;
9
- exports.parseIntFlag = parseIntFlag;
10
1
  /**
11
2
  * Shared helpers for command files.
12
3
  * - Version lookup from package.json
@@ -15,13 +6,22 @@ exports.parseIntFlag = parseIntFlag;
15
6
  * - A minimal Logger mirroring the oclif Command log/warn/error shape so call
16
7
  * sites ported from oclif keep working.
17
8
  */
18
- const telemetry_service_1 = require("../services/telemetry.service");
19
- const styling_1 = require("./styling");
20
- // Resolve version at runtime — avoids pulling package.json into the tsbuildinfo rootDir.
21
- function getCliVersion() {
9
+ import { readFileSync } from 'node:fs';
10
+ import { telemetry } from '../services/telemetry.service.js';
11
+ import { symbols } from './styling.js';
12
+ // Resolve version at runtime. The bun-compiled binary can't read package.json
13
+ // off disk (it isn't bundled next to the embedded module), so the build stamps
14
+ // the version in via `bun --define __DCD_CLI_VERSION__` (see
15
+ // scripts/build-binaries.mjs). Prefer that constant; on the npm/tsx path the
16
+ // identifier was never defined, so `typeof` is 'undefined' (no ReferenceError)
17
+ // and we fall back to reading package.json.
18
+ export function getCliVersion() {
19
+ if (typeof __DCD_CLI_VERSION__ === 'string' &&
20
+ __DCD_CLI_VERSION__.length > 0) {
21
+ return __DCD_CLI_VERSION__;
22
+ }
22
23
  try {
23
- // eslint-disable-next-line @typescript-eslint/no-var-requires
24
- const pkg = require('../../package.json');
24
+ const pkg = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
25
25
  return pkg.version;
26
26
  }
27
27
  catch {
@@ -30,17 +30,17 @@ function getCliVersion() {
30
30
  }
31
31
  // The Bun runtime sets process.versions.bun; bun-compiled standalone binaries
32
32
  // inherit this. Node-run installs (npm/pnpm/npx/tsx) don't expose it.
33
- function getInstallMethod() {
33
+ export function getInstallMethod() {
34
34
  return typeof process.versions.bun === 'string'
35
35
  ? 'binary'
36
36
  : 'npm';
37
37
  }
38
- function getUpgradeCommand() {
38
+ export function getUpgradeCommand() {
39
39
  return getInstallMethod() === 'binary'
40
40
  ? 'dcd upgrade'
41
41
  : 'npm install -g @devicecloud.dev/dcd@latest';
42
42
  }
43
- class CliError extends Error {
43
+ export class CliError extends Error {
44
44
  exitCode;
45
45
  constructor(message, exitCode = 1) {
46
46
  super(message);
@@ -48,15 +48,14 @@ class CliError extends Error {
48
48
  this.name = 'CliError';
49
49
  }
50
50
  }
51
- exports.CliError = CliError;
52
- exports.logger = {
51
+ export const logger = {
53
52
  log(message) {
54
53
  // eslint-disable-next-line no-console
55
54
  console.log(message);
56
55
  },
57
56
  warn(message) {
58
57
  // eslint-disable-next-line no-console
59
- console.warn(styling_1.symbols.warning + ' ' + message);
58
+ console.warn(symbols.warning + ' ' + message);
60
59
  },
61
60
  error(message, opts = {}) {
62
61
  const text = message instanceof Error ? message.message : message;
@@ -70,14 +69,14 @@ exports.logger = {
70
69
  // The literal "Error:" prefix is important for tests and for grep-friendly
71
70
  // CI logs — it survives color stripping and matches /error/i assertions.
72
71
  // eslint-disable-next-line no-console
73
- console.error(styling_1.symbols.error + ' Error: ' + text);
72
+ console.error(symbols.error + ' Error: ' + text);
74
73
  }
75
74
  // process.exit bypasses beforeExit, so async fetch in telemetry.flush()
76
75
  // would be killed mid-flight. flushSync uses curl to ship synchronously
77
76
  // before we exit; it's a no-op if telemetry never reached configure().
78
77
  const exitCode = opts.exit ?? 1;
79
- telemetry_service_1.telemetry.recordCommandFailure({ error: message, exitCode });
80
- telemetry_service_1.telemetry.flushSync();
78
+ telemetry.recordCommandFailure({ error: message, exitCode });
79
+ telemetry.flushSync();
81
80
  process.exit(exitCode);
82
81
  },
83
82
  exit(code = 0) {
@@ -88,7 +87,7 @@ exports.logger = {
88
87
  * Validate that a string flag value is one of the allowed options.
89
88
  * Returns the value untouched on success; throws CliError otherwise.
90
89
  */
91
- function validateEnum(value, allowed, flagName) {
90
+ export function validateEnum(value, allowed, flagName) {
92
91
  if (value === undefined || value === null || value === '')
93
92
  return undefined;
94
93
  if (!allowed.includes(value)) {
@@ -99,10 +98,9 @@ function validateEnum(value, allowed, flagName) {
99
98
  /**
100
99
  * Coerce a flag value (possibly a single string, array, or undefined) into a
101
100
  * flat string array. Comma-separated values inside each entry are split out.
102
- * Used for repeatable flags like --include-tags, --env, --metadata where citty
103
- * surfaces a string (single use) or string[] (repeated).
101
+ * Pair with {@link collectRepeatedFlag} for repeatable flags.
104
102
  */
105
- function coerceArray(value, split = true) {
103
+ export function coerceArray(value, split = true) {
106
104
  if (value === undefined)
107
105
  return [];
108
106
  const arr = Array.isArray(value) ? value : [value];
@@ -110,11 +108,41 @@ function coerceArray(value, split = true) {
110
108
  return arr;
111
109
  return arr.flatMap((v) => v.split(','));
112
110
  }
111
+ /**
112
+ * Collect every occurrence of a repeatable flag from raw argv, in order.
113
+ *
114
+ * citty 0.2.2 delegates to Node's `parseArgs`, which — without `multiple: true`
115
+ * (unsupported by citty's ArgsDef) — keeps only the LAST value of a repeated
116
+ * `type: 'string'` flag. So `-e A=1 -e B=2` collapses to just `B=2`. We recover
117
+ * all occurrences by scanning rawArgs ourselves (same approach as
118
+ * `recoverFlagValue` in commands/live.ts).
119
+ *
120
+ * `names` lists every spelling of one logical flag, e.g. ['--env', '-e'].
121
+ * Handles both `--flag value` (consuming the next token, so values starting
122
+ * with `-` survive) and `--flag=value`. Feed the result through
123
+ * {@link coerceArray} for comma-splitting where appropriate.
124
+ */
125
+ export function collectRepeatedFlag(rawArgs, names) {
126
+ const out = [];
127
+ for (let i = 0; i < rawArgs.length; i++) {
128
+ const arg = rawArgs[i];
129
+ const eqName = names.find((n) => arg.startsWith(`${n}=`));
130
+ if (eqName) {
131
+ out.push(arg.slice(eqName.length + 1));
132
+ continue;
133
+ }
134
+ if (names.includes(arg) && i + 1 < rawArgs.length) {
135
+ out.push(rawArgs[i + 1]);
136
+ i++; // consume the value so a leading-dash value isn't re-read as a flag
137
+ }
138
+ }
139
+ return out;
140
+ }
113
141
  /**
114
142
  * Parse an integer flag. Returns undefined if the value is undefined/empty.
115
143
  * Throws CliError if the value is not a valid integer.
116
144
  */
117
- function parseIntFlag(value, flagName) {
145
+ export function parseIntFlag(value, flagName) {
118
146
  if (value === undefined || value === null || value === '')
119
147
  return undefined;
120
148
  // All integer flags (limit/offset/retry) are non-negative; also rejects
@@ -1,4 +1,4 @@
1
- import type { AuthContext } from '../types/domain/auth.types';
1
+ import type { AuthContext } from '../types/domain/auth.types.js';
2
2
  export interface CompatibilityData {
3
3
  android: Record<string, string[]>;
4
4
  androidPlay: Record<string, string[]>;
@@ -1,9 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fetchCompatibilityData = fetchCompatibilityData;
4
- exports.clearCompatibilityCache = clearCompatibilityCache;
5
1
  let cachedCompatibilityData = null;
6
- async function fetchCompatibilityData(apiUrl, auth) {
2
+ export async function fetchCompatibilityData(apiUrl, auth) {
7
3
  if (cachedCompatibilityData) {
8
4
  return cachedCompatibilityData;
9
5
  }
@@ -27,9 +23,11 @@ async function fetchCompatibilityData(apiUrl, auth) {
27
23
  }
28
24
  catch (error) {
29
25
  const errorMessage = error instanceof Error ? error.message : String(error);
30
- throw new Error(`Failed to fetch compatibility data from API: ${errorMessage}`);
26
+ throw new Error(`Failed to fetch compatibility data from API: ${errorMessage}`, {
27
+ cause: error,
28
+ });
31
29
  }
32
30
  }
33
- function clearCompatibilityCache() {
31
+ export function clearCompatibilityCache() {
34
32
  cachedCompatibilityData = null;
35
33
  }
@@ -1,13 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CONFIG_SCHEMA_VERSION = void 0;
4
- exports.getConfigDir = getConfigDir;
5
- exports.getConfigPath = getConfigPath;
6
- exports.readConfig = readConfig;
7
- exports.resolveApiUrl = resolveApiUrl;
8
- exports.writeConfig = writeConfig;
9
- exports.clearConfig = clearConfig;
10
- exports.configFileMode = configFileMode;
11
1
  /**
12
2
  * Persistent CLI config: Supabase session tokens + chosen org.
13
3
  *
@@ -16,31 +6,31 @@ exports.configFileMode = configFileMode;
16
6
  * Writes are atomic (tmp file + rename) so a crash mid-refresh can't
17
7
  * leave a corrupt config behind that logs the user out.
18
8
  */
19
- const node_crypto_1 = require("node:crypto");
20
- const node_fs_1 = require("node:fs");
21
- const node_os_1 = require("node:os");
22
- const path = require("node:path");
23
- const environments_1 = require("../config/environments");
24
- exports.CONFIG_SCHEMA_VERSION = 1;
25
- function getConfigDir() {
9
+ import { randomBytes } from 'node:crypto';
10
+ import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync, } from 'node:fs';
11
+ import { homedir } from 'node:os';
12
+ import * as path from 'node:path';
13
+ import { ENVIRONMENTS } from '../config/environments.js';
14
+ export const CONFIG_SCHEMA_VERSION = 1;
15
+ export function getConfigDir() {
26
16
  if (process.env.DCD_CONFIG_DIR)
27
17
  return process.env.DCD_CONFIG_DIR;
28
18
  const xdg = process.env.XDG_CONFIG_HOME;
29
19
  if (xdg && xdg.trim().length > 0)
30
20
  return path.join(xdg, 'dcd');
31
- return path.join((0, node_os_1.homedir)(), '.dcd');
21
+ return path.join(homedir(), '.dcd');
32
22
  }
33
- function getConfigPath() {
23
+ export function getConfigPath() {
34
24
  return path.join(getConfigDir(), 'config.json');
35
25
  }
36
- function readConfig() {
26
+ export function readConfig() {
37
27
  const p = getConfigPath();
38
- if (!(0, node_fs_1.existsSync)(p))
28
+ if (!existsSync(p))
39
29
  return null;
40
30
  try {
41
- const raw = (0, node_fs_1.readFileSync)(p, 'utf8');
31
+ const raw = readFileSync(p, 'utf8');
42
32
  const parsed = JSON.parse(raw);
43
- if (parsed.version !== exports.CONFIG_SCHEMA_VERSION) {
33
+ if (parsed.version !== CONFIG_SCHEMA_VERSION) {
44
34
  // eslint-disable-next-line no-console
45
35
  console.warn(`Warning: config at ${p} was written by an incompatible CLI version (config version ${parsed.version}); ignoring it. Run \`dcd login\` to recreate it.`);
46
36
  return null;
@@ -65,20 +55,20 @@ function readConfig() {
65
55
  * token is rejected with a misleading "Invalid or expired JWT". `switch-org`
66
56
  * has always done this; this helper extends it to every command.
67
57
  */
68
- function resolveApiUrl(flag) {
58
+ export function resolveApiUrl(flag) {
69
59
  const explicit = flag?.trim();
70
60
  if (explicit)
71
61
  return explicit;
72
- return readConfig()?.api_url ?? environments_1.ENVIRONMENTS.prod.apiUrl;
62
+ return readConfig()?.api_url ?? ENVIRONMENTS.prod.apiUrl;
73
63
  }
74
- function writeConfig(config) {
64
+ export function writeConfig(config) {
75
65
  const dir = getConfigDir();
76
- if (!(0, node_fs_1.existsSync)(dir)) {
77
- (0, node_fs_1.mkdirSync)(dir, { recursive: true, mode: 0o700 });
66
+ if (!existsSync(dir)) {
67
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
78
68
  }
79
69
  else {
80
70
  try {
81
- (0, node_fs_1.chmodSync)(dir, 0o700);
71
+ chmodSync(dir, 0o700);
82
72
  }
83
73
  catch { /* best effort */ }
84
74
  }
@@ -88,38 +78,38 @@ function writeConfig(config) {
88
78
  // writeFileSync and renameSync right now.
89
79
  try {
90
80
  const base = path.basename(finalPath);
91
- for (const entry of (0, node_fs_1.readdirSync)(dir)) {
81
+ for (const entry of readdirSync(dir)) {
92
82
  if (!entry.startsWith(`${base}.`) || !entry.endsWith('.tmp'))
93
83
  continue;
94
84
  const tmp = path.join(dir, entry);
95
85
  try {
96
- if (Date.now() - (0, node_fs_1.statSync)(tmp).mtimeMs > 60_000)
97
- (0, node_fs_1.unlinkSync)(tmp);
86
+ if (Date.now() - statSync(tmp).mtimeMs > 60_000)
87
+ unlinkSync(tmp);
98
88
  }
99
89
  catch { /* best effort */ }
100
90
  }
101
91
  }
102
92
  catch { /* best effort */ }
103
- const tmpPath = `${finalPath}.${(0, node_crypto_1.randomBytes)(6).toString('hex')}.tmp`;
104
- (0, node_fs_1.writeFileSync)(tmpPath, JSON.stringify(config, null, 2), { mode: 0o600 });
93
+ const tmpPath = `${finalPath}.${randomBytes(6).toString('hex')}.tmp`;
94
+ writeFileSync(tmpPath, JSON.stringify(config, null, 2), { mode: 0o600 });
105
95
  try {
106
- (0, node_fs_1.chmodSync)(tmpPath, 0o600);
96
+ chmodSync(tmpPath, 0o600);
107
97
  }
108
98
  catch { /* best effort on platforms w/o chmod */ }
109
- (0, node_fs_1.renameSync)(tmpPath, finalPath);
99
+ renameSync(tmpPath, finalPath);
110
100
  try {
111
- (0, node_fs_1.chmodSync)(finalPath, 0o600);
101
+ chmodSync(finalPath, 0o600);
112
102
  }
113
103
  catch { /* best effort */ }
114
104
  }
115
- function clearConfig() {
105
+ export function clearConfig() {
116
106
  const p = getConfigPath();
117
- if ((0, node_fs_1.existsSync)(p))
118
- (0, node_fs_1.unlinkSync)(p);
107
+ if (existsSync(p))
108
+ unlinkSync(p);
119
109
  }
120
- function configFileMode() {
110
+ export function configFileMode() {
121
111
  const p = getConfigPath();
122
- if (!(0, node_fs_1.existsSync)(p))
112
+ if (!existsSync(p))
123
113
  return null;
124
- return (0, node_fs_1.statSync)(p).mode & 0o777;
114
+ return statSync(p).mode & 0o777;
125
115
  }
@@ -1,16 +1,13 @@
1
- "use strict";
2
1
  /**
3
2
  * Utility for checking internet connectivity using third-party endpoints
4
3
  */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.checkInternetConnectivity = checkInternetConnectivity;
7
4
  /**
8
5
  * Check if the system has internet connectivity by testing against
9
6
  * multiple reliable third-party endpoints with detailed diagnostics.
10
7
  *
11
8
  * @returns Promise<ConnectivityCheckResult> - Detailed connectivity check results
12
9
  */
13
- async function checkInternetConnectivity() {
10
+ export async function checkInternetConnectivity() {
14
11
  // Use multiple reliable endpoints to test connectivity
15
12
  const testEndpoints = [
16
13
  { url: 'https://www.google.com/generate_204', description: 'Google' },
@@ -1,17 +1,11 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isUrl = isUrl;
4
- exports.downloadExpoUrl = downloadExpoUrl;
5
- exports.extractTarGz = extractTarGz;
6
- exports.findAppBundle = findAppBundle;
7
- const node_crypto_1 = require("node:crypto");
8
- const fs = require("node:fs");
9
- const fsp = require("node:fs/promises");
10
- const os = require("node:os");
11
- const path = require("node:path");
12
- const node_stream_1 = require("node:stream");
13
- const promises_1 = require("node:stream/promises");
14
- const tar = require("tar");
1
+ import { randomUUID } from 'node:crypto';
2
+ import * as fs from 'node:fs';
3
+ import * as fsp from 'node:fs/promises';
4
+ import * as os from 'node:os';
5
+ import * as path from 'node:path';
6
+ import { Readable } from 'node:stream';
7
+ import { pipeline } from 'node:stream/promises';
8
+ import * as tar from 'tar';
15
9
  const DOWNLOAD_RETRY_ATTEMPTS = 3;
16
10
  const DOWNLOAD_RETRY_DELAY_MS = 2000;
17
11
  /**
@@ -19,7 +13,7 @@ const DOWNLOAD_RETRY_DELAY_MS = 2000;
19
13
  * @param input - String to test
20
14
  * @returns True if the string begins with http:// or https://
21
15
  */
22
- function isUrl(input) {
16
+ export function isUrl(input) {
23
17
  return input.startsWith('http://') || input.startsWith('https://');
24
18
  }
25
19
  /**
@@ -31,8 +25,8 @@ function isUrl(input) {
31
25
  * @param debug - Whether to emit debug log lines
32
26
  * @returns Absolute path to the downloaded temp file
33
27
  */
34
- async function downloadExpoUrl(url, debug) {
35
- const destPath = path.join(os.tmpdir(), `dcd-expo-${(0, node_crypto_1.randomUUID)()}.tar.gz`);
28
+ export async function downloadExpoUrl(url, debug) {
29
+ const destPath = path.join(os.tmpdir(), `dcd-expo-${randomUUID()}.tar.gz`);
36
30
  for (let attempt = 1; attempt <= DOWNLOAD_RETRY_ATTEMPTS; attempt++) {
37
31
  if (debug) {
38
32
  console.log(`[DEBUG] Downloading Expo URL (attempt ${attempt}/${DOWNLOAD_RETRY_ATTEMPTS}): ${url}`);
@@ -60,7 +54,7 @@ async function downloadExpoUrl(url, debug) {
60
54
  }
61
55
  // Stream to disk using pipeline to handle backpressure and avoid loading
62
56
  // the entire archive in memory
63
- await (0, promises_1.pipeline)(node_stream_1.Readable.fromWeb(response.body), fs.createWriteStream(destPath));
57
+ await pipeline(Readable.fromWeb(response.body), fs.createWriteStream(destPath));
64
58
  if (debug) {
65
59
  const stat = await fsp.stat(destPath);
66
60
  console.log(`[DEBUG] Downloaded ${(stat.size / 1024 / 1024).toFixed(2)} MB to ${destPath}`);
@@ -91,8 +85,8 @@ async function downloadExpoUrl(url, debug) {
91
85
  * @param debug - Whether to emit debug log lines
92
86
  * @returns Absolute path to the newly created extract directory
93
87
  */
94
- async function extractTarGz(tarPath, debug) {
95
- const extractDir = path.join(os.tmpdir(), `dcd-expo-${(0, node_crypto_1.randomUUID)()}`);
88
+ export async function extractTarGz(tarPath, debug) {
89
+ const extractDir = path.join(os.tmpdir(), `dcd-expo-${randomUUID()}`);
96
90
  await fsp.mkdir(extractDir, { recursive: true });
97
91
  if (debug) {
98
92
  console.log(`[DEBUG] Extracting ${tarPath} to ${extractDir}`);
@@ -109,7 +103,7 @@ async function extractTarGz(tarPath, debug) {
109
103
  * @param dir - Directory to search within
110
104
  * @returns Absolute path to the .app directory
111
105
  */
112
- async function findAppBundle(dir) {
106
+ export async function findAppBundle(dir) {
113
107
  const candidates = [];
114
108
  async function walk(current, depth) {
115
109
  const entries = await fsp.readdir(current, { withFileTypes: true });
@@ -1,18 +1,14 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fetchOrgs = fetchOrgs;
4
- exports.pickOrg = pickOrg;
5
1
  /**
6
2
  * Shared helpers for fetching and picking from /me/orgs. Used by both
7
3
  * `dcd login` (after the PKCE claim returns a session) and `dcd switch-org`.
8
4
  */
9
- const p = require("@clack/prompts");
10
- const cli_1 = require("./cli");
11
- async function fetchOrgs(apiUrl, headers) {
5
+ import * as p from '@clack/prompts';
6
+ import { CliError } from './cli.js';
7
+ export async function fetchOrgs(apiUrl, headers) {
12
8
  const res = await fetch(`${apiUrl.replace(/\/$/, '')}/me/orgs`, { headers });
13
9
  if (!res.ok) {
14
10
  const body = await res.text().catch(() => '');
15
- throw new cli_1.CliError(`Failed to list organizations: HTTP ${res.status}${body ? ` — ${body}` : ''}`);
11
+ throw new CliError(`Failed to list organizations: HTTP ${res.status}${body ? ` — ${body}` : ''}`);
16
12
  }
17
13
  const body = (await res.json());
18
14
  return body.orgs ?? [];
@@ -21,9 +17,9 @@ async function fetchOrgs(apiUrl, headers) {
21
17
  * Interactive org picker. Auto-selects when there's only one org (returns it
22
18
  * without prompting). Throws on zero orgs or user cancellation.
23
19
  */
24
- async function pickOrg(orgs, message = 'Pick an organization') {
20
+ export async function pickOrg(orgs, message = 'Pick an organization') {
25
21
  if (orgs.length === 0) {
26
- throw new cli_1.CliError('No organizations found for this user.');
22
+ throw new CliError('No organizations found for this user.');
27
23
  }
28
24
  if (orgs.length === 1)
29
25
  return orgs[0];
@@ -32,9 +28,9 @@ async function pickOrg(orgs, message = 'Pick an organization') {
32
28
  options: orgs.map((o) => ({ value: o.id, label: o.name })),
33
29
  });
34
30
  if (p.isCancel(picked))
35
- throw new cli_1.CliError('Cancelled.');
31
+ throw new CliError('Cancelled.');
36
32
  const chosen = orgs.find((o) => o.id === picked);
37
33
  if (!chosen)
38
- throw new cli_1.CliError('No organization selected.');
34
+ throw new CliError('No organization selected.');
39
35
  return chosen;
40
36
  }
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toPortableRelativePath = toPortableRelativePath;
4
- const path = require("node:path");
1
+ import * as path from 'node:path';
5
2
  /**
6
3
  * Convert an absolute path into the portable './'-prefixed, forward-slash
7
4
  * relative form used as flow keys across submission, metadata maps, and
@@ -12,7 +9,7 @@ const path = require("node:path");
12
9
  * Replaces the old `replaceAll(commonRoot, '.')` pattern, which corrupted
13
10
  * paths when the root substring recurred mid-path or collapsed to ''.
14
11
  */
15
- function toPortableRelativePath(absolutePath, commonRoot) {
12
+ export function toPortableRelativePath(absolutePath, commonRoot) {
16
13
  let relative = absolutePath;
17
14
  if (commonRoot && absolutePath.startsWith(commonRoot)) {
18
15
  relative = absolutePath.slice(commonRoot.length);
@@ -1,10 +1,13 @@
1
1
  declare class Action {
2
2
  private current;
3
3
  private _status;
4
+ private _lastPrinted;
5
+ private interactive;
4
6
  start(title: string, initialStatus?: string, _opts?: unknown): void;
5
7
  stop(message?: string): void;
6
8
  set status(value: string);
7
9
  get status(): string;
10
+ private print;
8
11
  }
9
12
  export declare const ux: {
10
13
  action: Action;