@layr-labs/ecloud-cli 0.1.0-dev.1 → 0.1.0-dev.3

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 (53) hide show
  1. package/README.md +6 -4
  2. package/VERSION +2 -2
  3. package/dist/commands/auth/generate.js +184 -46
  4. package/dist/commands/auth/generate.js.map +1 -1
  5. package/dist/commands/auth/login.js +234 -93
  6. package/dist/commands/auth/login.js.map +1 -1
  7. package/dist/commands/auth/logout.js +170 -30
  8. package/dist/commands/auth/logout.js.map +1 -1
  9. package/dist/commands/auth/migrate.js +216 -76
  10. package/dist/commands/auth/migrate.js.map +1 -1
  11. package/dist/commands/auth/whoami.js +145 -17
  12. package/dist/commands/auth/whoami.js.map +1 -1
  13. package/dist/commands/billing/cancel.js +164 -30
  14. package/dist/commands/billing/cancel.js.map +1 -1
  15. package/dist/commands/billing/status.js +213 -80
  16. package/dist/commands/billing/status.js.map +1 -1
  17. package/dist/commands/billing/subscribe.js +179 -45
  18. package/dist/commands/billing/subscribe.js.map +1 -1
  19. package/dist/commands/compute/app/create.js +148 -20
  20. package/dist/commands/compute/app/create.js.map +1 -1
  21. package/dist/commands/compute/app/deploy.js +244 -146
  22. package/dist/commands/compute/app/deploy.js.map +1 -1
  23. package/dist/commands/compute/app/info.js +2 -1
  24. package/dist/commands/compute/app/info.js.map +1 -1
  25. package/dist/commands/compute/app/list.js +194 -111
  26. package/dist/commands/compute/app/list.js.map +1 -1
  27. package/dist/commands/compute/app/logs.js +105 -20
  28. package/dist/commands/compute/app/logs.js.map +1 -1
  29. package/dist/commands/compute/app/profile/set.js +153 -64
  30. package/dist/commands/compute/app/profile/set.js.map +1 -1
  31. package/dist/commands/compute/app/start.js +132 -43
  32. package/dist/commands/compute/app/start.js.map +1 -1
  33. package/dist/commands/compute/app/stop.js +132 -43
  34. package/dist/commands/compute/app/stop.js.map +1 -1
  35. package/dist/commands/compute/app/terminate.js +131 -44
  36. package/dist/commands/compute/app/terminate.js.map +1 -1
  37. package/dist/commands/compute/app/upgrade.js +210 -109
  38. package/dist/commands/compute/app/upgrade.js.map +1 -1
  39. package/dist/commands/compute/environment/list.js +104 -12
  40. package/dist/commands/compute/environment/list.js.map +1 -1
  41. package/dist/commands/compute/environment/set.js +103 -18
  42. package/dist/commands/compute/environment/set.js.map +1 -1
  43. package/dist/commands/compute/environment/show.js +122 -30
  44. package/dist/commands/compute/environment/show.js.map +1 -1
  45. package/dist/commands/compute/undelegate.js +113 -13
  46. package/dist/commands/compute/undelegate.js.map +1 -1
  47. package/dist/commands/telemetry.js +213 -0
  48. package/dist/commands/telemetry.js.map +1 -0
  49. package/dist/commands/upgrade.js +159 -19
  50. package/dist/commands/upgrade.js.map +1 -1
  51. package/dist/commands/version.js +163 -23
  52. package/dist/commands/version.js.map +1 -1
  53. package/package.json +2 -2
@@ -6,7 +6,7 @@ import { isSubscriptionActive } from "@layr-labs/ecloud-sdk";
6
6
 
7
7
  // src/client.ts
