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

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 (75) hide show
  1. package/README.md +264 -48
  2. package/VERSION +2 -0
  3. package/dist/commands/auth/generate.js +116 -10
  4. package/dist/commands/auth/generate.js.map +1 -1
  5. package/dist/commands/auth/login.js +37 -35
  6. package/dist/commands/auth/login.js.map +1 -1
  7. package/dist/commands/auth/logout.js +2 -8
  8. package/dist/commands/auth/logout.js.map +1 -1
  9. package/dist/commands/auth/migrate.js +32 -37
  10. package/dist/commands/auth/migrate.js.map +1 -1
  11. package/dist/commands/auth/whoami.js +53 -21
  12. package/dist/commands/auth/whoami.js.map +1 -1
  13. package/dist/commands/billing/cancel.js +83 -22
  14. package/dist/commands/billing/cancel.js.map +1 -1
  15. package/dist/commands/billing/status.js +92 -29
  16. package/dist/commands/billing/status.js.map +1 -1
  17. package/dist/commands/billing/subscribe.js +86 -31
  18. package/dist/commands/billing/subscribe.js.map +1 -1
  19. package/dist/commands/compute/app/configure/tls.js +150 -0
  20. package/dist/commands/compute/app/configure/tls.js.map +1 -0
  21. package/dist/commands/compute/app/create.js +134 -0
  22. package/dist/commands/compute/app/create.js.map +1 -0
  23. package/dist/commands/compute/app/deploy.js +1101 -0
  24. package/dist/commands/compute/app/deploy.js.map +1 -0
  25. package/dist/commands/compute/app/info.js +818 -0
  26. package/dist/commands/compute/app/info.js.map +1 -0
  27. package/dist/commands/compute/app/list.js +578 -0
  28. package/dist/commands/compute/app/list.js.map +1 -0
  29. package/dist/commands/compute/app/logs.js +639 -0
  30. package/dist/commands/compute/app/logs.js.map +1 -0
  31. package/dist/commands/compute/app/profile/set.js +1086 -0
  32. package/dist/commands/compute/app/profile/set.js.map +1 -0
  33. package/dist/commands/compute/app/start.js +675 -0
  34. package/dist/commands/compute/app/start.js.map +1 -0
  35. package/dist/commands/compute/app/stop.js +675 -0
  36. package/dist/commands/compute/app/stop.js.map +1 -0
  37. package/dist/commands/compute/app/terminate.js +681 -0
  38. package/dist/commands/compute/app/terminate.js.map +1 -0
  39. package/dist/commands/compute/app/upgrade.js +1072 -0
  40. package/dist/commands/compute/app/upgrade.js.map +1 -0
  41. package/dist/commands/compute/environment/list.js +89 -0
  42. package/dist/commands/compute/environment/list.js.map +1 -0
  43. package/dist/commands/compute/environment/set.js +215 -0
  44. package/dist/commands/compute/environment/set.js.map +1 -0
  45. package/dist/commands/compute/environment/show.js +96 -0
  46. package/dist/commands/compute/environment/show.js.map +1 -0
  47. package/dist/commands/compute/undelegate.js +259 -0
  48. package/dist/commands/compute/undelegate.js.map +1 -0
  49. package/dist/commands/upgrade.js +91 -0
  50. package/dist/commands/upgrade.js.map +1 -0
  51. package/dist/commands/version.js +65 -0
  52. package/dist/commands/version.js.map +1 -0
  53. package/package.json +30 -5
  54. package/dist/commands/app/create.js +0 -29
  55. package/dist/commands/app/create.js.map +0 -1
  56. package/dist/commands/app/deploy.js +0 -142
  57. package/dist/commands/app/deploy.js.map +0 -1
  58. package/dist/commands/app/logs.js +0 -108
  59. package/dist/commands/app/logs.js.map +0 -1
  60. package/dist/commands/app/start.js +0 -121
  61. package/dist/commands/app/start.js.map +0 -1
  62. package/dist/commands/app/stop.js +0 -121
  63. package/dist/commands/app/stop.js.map +0 -1
  64. package/dist/commands/app/terminate.js +0 -128
  65. package/dist/commands/app/terminate.js.map +0 -1
  66. package/dist/commands/app/upgrade.js +0 -142
  67. package/dist/commands/app/upgrade.js.map +0 -1
  68. package/dist/keys/mainnet-alpha/prod/kms-encryption-public-key.pem +0 -14
  69. package/dist/keys/mainnet-alpha/prod/kms-signing-public-key.pem +0 -4
  70. package/dist/keys/sepolia/dev/kms-encryption-public-key.pem +0 -14
  71. package/dist/keys/sepolia/dev/kms-signing-public-key.pem +0 -4
  72. package/dist/keys/sepolia/prod/kms-encryption-public-key.pem +0 -14
  73. package/dist/keys/sepolia/prod/kms-signing-public-key.pem +0 -4
  74. package/dist/templates/Dockerfile.layered.tmpl +0 -58
  75. package/dist/templates/compute-source-env.sh.tmpl +0 -110
