@layr-labs/ecloud-cli 0.1.1 → 0.1.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 (44) hide show
  1. package/VERSION +2 -2
  2. package/dist/commands/auth/generate.js +2 -2
  3. package/dist/commands/auth/generate.js.map +1 -1
  4. package/dist/commands/auth/login.js.map +1 -1
  5. package/dist/commands/auth/logout.js.map +1 -1
  6. package/dist/commands/auth/migrate.js.map +1 -1
  7. package/dist/commands/auth/whoami.js +5 -3
  8. package/dist/commands/auth/whoami.js.map +1 -1
  9. package/dist/commands/billing/cancel.js +5 -3
  10. package/dist/commands/billing/cancel.js.map +1 -1
  11. package/dist/commands/billing/status.js +5 -3
  12. package/dist/commands/billing/status.js.map +1 -1
  13. package/dist/commands/billing/subscribe.js +10 -6
  14. package/dist/commands/billing/subscribe.js.map +1 -1
  15. package/dist/commands/compute/app/create.js.map +1 -1
  16. package/dist/commands/compute/app/deploy.js +143 -76
  17. package/dist/commands/compute/app/deploy.js.map +1 -1
  18. package/dist/commands/compute/app/info.js +54 -8
  19. package/dist/commands/compute/app/info.js.map +1 -1
  20. package/dist/commands/compute/app/list.js +6 -7
  21. package/dist/commands/compute/app/list.js.map +1 -1
  22. package/dist/commands/compute/app/logs.js +55 -9
  23. package/dist/commands/compute/app/logs.js.map +1 -1
  24. package/dist/commands/compute/app/profile/set.js +141 -20
  25. package/dist/commands/compute/app/profile/set.js.map +1 -1
  26. package/dist/commands/compute/app/start.js +55 -9
  27. package/dist/commands/compute/app/start.js.map +1 -1
  28. package/dist/commands/compute/app/stop.js +55 -9
  29. package/dist/commands/compute/app/stop.js.map +1 -1
  30. package/dist/commands/compute/app/terminate.js +55 -9
  31. package/dist/commands/compute/app/terminate.js.map +1 -1
  32. package/dist/commands/compute/app/upgrade.js +172 -49
  33. package/dist/commands/compute/app/upgrade.js.map +1 -1
  34. package/dist/commands/compute/environment/list.js.map +1 -1
  35. package/dist/commands/compute/environment/set.js.map +1 -1
  36. package/dist/commands/compute/environment/show.js.map +1 -1
  37. package/dist/commands/compute/undelegate.js +6 -7
  38. package/dist/commands/compute/undelegate.js.map +1 -1
  39. package/dist/commands/telemetry/disable.js.map +1 -1
  40. package/dist/commands/telemetry/enable.js.map +1 -1
  41. package/dist/commands/telemetry/status.js.map +1 -1
  42. package/dist/commands/upgrade.js.map +1 -1
  43. package/dist/commands/version.js.map +1 -1
  44. package/package.json +3 -2
@@ -2,14 +2,7 @@
2
2
 
3
3
  // src/commands/compute/app/deploy.ts
4
4
  import { Command, Flags as Flags2 } from "@oclif/core";
5
- import {
6
- getEnvironmentConfig as getEnvironmentConfig2,
7
- UserApiClient as UserApiClient3,
8
- isMainnet,
9
- prepareDeploy,
10
- executeDeploy,
11
- watchDeployment
12
- } from "@layr-labs/ecloud-sdk";
5
+ import { getEnvironmentConfig as getEnvironmentConfig3, isMainnet, UserApiClient as UserApiClient3 } from "@layr-labs/ecloud-sdk";
13
6
 
14
7
  // src/telemetry.ts