8
8
  import {
9
- createAppModule,
9
+ createComputeModule,
10
10
  createBillingModule,
11
11
  getEnvironmentConfig as getEnvironmentConfig2,
12
12
  requirePrivateKey,
@@ -53,7 +53,75 @@ import * as path from "path";
53
53
  import * as os from "os";
54
54
  import { load as loadYaml, dump as dumpYaml } from "js-yaml";
55
55
  import { getBuildType } from "@layr-labs/ecloud-sdk";
56
+ import * as crypto from "crypto";
57
+ var GLOBAL_CONFIG_FILE = "config.yaml";
56
58
  var PROFILE_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
59
+ function getGlobalConfigDir() {
60
+ const configHome = process.env.XDG_CONFIG_HOME;
61
+ let baseDir;
62
+ if (configHome && path.isAbsolute(configHome)) {
63
+ baseDir = configHome;
64
+ } else {
65
+ baseDir = path.join(os.homedir(), ".config");
66
+ }
67
+ const buildType = getBuildType();
68
+ const buildSuffix = buildType === "dev" ? "-dev" : "";
69
+ const configDirName = `ecloud${buildSuffix}`;
70
+ return path.join(baseDir, configDirName);
71
+ }
72
+ function getGlobalConfigPath() {
73
+ return path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE);
74
+ }
75
+ function loadGlobalConfig() {
76
+ const configPath = getGlobalConfigPath();
77
+ if (!fs.existsSync(configPath)) {
78
+ return {
79
+ first_run: true
80
+ };
81
+ }
82
+ try {
83
+ const content = fs.readFileSync(configPath, "utf-8");
84
+ const config = loadYaml(content);
85
+ return config || { first_run: true };
86
+ } catch {
87
+ return {
88
+ first_run: true
89
+ };
90
+ }
91
+ }
92
+ function saveGlobalConfig(config) {
93
+ const configPath = getGlobalConfigPath();
94
+ const configDir = path.dirname(configPath);
95
+ fs.mkdirSync(configDir, { recursive: true, mode: 493 });
96
+ const content = dumpYaml(config, { lineWidth: -1 });
97
+ fs.writeFileSync(configPath, content, { mode: 420 });
98
+ }
99
+ function getDefaultEnvironment() {
100
+ const config = loadGlobalConfig();
101
+ return config.default_environment;
102
+ }
103
+ function getGlobalTelemetryPreference() {
104
+ const config = loadGlobalConfig();
105
+ return config.telemetry_enabled;
106
+ }
107
+ function getOrCreateUserUUID() {
108
+ const config = loadGlobalConfig();
109
+ if (config.user_uuid) {
110
+ return config.user_uuid;
111
+ }
112
+ const uuid = generateUUID();
113
+ config.user_uuid = uuid;
114
+ config.first_run = false;
115
+ saveGlobalConfig(config);
116
+ return uuid;
117
+ }
118
+ function generateUUID() {
119
+ const bytes = crypto.randomBytes(16);
120
+ bytes[6] = bytes[6] & 15 | 64;
121
+ bytes[8] = bytes[8] & 63 | 128;
122
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
123
+ return hex.slice(0, 4).join("") + hex.slice(4, 6).join("") + "-" + hex.slice(6, 8).join("") + "-" + hex.slice(8, 10).join("") + "-" + hex.slice(10, 12).join("") + "-" + hex.slice(12, 16).join("");
124
+ }
57
125
 
58
126
  // src/utils/appNames.ts
59
127
  import * as fs2 from "fs";
@@ -125,13 +193,75 @@ async function createBillingClient(flags) {
125
193
  const privateKey = await getPrivateKeyInteractive(result?.key);
126
194
  return createBillingModule({
127
195
  verbose: flags.verbose ?? false,
128
- privateKey
196
+ privateKey,
197
+ skipTelemetry: true
198
+ // CLI already has telemetry, skip SDK telemetry
129
199
  });
130
200
  }
131
201
 
132
202
  // src/commands/billing/subscribe.ts
133
203
  import chalk from "chalk";
134
204
  import open from "open";
205
+
206
+ // src/telemetry.ts
207
+ import {
208
+ createTelemetryClient,
209
+ createAppEnvironment,
210
+ createMetricsContext,
211
+ addMetric,
212
+ addMetricWithDimensions,
213
+ emitMetrics,
214
+ getBuildType as getBuildType2
215
+ } from "@layr-labs/ecloud-sdk";
216
+ function createCLITelemetryClient() {
217
+ const userUUID = getOrCreateUserUUID();
218
+ const environment = createAppEnvironment(userUUID);
219
+ const telemetryEnabled = getGlobalTelemetryPreference();
220
+ return createTelemetryClient(environment, "ecloud-cli", {
221
+ telemetryEnabled: telemetryEnabled === true
222
+ // Only enabled if explicitly set to true
223
+ });
224
+ }
225
+ async function withTelemetry(command, action) {
226
+ const client = createCLITelemetryClient();
227
+ const metrics = createMetricsContext();
228
+ metrics.properties["source"] = "ecloud-cli";
229
+ metrics.properties["command"] = command.id || command.constructor.name;
230
+ const environment = getDefaultEnvironment() || "sepolia";
231
+ metrics.properties["environment"] = environment;
232
+ const buildType = getBuildType2() || "prod";
233
+ metrics.properties["build_type"] = buildType;
234
+ const cliVersion = command.config.version;
235
+ if (cliVersion) {
236
+ metrics.properties["cli_version"] = cliVersion;
237
+ }
238
+ addMetric(metrics, "Count", 1);
239
+ let actionError;
240
+ let result;
241
+ try {
242
+ result = await action();
243
+ return result;
244
+ } catch (err) {
245
+ actionError = err instanceof Error ? err : new Error(String(err));
246
+ throw err;
247
+ } finally {
248
+ const resultValue = actionError ? "Failure" : "Success";
249
+ const dimensions = {};
250
+ if (actionError) {
251
+ dimensions["error"] = actionError.message;
252
+ }
253
+ addMetricWithDimensions(metrics, resultValue, 1, dimensions);
254
+ const duration = Date.now() - metrics.startTime.getTime();
255
+ addMetric(metrics, "DurationMilliseconds", duration);
256
+ try {
257
+ await emitMetrics(client, metrics);
258
+ await client.close();
259
+ } catch {
260
+ }
261
+ }
262
+ }
263
+
264
+ // src/commands/billing/subscribe.ts
135
265
  var PAYMENT_TIMEOUT_MS = 5 * 60 * 1e3;
