@layr-labs/ecloud-cli 0.2.0 → 0.2.2-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.
- package/VERSION +2 -2
- package/dist/commands/auth/whoami.js +16 -3
- package/dist/commands/auth/whoami.js.map +1 -1
- package/dist/commands/billing/cancel.js +44 -5
- package/dist/commands/billing/cancel.js.map +1 -1
- package/dist/commands/billing/status.js +44 -5
- package/dist/commands/billing/status.js.map +1 -1
- package/dist/commands/billing/subscribe.js +44 -5
- package/dist/commands/billing/subscribe.js.map +1 -1
- package/dist/commands/compute/app/create.js +16 -3
- package/dist/commands/compute/app/create.js.map +1 -1
- package/dist/commands/compute/app/deploy.js +120 -25
- package/dist/commands/compute/app/deploy.js.map +1 -1
- package/dist/commands/compute/app/info.js +124 -35
- package/dist/commands/compute/app/info.js.map +1 -1
- package/dist/commands/compute/app/list.js +78 -17
- package/dist/commands/compute/app/list.js.map +1 -1
- package/dist/commands/compute/app/logs.js +69 -28
- package/dist/commands/compute/app/logs.js.map +1 -1
- package/dist/commands/compute/app/profile/set.js +109 -40
- package/dist/commands/compute/app/profile/set.js.map +1 -1
- package/dist/commands/compute/app/releases.js +82 -120
- package/dist/commands/compute/app/releases.js.map +1 -1
- package/dist/commands/compute/app/start.js +77 -35
- package/dist/commands/compute/app/start.js.map +1 -1
- package/dist/commands/compute/app/stop.js +77 -35
- package/dist/commands/compute/app/stop.js.map +1 -1
- package/dist/commands/compute/app/terminate.js +77 -35
- package/dist/commands/compute/app/terminate.js.map +1 -1
- package/dist/commands/compute/app/upgrade.js +117 -39
- package/dist/commands/compute/app/upgrade.js.map +1 -1
- package/dist/commands/compute/build/info.js +56 -16
- package/dist/commands/compute/build/info.js.map +1 -1
- package/dist/commands/compute/build/list.js +72 -67
- package/dist/commands/compute/build/list.js.map +1 -1
- package/dist/commands/compute/build/logs.js +55 -13
- package/dist/commands/compute/build/logs.js.map +1 -1
- package/dist/commands/compute/build/status.js +55 -13
- package/dist/commands/compute/build/status.js.map +1 -1
- package/dist/commands/compute/build/submit.js +68 -9
- package/dist/commands/compute/build/submit.js.map +1 -1
- package/dist/commands/compute/build/verify.js +55 -13
- package/dist/commands/compute/build/verify.js.map +1 -1
- package/dist/commands/compute/environment/set.js +20 -7
- package/dist/commands/compute/environment/set.js.map +1 -1
- package/dist/commands/compute/undelegate.js +46 -10
- package/dist/commands/compute/undelegate.js.map +1 -1
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/commands/compute/app/upgrade.ts
|
|
4
4
|
import { Command, Args, Flags as Flags2 } from "@oclif/core";
|
|
5
|
-
import { getEnvironmentConfig as
|
|
5
|
+
import { getEnvironmentConfig as getEnvironmentConfig4, UserApiClient as UserApiClient3, isMainnet } from "@layr-labs/ecloud-sdk";
|
|
6
6
|
|
|
7
7
|
// src/telemetry.ts
|
|
8
8
|
import {
|
|
@@ -209,9 +209,9 @@ import fs3 from "fs";
|
|
|
209
209
|
import path3 from "path";
|
|
210
210
|
import os3 from "os";
|
|
211
211
|
import { isAddress as isAddress2 } from "viem";
|
|
212
|
-
import { privateKeyToAccount as
|
|
212
|
+
import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
213
213
|
import {
|
|
214
|
-
getEnvironmentConfig,
|
|
214
|
+
getEnvironmentConfig as getEnvironmentConfig2,
|
|
215
215
|
getAvailableEnvironments,
|
|
216
216
|
isEnvironmentAvailable,
|
|
217
217
|
getAllAppsByDeveloper as getAllAppsByDeveloper2,
|
|
@@ -228,12 +228,43 @@ import {
|
|
|
228
228
|
|
|
229
229
|
// src/utils/appResolver.ts
|
|
230
230
|
import { isAddress } from "viem";
|
|
231
|
-
import { privateKeyToAccount } from "viem/accounts";
|
|
231
|
+
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
232
232
|
import {
|
|
233
233
|
UserApiClient,
|
|
234
234
|
getAllAppsByDeveloper
|
|
235
235
|
} from "@layr-labs/ecloud-sdk";
|
|
236
236
|
|
|
237
|
+
// src/utils/viemClients.ts
|
|
238
|
+
import {
|
|
239
|
+
createPublicClient,
|
|
240
|
+
http
|
|
241
|
+
} from "viem";
|
|
242
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
243
|
+
import {
|
|
244
|
+
getEnvironmentConfig,
|
|
245
|
+
addHexPrefix,
|
|
246
|
+
createViemClients as sdkCreateViemClients,
|
|
247
|
+
getChainFromID
|
|
248
|
+
} from "@layr-labs/ecloud-sdk";
|
|
249
|
+
function createViemClients(options) {
|
|
250
|
+
const privateKey = addHexPrefix(options.privateKey);
|
|
251
|
+
const environmentConfig = getEnvironmentConfig(options.environment);
|
|
252
|
+
const rpcUrl = options.rpcUrl || environmentConfig.defaultRPCURL;
|
|
253
|
+
const chain = getChainFromID(environmentConfig.chainID);
|
|
254
|
+
const { publicClient, walletClient } = sdkCreateViemClients({
|
|
255
|
+
privateKey,
|
|
256
|
+
rpcUrl,
|
|
257
|
+
chainId: environmentConfig.chainID
|
|
258
|
+
});
|
|
259
|
+
const account = privateKeyToAccount(privateKey);
|
|
260
|
+
return {
|
|
261
|
+
publicClient,
|
|
262
|
+
walletClient,
|
|
263
|
+
chain,
|
|
264
|
+
address: account.address
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
237
268
|
// src/utils/appNames.ts
|
|
238
269
|
import * as fs2 from "fs";
|
|
239
270
|
import * as path2 from "path";
|
|
@@ -280,7 +311,7 @@ function listApps(environment) {
|
|
|
280
311
|
|
|
281
312
|
// src/utils/version.ts
|
|
282
313
|
function getCliVersion() {
|
|
283
|
-
return true ? "0.2.
|
|
314
|
+
return true ? "0.2.2-dev" : "0.0.0";
|
|
284
315
|
}
|
|
285
316
|
function getClientId() {
|
|
286
317
|
return `ecloud-cli/v${getCliVersion()}`;
|
|
@@ -303,7 +334,7 @@ async function getAppInfosChunked(userApiClient, appIds, addressCount) {
|
|
|
303
334
|
}
|
|
304
335
|
|
|
305
336
|
// src/utils/prompts.ts
|
|
306
|
-
function
|
|
337
|
+
function addHexPrefix2(value) {
|
|
307
338
|
if (value.startsWith("0x")) {
|
|
308
339
|
return value;
|
|
309
340
|
}
|
|
@@ -848,7 +879,7 @@ async function getOrPromptAppID(appIDOrOptions, environment) {
|
|
|
848
879
|
};
|
|
849
880
|
}
|
|
850
881
|
if (options.appID) {
|
|
851
|
-
const normalized = typeof options.appID === "string" ?
|
|
882
|
+
const normalized = typeof options.appID === "string" ? addHexPrefix2(options.appID) : options.appID;
|
|
852
883
|
if (isAddress2(normalized)) {
|
|
853
884
|
return normalized;
|
|
854
885
|
}
|
|
@@ -864,7 +895,7 @@ async function getOrPromptAppID(appIDOrOptions, environment) {
|
|
|
864
895
|
const apps = listApps(options.environment);
|
|
865
896
|
const foundAppID = apps[options.appID];
|
|
866
897
|
if (foundAppID) {
|
|
867
|
-
return
|
|
898
|
+
return addHexPrefix2(foundAppID);
|
|
868
899
|
}
|
|
869
900
|
throw new Error(
|
|
870
901
|
`App name '${options.appID}' not found in environment '${options.environment}'`
|
|
@@ -875,18 +906,23 @@ async function getOrPromptAppID(appIDOrOptions, environment) {
|
|
|
875
906
|
async function getAppIDInteractive(options) {
|
|
876
907
|
const action = options.action || "view";
|
|
877
908
|
const environment = options.environment || "sepolia";
|
|
878
|
-
const environmentConfig =
|
|
909
|
+
const environmentConfig = getEnvironmentConfig2(environment);
|
|
879
910
|
if (!options.privateKey || !options.rpcUrl) {
|
|
880
911
|
return getAppIDInteractiveFromRegistry(environment, action);
|
|
881
912
|
}
|
|
882
913
|
console.log(`
|
|
883
914
|
Select an app to ${action}:
|
|
884
915
|
`);
|
|
885
|
-
const privateKeyHex =
|
|
886
|
-
const account =
|
|
916
|
+
const privateKeyHex = addHexPrefix2(options.privateKey);
|
|
917
|
+
const account = privateKeyToAccount3(privateKeyHex);
|
|
887
918
|
const developerAddr = account.address;
|
|
919
|
+
const { publicClient, walletClient } = createViemClients({
|
|
920
|
+
privateKey: options.privateKey,
|
|
921
|
+
rpcUrl: options.rpcUrl,
|
|
922
|
+
environment
|
|
923
|
+
});
|
|
888
924
|
const { apps, appConfigs } = await getAllAppsByDeveloper2(
|
|
889
|
-
|
|
925
|
+
publicClient,
|
|
890
926
|
environmentConfig,
|
|
891
927
|
developerAddr
|
|
892
928
|
);
|
|
@@ -899,9 +935,9 @@ Select an app to ${action}:
|
|
|
899
935
|
try {
|
|
900
936
|
const userApiClient = new UserApiClient2(
|
|
901
937
|
environmentConfig,
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
getClientId()
|
|
938
|
+
walletClient,
|
|
939
|
+
publicClient,
|
|
940
|
+
{ clientId: getClientId() }
|
|
905
941
|
);
|
|
906
942
|
const appInfos = await getAppInfosChunked(userApiClient, apps);
|
|
907
943
|
const freshProfiles = {};
|
|
@@ -1025,14 +1061,14 @@ async function getAppIDInteractiveFromRegistry(environment, action) {
|
|
|
1025
1061
|
if (!value) {
|
|
1026
1062
|
return "App ID or name cannot be empty";
|
|
1027
1063
|
}
|
|
1028
|
-
const normalized2 =
|
|
1064
|
+
const normalized2 = addHexPrefix2(value);
|
|
1029
1065
|
if (isAddress2(normalized2)) {
|
|
1030
1066
|
return true;
|
|
1031
1067
|
}
|
|
1032
1068
|
return "Invalid app ID address";
|
|
1033
1069
|
}
|
|
1034
1070
|
});
|
|
1035
|
-
const normalized =
|
|
1071
|
+
const normalized = addHexPrefix2(appIDInput);
|
|
1036
1072
|
if (isAddress2(normalized)) {
|
|
1037
1073
|
return normalized;
|
|
1038
1074
|
}
|
|
@@ -1068,7 +1104,7 @@ Select an app to ${action}:`);
|
|
|
1068
1104
|
if (!value) {
|
|
1069
1105
|
return "App ID or name cannot be empty";
|
|
1070
1106
|
}
|
|
1071
|
-
const normalized2 =
|
|
1107
|
+
const normalized2 = addHexPrefix2(value);
|
|
1072
1108
|
if (isAddress2(normalized2)) {
|
|
1073
1109
|
return true;
|
|
1074
1110
|
}
|
|
@@ -1078,17 +1114,17 @@ Select an app to ${action}:`);
|
|
|
1078
1114
|
return "Invalid app ID or name not found";
|
|
1079
1115
|
}
|
|
1080
1116
|
});
|
|
1081
|
-
const normalized =
|
|
1117
|
+
const normalized = addHexPrefix2(appIDInput);
|
|
1082
1118
|
if (isAddress2(normalized)) {
|
|
1083
1119
|
return normalized;
|
|
1084
1120
|
}
|
|
1085
1121
|
const foundAppID = allApps[appIDInput];
|
|
1086
1122
|
if (foundAppID) {
|
|
1087
|
-
return
|
|
1123
|
+
return addHexPrefix2(foundAppID);
|
|
1088
1124
|
}
|
|
1089
1125
|
throw new Error(`Failed to resolve app ID from input: ${appIDInput}`);
|
|
1090
1126
|
}
|
|
1091
|
-
return
|
|
1127
|
+
return addHexPrefix2(selected);
|
|
1092
1128
|
}
|
|
1093
1129
|
async function getResourceUsageMonitoringInteractive(resourceUsageMonitoring) {
|
|
1094
1130
|
if (resourceUsageMonitoring) {
|
|
@@ -1150,7 +1186,7 @@ async function getPrivateKeyInteractive(privateKey) {
|
|
|
1150
1186
|
async function getEnvironmentInteractive(environment) {
|
|
1151
1187
|
if (environment) {
|
|
1152
1188
|
try {
|
|
1153
|
-
|
|
1189
|
+
getEnvironmentConfig2(environment);
|
|
1154
1190
|
if (!isEnvironmentAvailable(environment)) {
|
|
1155
1191
|
throw new Error(`Environment ${environment} is not available in this build`);
|
|
1156
1192
|
}
|
|
@@ -1163,7 +1199,7 @@ async function getEnvironmentInteractive(environment) {
|
|
|
1163
1199
|
const configDefaultEnv = getDefaultEnvironment();
|
|
1164
1200
|
if (configDefaultEnv && availableEnvs.includes(configDefaultEnv)) {
|
|
1165
1201
|
try {
|
|
1166
|
-
|
|
1202
|
+
getEnvironmentConfig2(configDefaultEnv);
|
|
1167
1203
|
defaultEnv = configDefaultEnv;
|
|
1168
1204
|
} catch {
|
|
1169
1205
|
}
|
|
@@ -1230,14 +1266,14 @@ import {
|
|
|
1230
1266
|
createComputeModule,
|
|
1231
1267
|
createBillingModule,
|
|
1232
1268
|
createBuildModule,
|
|
1233
|
-
getEnvironmentConfig as
|
|
1269
|
+
getEnvironmentConfig as getEnvironmentConfig3,
|
|
1234
1270
|
requirePrivateKey,
|
|
1235
1271
|
getPrivateKeyWithSource
|
|
1236
1272
|
} from "@layr-labs/ecloud-sdk";
|
|
1237
1273
|
async function createComputeClient(flags) {
|
|
1238
1274
|
flags = await validateCommonFlags(flags);
|
|
1239
1275
|
const environment = flags.environment;
|
|
1240
|
-
const environmentConfig =
|
|
1276
|
+
const environmentConfig = getEnvironmentConfig3(environment);
|
|
1241
1277
|
const rpcUrl = flags["rpc-url"] || environmentConfig.defaultRPCURL;
|
|
1242
1278
|
const { key: privateKey, source } = await requirePrivateKey({
|
|
1243
1279
|
privateKey: flags["private-key"]
|
|
@@ -1245,10 +1281,15 @@ async function createComputeClient(flags) {
|
|
|
1245
1281
|
if (flags.verbose) {
|
|
1246
1282
|
console.log(`Using private key from: ${source}`);
|
|
1247
1283
|
}
|
|
1248
|
-
|
|
1249
|
-
verbose: flags.verbose,
|
|
1284
|
+
const { walletClient, publicClient } = createViemClients({
|
|
1250
1285
|
privateKey,
|
|
1251
1286
|
rpcUrl,
|
|
1287
|
+
environment
|
|
1288
|
+
});
|
|
1289
|
+
return createComputeModule({
|
|
1290
|
+
verbose: flags.verbose,
|
|
1291
|
+
walletClient,
|
|
1292
|
+
publicClient,
|
|
1252
1293
|
environment,
|
|
1253
1294
|
clientId: getClientId(),
|
|
1254
1295
|
skipTelemetry: true
|
|
@@ -1257,10 +1298,21 @@ async function createComputeClient(flags) {
|
|
|
1257
1298
|
}
|
|
1258
1299
|
async function createBuildClient(flags) {
|
|
1259
1300
|
flags = await validateCommonFlags(flags, { requirePrivateKey: false });
|
|
1301
|
+
const environment = flags.environment || "mainnet";
|
|
1302
|
+
const environmentConfig = getEnvironmentConfig3(environment);
|
|
1303
|
+
const rpcUrl = flags["rpc-url"] || environmentConfig.defaultRPCURL;
|
|
1304
|
+
let walletClient;
|
|
1305
|
+
if (flags["private-key"]) {
|
|
1306
|
+
walletClient = createViemClients({
|
|
1307
|
+
privateKey: flags["private-key"],
|
|
1308
|
+
rpcUrl,
|
|
1309
|
+
environment
|
|
1310
|
+
}).walletClient;
|
|
1311
|
+
}
|
|
1260
1312
|
return createBuildModule({
|
|
1261
1313
|
verbose: flags.verbose,
|
|
1262
|
-
|
|
1263
|
-
environment
|
|
1314
|
+
walletClient,
|
|
1315
|
+
environment,
|
|
1264
1316
|
clientId: getClientId(),
|
|
1265
1317
|
skipTelemetry: true
|
|
1266
1318
|
// CLI already has telemetry, skip SDK telemetry
|
|
@@ -1345,6 +1397,17 @@ async function runVerifiableBuildAndVerify(client, request, options = {}) {
|
|
|
1345
1397
|
return { build, verified: verify };
|
|
1346
1398
|
}
|
|
1347
1399
|
|
|
1400
|
+
// src/utils/dashboard.ts
|
|
1401
|
+
var DASHBOARD_URLS = {
|
|
1402
|
+
"sepolia-dev": "https://compute-dashboard-sepolia-dev.vercel.app",
|
|
1403
|
+
sepolia: "https://verify-sepolia.eigencloud.xyz",
|
|
1404
|
+
"mainnet-alpha": "https://verify.eigencloud.xyz"
|
|
1405
|
+
};
|
|
1406
|
+
function getDashboardUrl(environment, appAddress) {
|
|
1407
|
+
const baseUrl = DASHBOARD_URLS[environment] || DASHBOARD_URLS["sepolia"];
|
|
1408
|
+
return `${baseUrl}/app/${appAddress}`;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1348
1411
|
// src/utils/dockerhub.ts
|
|
1349
1412
|
var DOCKERHUB_OWNER = "eigenlayer";
|
|
1350
1413
|
var DOCKERHUB_REPO = "eigencloud-containers";
|
|
@@ -1507,6 +1570,11 @@ var AppUpgrade = class _AppUpgrade extends Command {
|
|
|
1507
1570
|
"build-dependencies": Flags2.string({
|
|
1508
1571
|
description: "Dependency digests for verifiable build (git source mode) (sha256:...)",
|
|
1509
1572
|
multiple: true
|
|
1573
|
+
}),
|
|
1574
|
+
"build-caddyfile": Flags2.string({
|
|
1575
|
+
description: "Optional path to Caddyfile inside the repo (relative to build context). If omitted, auto-detected from env file TLS settings",
|
|
1576
|
+
required: false,
|
|
1577
|
+
env: "ECLOUD_BUILD_CADDYFILE"
|
|
1510
1578
|
})
|
|
1511
1579
|
};
|
|
1512
1580
|
async run() {
|
|
@@ -1514,7 +1582,7 @@ var AppUpgrade = class _AppUpgrade extends Command {
|
|
|
1514
1582
|
const { args, flags } = await this.parse(_AppUpgrade);
|
|
1515
1583
|
const compute = await createComputeClient(flags);
|
|
1516
1584
|
const environment = flags.environment;
|
|
1517
|
-
const environmentConfig =
|
|
1585
|
+
const environmentConfig = getEnvironmentConfig4(environment);
|
|
1518
1586
|
const rpcUrl = flags["rpc-url"] || environmentConfig.defaultRPCURL;
|
|
1519
1587
|
const privateKey = flags["private-key"];
|
|
1520
1588
|
const appID = await getOrPromptAppID({
|
|
@@ -1575,7 +1643,7 @@ var AppUpgrade = class _AppUpgrade extends Command {
|
|
|
1575
1643
|
repoUrl: flags.repo,
|
|
1576
1644
|
gitRef: flags.commit,
|
|
1577
1645
|
dockerfilePath: flags["build-dockerfile"],
|
|
1578
|
-
caddyfilePath:
|
|
1646
|
+
caddyfilePath: flags["build-caddyfile"],
|
|
1579
1647
|
buildContextPath: flags["build-context"],
|
|
1580
1648
|
dependencies: flags["build-dependencies"]
|
|
1581
1649
|
} : await promptVerifiableGitSourceInputs();
|
|
@@ -1645,11 +1713,16 @@ var AppUpgrade = class _AppUpgrade extends Command {
|
|
|
1645
1713
|
envFilePath = envFilePath ?? await getEnvFileInteractive(flags["env-file"]);
|
|
1646
1714
|
let currentInstanceType = "";
|
|
1647
1715
|
try {
|
|
1648
|
-
const
|
|
1649
|
-
environmentConfig,
|
|
1716
|
+
const { publicClient, walletClient } = createViemClients({
|
|
1650
1717
|
privateKey,
|
|
1651
1718
|
rpcUrl,
|
|
1652
|
-
|
|
1719
|
+
environment: environmentConfig.name
|
|
1720
|
+
});
|
|
1721
|
+
const userApiClient = new UserApiClient3(
|
|
1722
|
+
environmentConfig,
|
|
1723
|
+
walletClient,
|
|
1724
|
+
publicClient,
|
|
1725
|
+
{ clientId: getClientId() }
|
|
1653
1726
|
);
|
|
1654
1727
|
const infos = await userApiClient.getInfos([appID], 1);
|
|
1655
1728
|
if (infos.length > 0) {
|
|
@@ -1699,10 +1772,7 @@ ${chalk.gray(`Upgrade cancelled`)}`);
|
|
|
1699
1772
|
return;
|
|
1700
1773
|
}
|
|
1701
1774
|
}
|
|
1702
|
-
const res = await compute.app.executeUpgrade(prepared,
|
|
1703
|
-
maxFeePerGas: gasEstimate.maxFeePerGas,
|
|
1704
|
-
maxPriorityFeePerGas: gasEstimate.maxPriorityFeePerGas
|
|
1705
|
-
});
|
|
1775
|
+
const res = await compute.app.executeUpgrade(prepared, gasEstimate);
|
|
1706
1776
|
await compute.app.watchUpgrade(res.appId);
|
|
1707
1777
|
try {
|
|
1708
1778
|
const cwd = process.env.INIT_CWD || process.cwd();
|
|
@@ -1714,12 +1784,20 @@ ${chalk.gray(`Upgrade cancelled`)}`);
|
|
|
1714
1784
|
`
|
|
1715
1785
|
\u2705 ${chalk.green(`App upgraded successfully ${chalk.bold(`(id: ${res.appId}, image: ${res.imageRef})`)}`)}`
|
|
1716
1786
|
);
|
|
1787
|
+
const dashboardUrl = getDashboardUrl(environment, res.appId);
|
|
1788
|
+
this.log(`
|
|
1789
|
+
${chalk.gray("View your app:")} ${chalk.blue.underline(dashboardUrl)}`);
|
|
1717
1790
|
});
|
|
1718
1791
|
}
|
|
1719
1792
|
};
|
|
1720
1793
|
async function fetchAvailableInstanceTypes(environmentConfig, privateKey, rpcUrl) {
|
|
1721
1794
|
try {
|
|
1722
|
-
const
|
|
1795
|
+
const { publicClient, walletClient } = createViemClients({
|
|
1796
|
+
privateKey,
|
|
1797
|
+
rpcUrl,
|
|
1798
|
+
environment: environmentConfig.name
|
|
1799
|
+
});
|
|
1800
|
+
const userApiClient = new UserApiClient3(environmentConfig, walletClient, publicClient, { clientId: getClientId() });
|
|
1723
1801
|
const skuList = await userApiClient.getSKUs();
|
|
1724
1802
|
if (skuList.skus.length === 0) {
|
|
1725
1803
|
throw new Error("No instance types available from server");
|