15
8
  import {
@@ -71,6 +64,29 @@ function saveGlobalConfig(config) {
71
64
  const content = dumpYaml(config, { lineWidth: -1 });
72
65
  fs.writeFileSync(configPath, content, { mode: 420 });
73
66
  }
67
+ function normalizeDirectoryPath(directoryPath) {
68
+ const resolved = path.resolve(directoryPath);
69
+ try {
70
+ return fs.realpathSync(resolved);
71
+ } catch {
72
+ return resolved;
73
+ }
74
+ }
75
+ function setLinkedAppForDirectory(environment, directoryPath, appId) {
76
+ if (!directoryPath || !environment) {
77
+ return;
78
+ }
79
+ const config = loadGlobalConfig();
80
+ if (!config.directory_links) {
81
+ config.directory_links = {};
82
+ }
83
+ if (!config.directory_links[environment]) {
84
+ config.directory_links[environment] = {};
85
+ }
86
+ const normalizedPath = normalizeDirectoryPath(directoryPath);
87
+ config.directory_links[environment][normalizedPath] = appId.toLowerCase();
88
+ saveGlobalConfig(config);
89
+ }
74
90
  function getDefaultEnvironment() {
75
91
  const config = loadGlobalConfig();
76
92
  return config.default_environment;
@@ -161,6 +177,7 @@ async function withTelemetry(command, action) {
161
177
 
162
178
  // src/flags.ts
163
179
  import { Flags } from "@oclif/core";
180
+ import { getBuildType as getBuildType3 } from "@layr-labs/ecloud-sdk";
164
181
 
165
182
  // src/utils/prompts.ts
166
183
  import { input, select, password, confirm as inquirerConfirm } from "@inquirer/prompts";
@@ -256,7 +273,7 @@ function findAvailableName(environment, baseName) {
256
273
 
257
274
  // src/utils/version.ts
258
275
  function getCliVersion() {
259
- return true ? "0.1.1" : "0.0.0";
276
+ return true ? "0.1.2" : "0.0.0";
260
277
  }
261
278
  function getClientId() {
262
279
  return `ecloud-cli/v${getCliVersion()}`;
@@ -710,8 +727,8 @@ async function getPrivateKeyInteractive(privateKey) {
710
727
  }
711
728
  return privateKey;
712
729
  }
713
- const { getPrivateKeyWithSource } = await import("@layr-labs/ecloud-sdk");
714
- const result = await getPrivateKeyWithSource({ privateKey: void 0 });
730
+ const { getPrivateKeyWithSource: getPrivateKeyWithSource2 } = await import("@layr-labs/ecloud-sdk");
731
+ const result = await getPrivateKeyWithSource2({ privateKey: void 0 });
715
732
  if (result) {
716
733
  return result.key;
717
734
  }
@@ -730,6 +747,50 @@ async function getPrivateKeyInteractive(privateKey) {
730
747
  });
731
748
  return key.trim();
732
749
  }
750
+ async function getEnvironmentInteractive(environment) {
751
+ if (environment) {
752
+ try {
753
+ getEnvironmentConfig(environment);
754
+ if (!isEnvironmentAvailable(environment)) {
755
+ throw new Error(`Environment ${environment} is not available in this build`);
756
+ }
757
+ return environment;
758
+ } catch {
759
+ }
760
+ }
761
+ const availableEnvs = getAvailableEnvironments();
762
+ let defaultEnv;
763
+ const configDefaultEnv = getDefaultEnvironment();
764
+ if (configDefaultEnv && availableEnvs.includes(configDefaultEnv)) {
765
+ try {
766
+ getEnvironmentConfig(configDefaultEnv);
767
+ defaultEnv = configDefaultEnv;
768
+ } catch {
769
+ }
770
+ }
771
+ const choices = [];
772
+ if (availableEnvs.includes("sepolia")) {
773
+ choices.push({ name: "sepolia - Ethereum Sepolia testnet", value: "sepolia" });
774
+ }
775
+ if (availableEnvs.includes("sepolia-dev")) {
776
+ choices.push({ name: "sepolia-dev - Ethereum Sepolia testnet (dev)", value: "sepolia-dev" });
777
+ }
778
+ if (availableEnvs.includes("mainnet-alpha")) {
779
+ choices.push({
780
+ name: "mainnet-alpha - Ethereum mainnet (\u26A0\uFE0F uses real funds)",
781
+ value: "mainnet-alpha"
782
+ });
783
+ }
784
+ if (choices.length === 0) {
785
+ throw new Error("No environments available in this build");
786
+ }
787
+ const env = await select({
788
+ message: "Select environment:",
789
+ choices,
790
+ default: defaultEnv
791
+ });
792
+ return env;
793
+ }
733
794
  var MAX_DESCRIPTION_LENGTH = 1e3;
734
795
  var MAX_IMAGE_SIZE = 4 * 1024 * 1024;
735
796
  var VALID_IMAGE_EXTENSIONS = [".jpg", ".jpeg", ".png"];
@@ -957,7 +1018,8 @@ var commonFlags = {
957
1018
  environment: Flags.string({
958
1019
  required: false,
959
1020
  description: "Deployment environment to use",
960
- env: "ECLOUD_ENV"
1021
+ env: "ECLOUD_ENV",
1022
+ default: async () => getDefaultEnvironment() || (getBuildType3() === "dev" ? "sepolia-dev" : "sepolia")
961
1023
  }),
962
1024
  "private-key": Flags.string({
963
1025
  required: false,
@@ -975,6 +1037,41 @@ var commonFlags = {
975
1037
  default: false
976
1038
  })
977
1039
  };
1040
+ async function validateCommonFlags(flags) {
1041
+ flags["environment"] = await getEnvironmentInteractive(flags["environment"]);
1042
+ flags["private-key"] = await getPrivateKeyInteractive(flags["private-key"]);
1043
+ return flags;
1044
+ }
1045
+
1046
+ // src/client.ts
1047
+ import {
1048
+ createComputeModule,
1049
+ createBillingModule,
1050
+ getEnvironmentConfig as getEnvironmentConfig2,
1051
+ requirePrivateKey,
1052
+ getPrivateKeyWithSource
1053
+ } from "@layr-labs/ecloud-sdk";
1054
+ async function createComputeClient(flags) {
1055
+ flags = await validateCommonFlags(flags);
1056
+ const environment = flags.environment;
1057
+ const environmentConfig = getEnvironmentConfig2(environment);
1058
+ const rpcUrl = flags["rpc-url"] || environmentConfig.defaultRPCURL;
1059
+ const { key: privateKey, source } = await requirePrivateKey({
1060
+ privateKey: flags["private-key"]
1061
+ });
1062
+ if (flags.verbose) {
1063
+ console.log(`Using private key from: ${source}`);
1064
+ }
1065
+ return createComputeModule({
1066
+ verbose: flags.verbose,
1067
+ privateKey,
1068
+ rpcUrl,
1069
+ environment,
1070
+ clientId: getClientId(),
1071
+ skipTelemetry: true
1072
+ // CLI already has telemetry, skip SDK telemetry
1073
+ });
1074
+ }
978
1075
 
979
1076
  // src/commands/compute/app/deploy.ts
980
1077
  import chalk from "chalk";
@@ -1045,16 +1142,11 @@ var AppDeploy = class _AppDeploy extends Command {
1045
1142
  async run() {
1046
1143
  return withTelemetry(this, async () => {
1047
1144
  const { flags } = await this.parse(_AppDeploy);
1048
- const logger = {
1049
- info: (msg) => this.log(msg),
1050
- warn: (msg) => this.warn(msg),
1051
- error: (msg) => this.error(msg),
1052
- debug: (msg) => flags.verbose && this.log(msg)
1053
- };
1054
- const environment = flags.environment || "sepolia";
1055
- const environmentConfig = getEnvironmentConfig2(environment);
1145
+ const compute = await createComputeClient(flags);
1146
+ const environment = flags.environment;
1147
+ const environmentConfig = getEnvironmentConfig3(environment);
1056
1148
  const rpcUrl = flags["rpc-url"] || environmentConfig.defaultRPCURL;
1057
- const privateKey = await getPrivateKeyInteractive(flags["private-key"]);
1149
+ const privateKey = flags["private-key"];
1058
1150
  const dockerfilePath = await getDockerfileInteractive(flags.dockerfile);
1059
1151
  const buildFromDockerfile = dockerfilePath !== "";
1060
1152
  const imageRef = await getImageReferenceInteractive(flags["image-ref"], buildFromDockerfile);
@@ -1078,22 +1170,15 @@ var AppDeploy = class _AppDeploy extends Command {
1078
1170
  flags["resource-usage-monitoring"]
1079
1171
  );
1080
1172
  const logVisibility = logSettings.publicLogs ? "public" : logSettings.logRedirect ? "private" : "off";
1081
- const { prepared, gasEstimate } = await prepareDeploy(
1082
- {
1083
- privateKey,
1084
- rpcUrl,
1085
- environment,
1086
- dockerfilePath,
1087
- imageRef,
1088
- envFilePath,
1089
- appName,
1090
- instanceType,
1091
- logVisibility,
1092
- resourceUsageMonitoring,
1093
- skipTelemetry: true
1094
- },
1095
- logger
1096
- );
1173
+ const { prepared, gasEstimate } = await compute.app.prepareDeploy({
1174
+ name: appName,
1175
+ dockerfile: dockerfilePath,
1176
+ imageRef,
1177
+ envFile: envFilePath,
1178
+ instanceType,
1179
+ logVisibility,
1180
+ resourceUsageMonitoring
1181
+ });
1097
1182
  this.log(`
1098
1183
  Estimated transaction cost: ${chalk.cyan(gasEstimate.maxCostEth)} ETH`);
1099
1184
  if (isMainnet(environmentConfig)) {
@@ -1104,16 +1189,10 @@ ${chalk.gray(`Deployment cancelled`)}`);
1104
1189
  return;
1105
1190
  }
1106
1191
  }
1107
- const res = await executeDeploy(
1108
- prepared,
1109
- {
1110
- maxFeePerGas: gasEstimate.maxFeePerGas,
1111
- maxPriorityFeePerGas: gasEstimate.maxPriorityFeePerGas
1112
- },
1113
- logger,
1114
- true
1115
- // skipTelemetry
1116
- );
1192
+ const res = await compute.app.executeDeploy(prepared, {
1193
+ maxFeePerGas: gasEstimate.maxFeePerGas,
1194
+ maxPriorityFeePerGas: gasEstimate.maxPriorityFeePerGas
1195
+ });
1117
1196
  if (!flags["skip-profile"]) {
1118
1197
  const hasProfileFlags = flags.website || flags.description || flags["x-url"] || flags.image;
1119
1198
  let profile = null;
@@ -1132,47 +1211,35 @@ ${chalk.gray(`Deployment cancelled`)}`);
1132
1211
  try {
1133
1212
  profile = await getAppProfileInteractive(appName, true) || null;
1134
1213
  } catch {
1135
- logger.debug("Profile collection skipped or cancelled");
1214
+ if (flags.verbose) {
1215
+ this.log("Profile collection skipped or cancelled");
1216
+ }
1136
1217
  }
1137
1218
  }
1138
1219
  if (profile) {
1139
- logger.info("Uploading app profile...");
1220
+ this.log("Uploading app profile...");
1140
1221
  try {
1141
- const userApiClient = new UserApiClient3(
1142
- environmentConfig,
1143
- privateKey,
1144
- rpcUrl,
1145
- getClientId()
1146
- );
1147
- await userApiClient.uploadAppProfile(
1148
- res.appId,
1149
- profile.name,
1150
- profile.website,
1151
- profile.description,
1152
- profile.xURL,
1153
- profile.imagePath
1154
- );
1155
- logger.info("\u2713 Profile uploaded successfully");
1222
+ await compute.app.setProfile(res.appId, profile);
1223
+ this.log("\u2713 Profile uploaded successfully");
1156
1224
  try {
1157
1225
  invalidateProfileCache(environment);
1158
1226
  } catch (cacheErr) {
1159
- logger.debug(`Failed to invalidate profile cache: ${cacheErr.message}`);
1227
+ if (flags.verbose) {
1228
+ this.log(`Failed to invalidate profile cache: ${cacheErr.message}`);
1229
+ }
1160
1230
  }
1161
1231
  } catch (uploadErr) {
1162
- logger.warn(`Failed to upload profile: ${uploadErr.message}`);
1232
+ this.warn(`Failed to upload profile: ${uploadErr.message}`);
1163
1233
  }
1164
1234
  }
1165
1235
  }
1166
- const ipAddress = await watchDeployment(
1167
- res.appId,
1168
- privateKey,
1169
- rpcUrl,
1170
- environment,
1171
- logger,
1172
- getClientId(),
1173
- true
1174
- // skipTelemetry - CLI already has telemetry
1175
- );
1236
+ const ipAddress = await compute.app.watchDeployment(res.appId);
1237
+ try {
1238
+ const cwd = process.env.INIT_CWD || process.cwd();
1239
+ setLinkedAppForDirectory(environment, cwd, res.appId);
1240
+ } catch (err) {
1241
+ logger.debug(`Failed to link directory to app: ${err.message}`);
1242
+ }
1176
1243
  this.log(
1177
1244
  `
1178
1245
  \u2705 ${chalk.green(`App deployed successfully ${chalk.bold(`(id: ${res.appId}, ip: ${ipAddress})`)}`)}`