136
266
  var POLL_INTERVAL_MS = 3e3;
137
267
  var BillingSubscribe = class _BillingSubscribe extends Command {
@@ -148,62 +278,66 @@ var BillingSubscribe = class _BillingSubscribe extends Command {
148
278
  })
149
279
  };
150
280
  async run() {
151
- const { flags } = await this.parse(_BillingSubscribe);
152
- const billing = await createBillingClient(flags);
153
- this.debug(`
281
+ return withTelemetry(this, async () => {
282
+ const { flags } = await this.parse(_BillingSubscribe);
283
+ const billing = await createBillingClient(flags);
284
+ this.debug(`
154
285
  Checking subscription status for ${flags.product}...`);
155
- const result = await billing.subscribe({
156
- productId: flags.product
157
- });
158
- if (result.type === "already_active") {
159
- this.log(`
286
+ const result = await billing.subscribe({
287
+ productId: flags.product
288
+ });
289
+ if (result.type === "already_active") {
290
+ this.log(`
160
291
  ${chalk.green("\u2713")} You're already subscribed to ${flags.product}.`);
161
- this.log(chalk.gray("Run 'ecloud billing status' for details."));
162
- return;
163
- }
164
- if (result.type === "payment_issue") {
165
- this.log(
166
- `
292
+ this.log(chalk.gray("Run 'ecloud billing status' for details."));
293
+ return;
294
+ }
295
+ if (result.type === "payment_issue") {
296
+ this.log(
297
+ `
167
298
  ${chalk.yellow("\u26A0")} You already have a subscription on ${flags.product}, but it has a payment issue.`
168
- );
169
- this.log("Please update your payment method to restore access.");
170
- if (result.portalUrl) {
171
- this.log(`
299
+ );
300
+ this.log("Please update your payment method to restore access.");
301
+ if (result.portalUrl) {
302
+ this.log(`
172
303
  ${chalk.bold("Update payment method:")}`);
173
- this.log(` ${result.portalUrl}`);
304
+ this.log(` ${result.portalUrl}`);
305
+ }
306
+ return;
174
307
  }
175
- return;
176
- }
177
- this.log(`
308
+ this.log(`
178
309
  ${chalk.gray("Opening checkout in your browser...")}`);
179
- this.log(chalk.gray(`
310
+ this.log(chalk.gray(`
180
311
  URL: ${result.checkoutUrl}`));
181
- await open(result.checkoutUrl);
182
- this.log(`
312
+ await open(result.checkoutUrl);
313
+ this.log(`
183
314
  ${chalk.gray("Waiting for payment confirmation...")}`);
184
- const startTime = Date.now();
185
- while (Date.now() - startTime < PAYMENT_TIMEOUT_MS) {
186
- await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
187
- try {
188
- const status = await billing.getStatus({
189
- productId: flags.product
190
- });
191
- if (isSubscriptionActive(status.subscriptionStatus)) {
192
- this.log(
193
- `
315
+ const startTime = Date.now();
316
+ while (Date.now() - startTime < PAYMENT_TIMEOUT_MS) {
317
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
318
+ try {
319
+ const status = await billing.getStatus({
320
+ productId: flags.product
321
+ });
322
+ if (isSubscriptionActive(status.subscriptionStatus)) {
323
+ this.log(
324
+ `
194
325
  ${chalk.green("\u2713")} Subscription activated successfully for ${flags.product}!`
195
- );
196
- this.log(`
326
+ );
327
+ this.log(`
197
328
  ${chalk.gray("Start deploying with:")} ecloud app deploy`);
198
- return;
329
+ return;
330
+ }
331
+ } catch (error) {
332
+ this.debug(`Error polling for subscription status: ${error}`);
199
333
  }
200
- } catch (error) {
201
- this.debug(`Error polling for subscription status: ${error}`);
202
334
  }
203
- }
204
- this.log(`
335
+ this.log(`
205
336
  ${chalk.yellow("\u26A0")} Payment confirmation timed out after 5 minutes.`);
206
- this.log(chalk.gray(`If you completed payment, run 'ecloud billing status' to check status.`));
337
+ this.log(
338
+ chalk.gray(`If you completed payment, run 'ecloud billing status' to check status.`)
339
+ );
340
+ });
207
341
  }
208
342
  };
209
343
  export {