@@ -0,0 +1,578 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/compute/app/list.ts
4
+ import { Command, Flags as Flags2 } from "@oclif/core";
5
+ import {
6
+ getEnvironmentConfig as getEnvironmentConfig2,
7
+ getAllAppsByDeveloper as getAllAppsByDeveloper3,
8
+ getAppLatestReleaseBlockNumbers,
9
+ getBlockTimestamps,
10
+ UserApiClient as UserApiClient3
11
+ } from "@layr-labs/ecloud-sdk";
12
+
13
+ // src/flags.ts
14
+ import { Flags } from "@oclif/core";
15
+
16
+ // src/utils/prompts.ts
17
+ import { input, select, password, confirm as inquirerConfirm } from "@inquirer/prompts";
18
+ import fs3 from "fs";
19
+ import path3 from "path";
20
+ import os3 from "os";
21
+ import { isAddress as isAddress2 } from "viem";
22
+ import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
23
+ import {
24
+ getEnvironmentConfig,
25
+ getAvailableEnvironments,
26
+ isEnvironmentAvailable,
27
+ getAllAppsByDeveloper as getAllAppsByDeveloper2,
28
+ getCategoryDescriptions,
29
+ fetchTemplateCatalog,
30
+ PRIMARY_LANGUAGES,
31
+ validateAppName,
32
+ validateImageReference,
33
+ validateFilePath,
34
+ validatePrivateKeyFormat,
35
+ extractAppNameFromImage,
36
+ UserApiClient as UserApiClient2
37
+ } from "@layr-labs/ecloud-sdk";
38
+
39
+ // src/utils/appResolver.ts
40
+ import { isAddress } from "viem";
41
+ import { privateKeyToAccount } from "viem/accounts";
42
+ import {
43
+ UserApiClient,
44
+ getAllAppsByDeveloper
45
+ } from "@layr-labs/ecloud-sdk";
46
+
47
+ // src/utils/globalConfig.ts
48
+ import * as fs from "fs";
49
+ import * as path from "path";
50
+ import * as os from "os";
51
+ import { load as loadYaml, dump as dumpYaml } from "js-yaml";
52
+ import { getBuildType } from "@layr-labs/ecloud-sdk";
53
+ var GLOBAL_CONFIG_FILE = "config.yaml";
54
+ var PROFILE_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
55
+ function getGlobalConfigDir() {
56
+ const configHome = process.env.XDG_CONFIG_HOME;
57
+ let baseDir;
58
+ if (configHome && path.isAbsolute(configHome)) {
59
+ baseDir = configHome;
60
+ } else {
61
+ baseDir = path.join(os.homedir(), ".config");
62
+ }
63
+ const buildType = getBuildType();
64
+ const buildSuffix = buildType === "dev" ? "-dev" : "";
65
+ const configDirName = `ecloud${buildSuffix}`;
66
+ return path.join(baseDir, configDirName);
67
+ }
68
+ function getGlobalConfigPath() {
69
+ return path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE);
70
+ }
71
+ function loadGlobalConfig() {
72
+ const configPath = getGlobalConfigPath();
73
+ if (!fs.existsSync(configPath)) {
74
+ return {
75
+ first_run: true
76
+ };
77
+ }
78
+ try {
79
+ const content = fs.readFileSync(configPath, "utf-8");
80
+ const config = loadYaml(content);
81
+ return config || { first_run: true };
82
+ } catch {
83
+ return {
84
+ first_run: true
85
+ };
86
+ }
87
+ }
88
+ function getDefaultEnvironment() {
89
+ const config = loadGlobalConfig();
90
+ return config.default_environment;
91
+ }
92
+
93
+ // src/utils/appNames.ts
94
+ import * as fs2 from "fs";
95
+ import * as path2 from "path";
96
+ import * as os2 from "os";
97
+ import { load as loadYaml2, dump as dumpYaml2 } from "js-yaml";
98
+ var CONFIG_DIR = path2.join(os2.homedir(), ".eigenx");
99
+ var APPS_DIR = path2.join(CONFIG_DIR, "apps");
100
+ var APP_REGISTRY_VERSION = "1.0.0";
101
+ function getAppRegistryPath(environment) {
102
+ return path2.join(APPS_DIR, `${environment}.yaml`);
103
+ }
104
+ function loadAppRegistry(environment) {
105
+ const filePath = getAppRegistryPath(environment);
106
+ if (!fs2.existsSync(filePath)) {
107
+ return {
108
+ version: APP_REGISTRY_VERSION,
109
+ apps: {}
110
+ };
111
+ }
112
+ try {
113
+ const content = fs2.readFileSync(filePath, "utf-8");
114
+ const registry = loadYaml2(content);
115
+ if (!registry.apps) {
116
+ registry.apps = {};
117
+ }
118
+ return registry;
119
+ } catch {
120
+ return {
121
+ version: APP_REGISTRY_VERSION,
122
+ apps: {}
123
+ };
124
+ }
125
+ }
126
+ function getAppName(environment, appID) {
127
+ const registry = loadAppRegistry(environment);
128
+ const normalizedAppID = appID.toLowerCase();
129
+ for (const [name, app] of Object.entries(registry.apps)) {
130
+ if (app?.app_id && String(app.app_id).toLowerCase() === normalizedAppID) {
131
+ return name;
132
+ }
133
+ }
134
+ return "";
135
+ }
136
+
137
+ // src/utils/version.ts
138
+ function getCliVersion() {
139
+ return true ? "0.1.0-dev" : "0.0.0";
140
+ }
141
+ function getClientId() {
142
+ return `ecloud-cli/v${getCliVersion()}`;
143
+ }
144
+
145
+ // src/utils/appResolver.ts
146
+ var CHUNK_SIZE = 10;
147
+ async function getAppInfosChunked(userApiClient, appIds, addressCount) {
148
+ if (appIds.length === 0) {
149
+ return [];
150
+ }
151
+ const chunks = [];
152
+ for (let i = 0; i < appIds.length; i += CHUNK_SIZE) {
153
+ chunks.push(appIds.slice(i, i + CHUNK_SIZE));
154
+ }
155
+ const chunkResults = await Promise.all(
156
+ chunks.map((chunk) => userApiClient.getInfos(chunk, addressCount))
157
+ );
158
+ return chunkResults.flat();
159
+ }
160
+
161
+ // src/utils/prompts.ts
162
+ var ContractAppStatusStarted = 1;
163
+ var ContractAppStatusStopped = 2;
164
+ var ContractAppStatusTerminated = 3;
165
+ var ContractAppStatusSuspended = 4;
166
+ function getContractStatusString(status) {
167
+ switch (status) {
168
+ case ContractAppStatusStarted:
169
+ return "Started";
170
+ case ContractAppStatusStopped:
171
+ return "Stopped";
172
+ case ContractAppStatusTerminated:
173
+ return "Terminated";
174
+ case ContractAppStatusSuspended:
175
+ return "Suspended";
176
+ default:
177
+ return "Unknown";
178
+ }
179
+ }
180
+ function getStatusSortPriority(status) {
181
+ switch (status.toLowerCase()) {
182
+ case "running":
183
+ case "started":
184
+ return 0;
185
+ // Running apps first
186
+ case "deploying":
187
+ case "upgrading":
188
+ case "resuming":
189
+ return 1;
190
+ // In-progress operations second
191
+ case "stopped":
192
+ case "stopping":
193
+ return 2;
194
+ // Stopped third
195
+ case "suspended":
196
+ return 3;
197
+ // Suspended fourth
198
+ case "failed":
199
+ return 4;
200
+ // Failed fifth
201
+ case "terminated":
202
+ return 5;
203
+ // Terminated last
204
+ default:
205
+ return 6;
206
+ }
207
+ }
208
+ async function getPrivateKeyInteractive(privateKey) {
209
+ if (privateKey) {
210
+ if (!validatePrivateKeyFormat(privateKey)) {
211
+ throw new Error("Invalid private key format");
212
+ }
213
+ return privateKey;
214
+ }
215
+ const { getPrivateKeyWithSource } = await import("@layr-labs/ecloud-sdk");
216
+ const result = await getPrivateKeyWithSource({ privateKey: void 0 });
217
+ if (result) {
218
+ return result.key;
219
+ }
220
+ const key = await password({
221
+ message: "Enter private key:",
222
+ mask: true,
223
+ validate: (value) => {
224
+ if (!value.trim()) {
225
+ return "Private key is required";
226
+ }
227
+ if (!validatePrivateKeyFormat(value)) {
228
+ return "Invalid private key format (must be 64 hex characters, optionally prefixed with 0x)";
229
+ }
230
+ return true;
231
+ }
232
+ });
233
+ return key.trim();
234
+ }
235
+ async function getEnvironmentInteractive(environment) {
236
+ if (environment) {
237
+ try {
238
+ getEnvironmentConfig(environment);
239
+ if (!isEnvironmentAvailable(environment)) {
240
+ throw new Error(`Environment ${environment} is not available in this build`);
241
+ }
242
+ return environment;
243
+ } catch {
244
+ }
245
+ }
246
+ const availableEnvs = getAvailableEnvironments();
247
+ let defaultEnv;
248
+ const configDefaultEnv = getDefaultEnvironment();
249
+ if (configDefaultEnv && availableEnvs.includes(configDefaultEnv)) {
250
+ try {
251
+ getEnvironmentConfig(configDefaultEnv);
252
+ defaultEnv = configDefaultEnv;
253
+ } catch {
254
+ }
255
+ }
256
+ const choices = [];
257
+ if (availableEnvs.includes("sepolia")) {
258
+ choices.push({ name: "sepolia - Ethereum Sepolia testnet", value: "sepolia" });
259
+ }
260
+ if (availableEnvs.includes("sepolia-dev")) {
261
+ choices.push({ name: "sepolia-dev - Ethereum Sepolia testnet (dev)", value: "sepolia-dev" });
262
+ }
263
+ if (availableEnvs.includes("mainnet-alpha")) {
264
+ choices.push({
265
+ name: "mainnet-alpha - Ethereum mainnet (\u26A0\uFE0F uses real funds)",
266
+ value: "mainnet-alpha"
267
+ });
268
+ }
269
+ if (choices.length === 0) {
270
+ throw new Error("No environments available in this build");
271
+ }
272
+ const env = await select({
273
+ message: "Select environment:",
274
+ choices,
275
+ default: defaultEnv
276
+ });
277
+ return env;
278
+ }
279
+ var MAX_IMAGE_SIZE = 4 * 1024 * 1024;
280
+
281
+ // src/flags.ts
282
+ var commonFlags = {
283
+ environment: Flags.string({
284
+ required: false,
285
+ description: "Deployment environment to use",
286
+ env: "ECLOUD_ENV"
287
+ }),
288
+ "private-key": Flags.string({
289
+ required: false,
290
+ description: "Private key for signing transactions",
291
+ env: "ECLOUD_PRIVATE_KEY"
292
+ }),
293
+ "rpc-url": Flags.string({
294
+ required: false,
295
+ description: "RPC URL to connect to blockchain",
296
+ env: "ECLOUD_RPC_URL"
297
+ }),
298
+ verbose: Flags.boolean({
299
+ required: false,
300
+ description: "Enable verbose logging (default: false)",
301
+ default: false
302
+ })
303
+ };
304
+ async function validateCommonFlags(flags) {
305
+ if (!flags["environment"]) {
306
+ flags["environment"] = getDefaultEnvironment();
307
+ }
308
+ flags["environment"] = await getEnvironmentInteractive(flags["environment"]);
309
+ flags["private-key"] = await getPrivateKeyInteractive(flags["private-key"]);
310
+ return flags;
311
+ }
312
+
313
+ // src/commands/compute/app/list.ts
314
+ import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
315
+
316
+ // src/utils/format.ts
317
+ import chalk from "chalk";
318
+ function formatBytes(bytes) {
319
+ if (bytes === 0) return "0 B";
320
+ const k = 1024;
321
+ const sizes = ["B", "KB", "MB", "GB", "TB"];
322
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
323
+ return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
324
+ }
325
+ function formatStatus(status) {
326
+ switch (status.toLowerCase()) {
327
+ case "running":
328
+ case "started":
329
+ return chalk.green(status);
330
+ case "stopped":
331
+ return chalk.yellow(status);
332
+ case "terminated":
333
+ return chalk.red(status);
334
+ case "suspended":
335
+ return chalk.red(status);
336
+ case "deploying":
337
+ case "upgrading":
338
+ case "resuming":
339
+ case "stopping":
340
+ return chalk.cyan(status);
341
+ case "failed":
342
+ return chalk.red(status);
343
+ default:
344
+ return chalk.gray(status);
345
+ }
346
+ }
347
+ function formatAppDisplay(options) {
348
+ const { appInfo, appName, status, releaseTimestamp, showProfileDetails = false } = options;
349
+ const displayName = appName || appInfo.profile?.name;
350
+ const name = displayName ? chalk.cyan(displayName) : chalk.gray("(unnamed)");
351
+ const id = chalk.gray(appInfo.address);
352
+ const releaseTime = releaseTimestamp ? chalk.gray(new Date(releaseTimestamp * 1e3).toISOString().replace("T", " ").slice(0, 19)) : chalk.gray("-");
353
+ const statusStr = status || appInfo.status;
354
+ const formattedStatus = formatStatus(statusStr);
355
+ const instance = appInfo.machineType && appInfo.machineType !== "No instance assigned" ? chalk.gray(appInfo.machineType) : chalk.gray("-");
356
+ const ip = appInfo.ip && appInfo.ip !== "No IP assigned" ? chalk.white(appInfo.ip) : chalk.gray("No IP assigned");
357
+ const metrics = appInfo.metrics;
358
+ const cpu = metrics?.cpu_utilization_percent !== void 0 ? chalk.white(`${metrics.cpu_utilization_percent.toFixed(1)}%`) : chalk.gray("-");
359
+ const memory = metrics?.memory_utilization_percent !== void 0 ? chalk.white(`${metrics.memory_utilization_percent.toFixed(1)}%`) : chalk.gray("-");
360
+ const memoryUsage = metrics?.memory_used_bytes !== void 0 && metrics?.memory_total_bytes !== void 0 ? chalk.gray(
361
+ `(${formatBytes(metrics.memory_used_bytes)} / ${formatBytes(metrics.memory_total_bytes)})`
362
+ ) : "";
363
+ const evmAddresses = (appInfo.evmAddresses || []).map((addr) => ({
364
+ address: addr.address,
365
+ path: addr.derivationPath
366
+ }));
367
+ const solanaAddresses = (appInfo.solanaAddresses || []).map((addr) => ({
368
+ address: addr.address,
369
+ path: addr.derivationPath
370
+ }));
371
+ let profile;
372
+ if (showProfileDetails && appInfo.profile) {
373
+ const p = appInfo.profile;
374
+ if (p.website || p.description || p.xURL) {
375
+ profile = {
376
+ website: p.website,
377
+ description: p.description,
378
+ xURL: p.xURL
379
+ };
380
+ }
381
+ }
382
+ return {
383
+ name,
384
+ id,
385
+ releaseTime,
386
+ status: formattedStatus,
387
+ instance,
388
+ ip,
389
+ cpu,
390
+ memory,
391
+ memoryUsage,
392
+ evmAddresses,
393
+ solanaAddresses,
394
+ profile
395
+ };
396
+ }
397
+ function printAppDisplay(display, log, indent = " ", options = {}) {
398
+ const { singleAddress = false, showProfile = false } = options;
399
+ log(`${indent}ID: ${display.id}`);
400
+ log(`${indent}Release Time: ${display.releaseTime}`);
401
+ log(`${indent}Status: ${display.status}`);
402
+ log(`${indent}Instance: ${display.instance}`);
403
+ log(`${indent}IP: ${display.ip}`);
404
+ log(`${indent}CPU: ${display.cpu}`);
405
+ log(`${indent}Memory: ${display.memory} ${display.memoryUsage}`);
406
+ if (display.evmAddresses.length > 0) {
407
+ const addrs = singleAddress ? display.evmAddresses.slice(0, 1) : display.evmAddresses;
408
+ for (let i = 0; i < addrs.length; i++) {
409
+ const addr = addrs[i];
410
+ const label = i === 0 ? "EVM Address:" : " ";
411
+ log(`${indent}${label} ${chalk.gray(`${addr.address} (path: ${addr.path})`)}`);
412
+ }
413
+ } else {
414
+ log(`${indent}EVM Address: ${chalk.gray("-")}`);
415
+ }
416
+ if (display.solanaAddresses.length > 0) {
417
+ const addrs = singleAddress ? display.solanaAddresses.slice(0, 1) : display.solanaAddresses;
418
+ for (let i = 0; i < addrs.length; i++) {
419
+ const addr = addrs[i];
420
+ const label = i === 0 ? "Solana Address:" : " ";
421
+ log(`${indent}${label} ${chalk.gray(`${addr.address} (path: ${addr.path})`)}`);
422
+ }
423
+ } else {
424
+ log(`${indent}Solana Address: ${chalk.gray("-")}`);
425
+ }
426
+ if (showProfile && display.profile) {
427
+ log(
428
+ chalk.gray(`${indent}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`)
429
+ );
430
+ if (display.profile.website) {
431
+ log(`${indent}Website: ${chalk.gray(display.profile.website)}`);
432
+ }
433
+ if (display.profile.description) {
434
+ log(`${indent}Description: ${chalk.gray(display.profile.description)}`);
435
+ }
436
+ if (display.profile.xURL) {
437
+ log(`${indent}X (Twitter): ${chalk.gray(display.profile.xURL)}`);
438
+ }
439
+ }
440
+ }
441
+
442
+ // src/commands/compute/app/list.ts
443
+ import chalk2 from "chalk";
444
+ var AppList = class _AppList extends Command {
445
+ static description = "List all deployed apps";
446
+ static flags = {
447
+ ...commonFlags,
448
+ all: Flags2.boolean({
449
+ description: "Show all apps including terminated ones",
450
+ char: "a",
451
+ default: false
452
+ }),
453
+ "address-count": Flags2.integer({
454
+ description: "Number of addresses to fetch",
455
+ default: 1
456
+ })
457
+ };
458
+ async run() {
459
+ const { flags } = await this.parse(_AppList);
460
+ const validatedFlags = await validateCommonFlags(flags);
461
+ const environment = validatedFlags.environment || "sepolia";
462
+ const environmentConfig = getEnvironmentConfig2(environment);
463
+ const rpcUrl = validatedFlags["rpc-url"] || environmentConfig.defaultRPCURL;
464
+ const privateKey = validatedFlags["private-key"];
465
+ const account = privateKeyToAccount3(privateKey);
466
+ const developerAddr = account.address;
467
+ if (flags.verbose) {
468
+ this.log(`Fetching apps for developer: ${developerAddr}`);
469
+ }
470
+ const result = await getAllAppsByDeveloper3(rpcUrl, environmentConfig, developerAddr);
471
+ if (result.apps.length === 0) {
472
+ this.log(`
473
+ No apps found for developer ${developerAddr}`);
474
+ return;
475
+ }
476
+ const filteredApps = [];
477
+ const filteredConfigs = [];
478
+ for (let i = 0; i < result.apps.length; i++) {
479
+ const config = result.appConfigs[i];
480
+ if (!flags.all && config.status === ContractAppStatusTerminated) {
481
+ continue;
482
+ }
483
+ filteredApps.push(result.apps[i]);
484
+ filteredConfigs.push(config);
485
+ }
486
+ if (filteredApps.length === 0) {
487
+ if (flags.all) {
488
+ this.log(`
489
+ No apps found for developer ${developerAddr}`);
490
+ } else {
491
+ this.log(
492
+ `
493
+ No active apps found for developer ${developerAddr} (use --all to show terminated apps)`
494
+ );
495
+ }
496
+ return;
497
+ }
498
+ const userApiClient = new UserApiClient3(environmentConfig, privateKey, rpcUrl, getClientId());
499
+ const addressCount = flags["address-count"];
500
+ const [appInfos, releaseBlockNumbers] = await Promise.all([
501
+ getAppInfosChunked(userApiClient, filteredApps, addressCount).catch((err) => {
502
+ if (flags.verbose) {
503
+ this.warn(`Could not fetch app info from UserAPI: ${err}`);
504
+ }
505
+ return [];
506
+ }),
507
+ getAppLatestReleaseBlockNumbers(rpcUrl, environmentConfig, filteredApps).catch((err) => {
508
+ if (flags.verbose) {
509
+ this.warn(`Could not fetch release block numbers: ${err}`);
510
+ }
511
+ return /* @__PURE__ */ new Map();
512
+ })
513
+ ]);
514
+ const blockNumbers = Array.from(releaseBlockNumbers.values()).filter((n) => n > 0);
515
+ const blockTimestamps = blockNumbers.length > 0 ? await getBlockTimestamps(rpcUrl, environmentConfig, blockNumbers).catch((err) => {
516
+ if (flags.verbose) {
517
+ this.warn(`Could not fetch block timestamps: ${err}`);
518
+ }
519
+ return /* @__PURE__ */ new Map();
520
+ }) : /* @__PURE__ */ new Map();
521
+ const appItems = [];
522
+ for (let i = 0; i < filteredApps.length; i++) {
523
+ const appAddr = filteredApps[i];
524
+ const config = filteredConfigs[i];
525
+ const apiInfo = appInfos.find(
526
+ (info) => info.address && String(info.address).toLowerCase() === appAddr.toLowerCase()
527
+ );
528
+ const profileName = apiInfo?.profile?.name;
529
+ const localName = getAppName(environment, appAddr);
530
+ const appName = profileName || localName;
531
+ const status = apiInfo?.status || getContractStatusString(config.status);
532
+ const releaseBlockNumber = releaseBlockNumbers.get(appAddr);
533
+ const releaseTimestamp = releaseBlockNumber ? blockTimestamps.get(releaseBlockNumber) : void 0;
534
+ appItems.push({ appAddr, apiInfo, appName, status, releaseTimestamp });
535
+ }
536
+ appItems.sort((a, b) => {
537
+ const aPriority = getStatusSortPriority(a.status);
538
+ const bPriority = getStatusSortPriority(b.status);
539
+ if (aPriority !== bPriority) {
540
+ return aPriority - bPriority;
541
+ }
542
+ const aTime = a.releaseTimestamp || 0;
543
+ const bTime = b.releaseTimestamp || 0;
544
+ return bTime - aTime;
545
+ });
546
+ console.log();
547
+ this.log(chalk2.bold(`Apps for ${developerAddr} (${environment}):`));
548
+ console.log();
549
+ for (let i = 0; i < appItems.length; i++) {
550
+ const { apiInfo, appName, status, releaseTimestamp } = appItems[i];
551
+ if (!apiInfo) {
552
+ continue;
553
+ }
554
+ const display = formatAppDisplay({
555
+ appInfo: apiInfo,
556
+ appName,
557
+ status,
558
+ releaseTimestamp
559
+ });
560
+ this.log(` ${display.name}`);
561
+ printAppDisplay(display, this.log.bind(this), " ", {
562
+ singleAddress: addressCount === 1,
563
+ showProfile: false
564
+ });
565
+ if (i < appItems.length - 1) {
566
+ this.log(
567
+ chalk2.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")
568
+ );
569
+ }
570
+ }
571
+ console.log();
572
+ this.log(chalk2.gray(`Total: ${appItems.length} app(s)`));
573
+ }
574
+ };
575
+ export {
576
+ AppList as default
577
+ };
578
+ //# sourceMappingURL=list.js.map