@layr-labs/ecloud-cli 0.2.0-dev.1 → 0.2.0-dev.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.
- package/VERSION +2 -2
- package/dist/commands/auth/generate.js +2 -2
- package/dist/commands/auth/generate.js.map +1 -1
- package/dist/commands/auth/login.js.map +1 -1
- package/dist/commands/auth/logout.js.map +1 -1
- package/dist/commands/auth/migrate.js.map +1 -1
- package/dist/commands/auth/whoami.js +3 -5
- package/dist/commands/auth/whoami.js.map +1 -1
- package/dist/commands/billing/cancel.js +3 -6
- package/dist/commands/billing/cancel.js.map +1 -1
- package/dist/commands/billing/status.js +3 -6
- package/dist/commands/billing/status.js.map +1 -1
- package/dist/commands/billing/subscribe.js +7 -12
- package/dist/commands/billing/subscribe.js.map +1 -1
- package/dist/commands/compute/app/create.js.map +1 -1
- package/dist/commands/compute/app/deploy.js +86 -614
- package/dist/commands/compute/app/deploy.js.map +1 -1
- package/dist/commands/compute/app/info.js +10 -59
- package/dist/commands/compute/app/info.js.map +1 -1
- package/dist/commands/compute/app/list.js +9 -10
- package/dist/commands/compute/app/list.js.map +1 -1
- package/dist/commands/compute/app/logs.js +11 -61
- package/dist/commands/compute/app/logs.js.map +1 -1
- package/dist/commands/compute/app/profile/set.js +20 -145
- package/dist/commands/compute/app/profile/set.js.map +1 -1
- package/dist/commands/compute/app/start.js +11 -61
- package/dist/commands/compute/app/start.js.map +1 -1
- package/dist/commands/compute/app/stop.js +11 -61
- package/dist/commands/compute/app/stop.js.map +1 -1
- package/dist/commands/compute/app/terminate.js +11 -61
- package/dist/commands/compute/app/terminate.js.map +1 -1
- package/dist/commands/compute/app/upgrade.js +52 -615
- package/dist/commands/compute/app/upgrade.js.map +1 -1
- package/dist/commands/compute/environment/list.js.map +1 -1
- package/dist/commands/compute/environment/set.js.map +1 -1
- package/dist/commands/compute/environment/show.js.map +1 -1
- package/dist/commands/compute/undelegate.js +9 -11
- package/dist/commands/compute/undelegate.js.map +1 -1
- package/dist/commands/telemetry/disable.js.map +1 -1
- package/dist/commands/telemetry/enable.js.map +1 -1
- package/dist/commands/telemetry/status.js.map +1 -1
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/commands/version.js.map +1 -1
- package/package.json +2 -7
- package/dist/commands/compute/app/releases.js +0 -1111
- package/dist/commands/compute/app/releases.js.map +0 -1
- package/dist/commands/compute/build/info.js +0 -500
- package/dist/commands/compute/build/info.js.map +0 -1
- package/dist/commands/compute/build/list.js +0 -494
- package/dist/commands/compute/build/list.js.map +0 -1
- package/dist/commands/compute/build/logs.js +0 -459
- package/dist/commands/compute/build/logs.js.map +0 -1
- package/dist/commands/compute/build/status.js +0 -481
- package/dist/commands/compute/build/status.js.map +0 -1
- package/dist/commands/compute/build/submit.js +0 -618
- package/dist/commands/compute/build/submit.js.map +0 -1
- package/dist/commands/compute/build/verify.js +0 -439
- package/dist/commands/compute/build/verify.js.map +0 -1
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
// src/commands/compute/app/upgrade.ts
|
|
4
4
|
import { Command, Args, Flags as Flags2 } from "@oclif/core";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getEnvironmentConfig as getEnvironmentConfig2,
|
|
7
|
+
UserApiClient as UserApiClient3,
|
|
8
|
+
isMainnet,
|
|
9
|
+
prepareUpgrade,
|
|
10
|
+
executeUpgrade,
|
|
11
|
+
watchUpgrade
|
|
12
|
+
} from "@layr-labs/ecloud-sdk";
|
|
6
13
|
|
|
7
14
|
// src/telemetry.ts
|
|
8
15
|
import {
|
|
@@ -64,42 +71,6 @@ function saveGlobalConfig(config) {
|
|
|
64
71
|
const content = dumpYaml(config, { lineWidth: -1 });
|
|
65
72
|
fs.writeFileSync(configPath, content, { mode: 420 });
|
|
66
73
|
}
|
|
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 getLinkedAppForDirectory(environment, directoryPath) {
|
|
76
|
-
if (!directoryPath) {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
const config = loadGlobalConfig();
|
|
80
|
-
const links = config.directory_links?.[environment];
|
|
81
|
-
if (!links) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
const normalizedPath = normalizeDirectoryPath(directoryPath);
|
|
85
|
-
const appId = links[normalizedPath];
|
|
86
|
-
return appId || null;
|
|
87
|
-
}
|
|
88
|
-
function setLinkedAppForDirectory(environment, directoryPath, appId) {
|
|
89
|
-
if (!directoryPath || !environment) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
const config = loadGlobalConfig();
|
|
93
|
-
if (!config.directory_links) {
|
|
94
|
-
config.directory_links = {};
|
|
95
|
-
}
|
|
96
|
-
if (!config.directory_links[environment]) {
|
|
97
|
-
config.directory_links[environment] = {};
|
|
98
|
-
}
|
|
99
|
-
const normalizedPath = normalizeDirectoryPath(directoryPath);
|
|
100
|
-
config.directory_links[environment][normalizedPath] = appId.toLowerCase();
|
|
101
|
-
saveGlobalConfig(config);
|
|
102
|
-
}
|
|
103
74
|
function getDefaultEnvironment() {
|
|
104
75
|
const config = loadGlobalConfig();
|
|
105
76
|
return config.default_environment;
|
|
@@ -201,7 +172,6 @@ async function withTelemetry(command, action) {
|
|
|
201
172
|
|
|
202
173
|
// src/flags.ts
|
|
203
174
|
import { Flags } from "@oclif/core";
|
|
204
|
-
import { getBuildType as getBuildType3 } from "@layr-labs/ecloud-sdk";
|
|
205
175
|
|
|
206
176
|
// src/utils/prompts.ts
|
|
207
177
|
import { input, select, password, confirm as inquirerConfirm } from "@inquirer/prompts";
|
|
@@ -280,7 +250,7 @@ function listApps(environment) {
|
|
|
280
250
|
|
|
281
251
|
// src/utils/version.ts
|
|
282
252
|
function getCliVersion() {
|
|
283
|
-
return true ? "0.2.0-dev.
|
|
253
|
+
return true ? "0.2.0-dev.2" : "0.0.0";
|
|
284
254
|
}
|
|
285
255
|
function getClientId() {
|
|
286
256
|
return `ecloud-cli/v${getCliVersion()}`;
|
|
@@ -336,113 +306,6 @@ Found Dockerfile in ${cwd}`);
|
|
|
336
306
|
throw new Error(`Unexpected choice: ${choice}`);
|
|
337
307
|
}
|
|
338
308
|
}
|
|
339
|
-
async function promptUseVerifiableBuild() {
|
|
340
|
-
return confirmWithDefault("Build from verifiable source?", false);
|
|
341
|
-
}
|
|
342
|
-
async function promptVerifiableSourceType() {
|
|
343
|
-
return select({
|
|
344
|
-
message: "Choose verifiable source type:",
|
|
345
|
-
choices: [
|
|
346
|
-
{ name: "Build from git source (public repo required)", value: "git" },
|
|
347
|
-
{ name: "Use a prebuilt verifiable image (eigencloud-containers)", value: "prebuilt" }
|
|
348
|
-
]
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
async function promptVerifiableGitSourceInputs() {
|
|
352
|
-
const repoUrl = (await input({
|
|
353
|
-
message: "Enter public git repository URL:",
|
|
354
|
-
default: "",
|
|
355
|
-
validate: (value) => {
|
|
356
|
-
if (!value.trim()) return "Repository URL is required";
|
|
357
|
-
try {
|
|
358
|
-
const url = new URL(value.trim());
|
|
359
|
-
if (url.protocol !== "https:") return "Repository URL must start with https://";
|
|
360
|
-
if (url.hostname.toLowerCase() !== "github.com")
|
|
361
|
-
return "Repository URL must be a public GitHub HTTPS URL (github.com)";
|
|
362
|
-
const parts = url.pathname.replace(/\/+$/, "").split("/").filter(Boolean);
|
|
363
|
-
if (parts.length < 2) return "Repository URL must be https://github.com/<owner>/<repo>";
|
|
364
|
-
const [owner, repo] = parts;
|
|
365
|
-
if (!owner || !repo) return "Repository URL must be https://github.com/<owner>/<repo>";
|
|
366
|
-
if (repo.toLowerCase() === "settings") return "Repository URL looks invalid";
|
|
367
|
-
if (url.search || url.hash)
|
|
368
|
-
return "Repository URL must not include query params or fragments";
|
|
369
|
-
} catch {
|
|
370
|
-
return "Invalid URL format";
|
|
371
|
-
}
|
|
372
|
-
return true;
|
|
373
|
-
}
|
|
374
|
-
})).trim();
|
|
375
|
-
const gitRef = (await input({
|
|
376
|
-
message: "Enter git commit SHA (40 hex chars):",
|
|
377
|
-
default: "",
|
|
378
|
-
validate: (value) => {
|
|
379
|
-
const trimmed = value.trim();
|
|
380
|
-
if (!trimmed) return "Commit SHA is required";
|
|
381
|
-
if (!/^[0-9a-f]{40}$/i.test(trimmed))
|
|
382
|
-
return "Commit must be a 40-character hexadecimal SHA";
|
|
383
|
-
return true;
|
|
384
|
-
}
|
|
385
|
-
})).trim();
|
|
386
|
-
const buildContextPath = (await input({
|
|
387
|
-
message: "Enter build context path (relative to repo):",
|
|
388
|
-
default: ".",
|
|
389
|
-
validate: (value) => value.trim() ? true : "Build context path cannot be empty"
|
|
390
|
-
})).trim();
|
|
391
|
-
const dockerfilePath = (await input({
|
|
392
|
-
message: "Enter Dockerfile path (relative to build context):",
|
|
393
|
-
default: "Dockerfile",
|
|
394
|
-
validate: (value) => value.trim() ? true : "Dockerfile path cannot be empty"
|
|
395
|
-
})).trim();
|
|
396
|
-
const caddyfileRaw = (await input({
|
|
397
|
-
message: "Enter Caddyfile path (relative to build context, optional):",
|
|
398
|
-
default: "",
|
|
399
|
-
validate: (value) => {
|
|
400
|
-
const trimmed = value.trim();
|
|
401
|
-
if (!trimmed) return true;
|
|
402
|
-
if (trimmed.includes("..")) return "Caddyfile path must not contain '..'";
|
|
403
|
-
return true;
|
|
404
|
-
}
|
|
405
|
-
})).trim();
|
|
406
|
-
const depsRaw = (await input({
|
|
407
|
-
message: "Enter dependency digests (comma-separated sha256:..., optional):",
|
|
408
|
-
default: "",
|
|
409
|
-
validate: (value) => {
|
|
410
|
-
const trimmed = value.trim();
|
|
411
|
-
if (!trimmed) return true;
|
|
412
|
-
const parts = trimmed.split(",").map((p) => p.trim()).filter(Boolean);
|
|
413
|
-
for (const p of parts) {
|
|
414
|
-
if (!/^sha256:[0-9a-f]{64}$/i.test(p)) {
|
|
415
|
-
return `Invalid dependency digest: ${p} (expected sha256:<64 hex>)`;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
return true;
|
|
419
|
-
}
|
|
420
|
-
})).trim();
|
|
421
|
-
const dependencies = depsRaw === "" ? [] : depsRaw.split(",").map((p) => p.trim()).filter(Boolean);
|
|
422
|
-
return {
|
|
423
|
-
repoUrl,
|
|
424
|
-
gitRef,
|
|
425
|
-
dockerfilePath,
|
|
426
|
-
caddyfilePath: caddyfileRaw === "" ? void 0 : caddyfileRaw,
|
|
427
|
-
buildContextPath,
|
|
428
|
-
dependencies
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
async function promptVerifiablePrebuiltImageRef() {
|
|
432
|
-
const ref = await input({
|
|
433
|
-
message: "Enter prebuilt verifiable image ref:",
|
|
434
|
-
default: "docker.io/eigenlayer/eigencloud-containers:",
|
|
435
|
-
validate: (value) => {
|
|
436
|
-
const trimmed = value.trim();
|
|
437
|
-
if (!trimmed) return "Image reference is required";
|
|
438
|
-
if (!/^docker\.io\/eigenlayer\/eigencloud-containers:[^@\s]+$/i.test(trimmed)) {
|
|
439
|
-
return "Image ref must match docker.io/eigenlayer/eigencloud-containers:<tag>";
|
|
440
|
-
}
|
|
441
|
-
return true;
|
|
442
|
-
}
|
|
443
|
-
});
|
|
444
|
-
return ref.trim();
|
|
445
|
-
}
|
|
446
309
|
function extractHostname(registry) {
|
|
447
310
|
let hostname = registry.replace(/^https?:\/\//, "");
|
|
448
311
|
hostname = hostname.split("/")[0];
|
|
@@ -582,9 +445,6 @@ function getDefaultAppName() {
|
|
|
582
445
|
return "myapp";
|
|
583
446
|
}
|
|
584
447
|
}
|
|
585
|
-
function getCurrentProjectPath() {
|
|
586
|
-
return process.env.INIT_CWD || process.cwd();
|
|
587
|
-
}
|
|
588
448
|
function suggestImageReference(registry, imageName, tag) {
|
|
589
449
|
imageName = imageName.toLowerCase().replace(/_/g, "-");
|
|
590
450
|
if (!tag) {
|
|
@@ -931,7 +791,6 @@ Select an app to ${action}:
|
|
|
931
791
|
switch (action) {
|
|
932
792
|
case "view":
|
|
933
793
|
case "view info for":
|
|
934
|
-
case "view releases for":
|
|
935
794
|
case "set profile for":
|
|
936
795
|
return true;
|
|
937
796
|
case "start":
|
|
@@ -960,19 +819,7 @@ Select an app to ${action}:
|
|
|
960
819
|
index: i
|
|
961
820
|
});
|
|
962
821
|
}
|
|
963
|
-
const linkedAppId = getLinkedAppForDirectory(environment, getCurrentProjectPath());
|
|
964
|
-
const normalizedLinkedAppId = linkedAppId ? linkedAppId.toLowerCase() : "";
|
|
965
822
|
appItems.sort((a, b) => {
|
|
966
|
-
if (normalizedLinkedAppId) {
|
|
967
|
-
const aLinked = String(a.addr).toLowerCase() === normalizedLinkedAppId;
|
|
968
|
-
const bLinked = String(b.addr).toLowerCase() === normalizedLinkedAppId;
|
|
969
|
-
if (aLinked && !bLinked) {
|
|
970
|
-
return -1;
|
|
971
|
-
}
|
|
972
|
-
if (bLinked && !aLinked) {
|
|
973
|
-
return 1;
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
823
|
const aPriority = getStatusPriority(a.status, false);
|
|
977
824
|
const bPriority = getStatusPriority(b.status, false);
|
|
978
825
|
if (aPriority !== bPriority) {
|
|
@@ -1038,18 +885,7 @@ async function getAppIDInteractiveFromRegistry(environment, action) {
|
|
|
1038
885
|
}
|
|
1039
886
|
throw new Error(`Invalid app ID address: ${appIDInput}`);
|
|
1040
887
|
}
|
|
1041
|
-
const
|
|
1042
|
-
const linkedAppId = getLinkedAppForDirectory(environment, getCurrentProjectPath());
|
|
1043
|
-
if (linkedAppId) {
|
|
1044
|
-
const linkedIndex = entries.findIndex(
|
|
1045
|
-
([, appId]) => String(appId).toLowerCase() === linkedAppId.toLowerCase()
|
|
1046
|
-
);
|
|
1047
|
-
if (linkedIndex > 0) {
|
|
1048
|
-
const [linkedEntry] = entries.splice(linkedIndex, 1);
|
|
1049
|
-
entries.unshift(linkedEntry);
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
const choices = entries.map(([name, appID]) => {
|
|
888
|
+
const choices = Object.entries(allApps).map(([name, appID]) => {
|
|
1053
889
|
const displayName = `${name} (${appID})`;
|
|
1054
890
|
return { name: displayName, value: appID };
|
|
1055
891
|
});
|
|
@@ -1127,8 +963,8 @@ async function getPrivateKeyInteractive(privateKey) {
|
|
|
1127
963
|
}
|
|
1128
964
|
return privateKey;
|
|
1129
965
|
}
|
|
1130
|
-
const { getPrivateKeyWithSource
|
|
1131
|
-
const result = await
|
|
966
|
+
const { getPrivateKeyWithSource } = await import("@layr-labs/ecloud-sdk");
|
|
967
|
+
const result = await getPrivateKeyWithSource({ privateKey: void 0 });
|
|
1132
968
|
if (result) {
|
|
1133
969
|
return result.key;
|
|
1134
970
|
}
|
|
@@ -1147,50 +983,6 @@ async function getPrivateKeyInteractive(privateKey) {
|
|
|
1147
983
|
});
|
|
1148
984
|
return key.trim();
|
|
1149
985
|
}
|
|
1150
|
-
async function getEnvironmentInteractive(environment) {
|
|
1151
|
-
if (environment) {
|
|
1152
|
-
try {
|
|
1153
|
-
getEnvironmentConfig(environment);
|
|
1154
|
-
if (!isEnvironmentAvailable(environment)) {
|
|
1155
|
-
throw new Error(`Environment ${environment} is not available in this build`);
|
|
1156
|
-
}
|
|
1157
|
-
return environment;
|
|
1158
|
-
} catch {
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
const availableEnvs = getAvailableEnvironments();
|
|
1162
|
-
let defaultEnv;
|
|
1163
|
-
const configDefaultEnv = getDefaultEnvironment();
|
|
1164
|
-
if (configDefaultEnv && availableEnvs.includes(configDefaultEnv)) {
|
|
1165
|
-
try {
|
|
1166
|
-
getEnvironmentConfig(configDefaultEnv);
|
|
1167
|
-
defaultEnv = configDefaultEnv;
|
|
1168
|
-
} catch {
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
const choices = [];
|
|
1172
|
-
if (availableEnvs.includes("sepolia")) {
|
|
1173
|
-
choices.push({ name: "sepolia - Ethereum Sepolia testnet", value: "sepolia" });
|
|
1174
|
-
}
|
|
1175
|
-
if (availableEnvs.includes("sepolia-dev")) {
|
|
1176
|
-
choices.push({ name: "sepolia-dev - Ethereum Sepolia testnet (dev)", value: "sepolia-dev" });
|
|
1177
|
-
}
|
|
1178
|
-
if (availableEnvs.includes("mainnet-alpha")) {
|
|
1179
|
-
choices.push({
|
|
1180
|
-
name: "mainnet-alpha - Ethereum mainnet (\u26A0\uFE0F uses real funds)",
|
|
1181
|
-
value: "mainnet-alpha"
|
|
1182
|
-
});
|
|
1183
|
-
}
|
|
1184
|
-
if (choices.length === 0) {
|
|
1185
|
-
throw new Error("No environments available in this build");
|
|
1186
|
-
}
|
|
1187
|
-
const env = await select({
|
|
1188
|
-
message: "Select environment:",
|
|
1189
|
-
choices,
|
|
1190
|
-
default: defaultEnv
|
|
1191
|
-
});
|
|
1192
|
-
return env;
|
|
1193
|
-
}
|
|
1194
986
|
var MAX_IMAGE_SIZE = 4 * 1024 * 1024;
|
|
1195
987
|
|
|
1196
988
|
// src/flags.ts
|
|
@@ -1198,8 +990,7 @@ var commonFlags = {
|
|
|
1198
990
|
environment: Flags.string({
|
|
1199
991
|
required: false,
|
|
1200
992
|
description: "Deployment environment to use",
|
|
1201
|
-
env: "ECLOUD_ENV"
|
|
1202
|
-
default: async () => getDefaultEnvironment() || (getBuildType3() === "dev" ? "sepolia-dev" : "sepolia")
|
|
993
|
+
env: "ECLOUD_ENV"
|
|
1203
994
|
}),
|
|
1204
995
|
"private-key": Flags.string({
|
|
1205
996
|
required: false,
|
|
@@ -1217,227 +1008,9 @@ var commonFlags = {
|
|
|
1217
1008
|
default: false
|
|
1218
1009
|
})
|
|
1219
1010
|
};
|
|
1220
|
-
async function validateCommonFlags(flags, options) {
|
|
1221
|
-
flags["environment"] = await getEnvironmentInteractive(flags["environment"]);
|
|
1222
|
-
if (options?.requirePrivateKey !== false) {
|
|
1223
|
-
flags["private-key"] = await getPrivateKeyInteractive(flags["private-key"]);
|
|
1224
|
-
}
|
|
1225
|
-
return flags;
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
// src/client.ts
|
|
1229
|
-
import {
|
|
1230
|
-
createComputeModule,
|
|
1231
|
-
createBillingModule,
|
|
1232
|
-
createBuildModule,
|
|
1233
|
-
getEnvironmentConfig as getEnvironmentConfig2,
|
|
1234
|
-
requirePrivateKey,
|
|
1235
|
-
getPrivateKeyWithSource
|
|
1236
|
-
} from "@layr-labs/ecloud-sdk";
|
|
1237
|
-
async function createComputeClient(flags) {
|
|
1238
|
-
flags = await validateCommonFlags(flags);
|
|
1239
|
-
const environment = flags.environment;
|
|
1240
|
-
const environmentConfig = getEnvironmentConfig2(environment);
|
|
1241
|
-
const rpcUrl = flags["rpc-url"] || environmentConfig.defaultRPCURL;
|
|
1242
|
-
const { key: privateKey, source } = await requirePrivateKey({
|
|
1243
|
-
privateKey: flags["private-key"]
|
|
1244
|
-
});
|
|
1245
|
-
if (flags.verbose) {
|
|
1246
|
-
console.log(`Using private key from: ${source}`);
|
|
1247
|
-
}
|
|
1248
|
-
return createComputeModule({
|
|
1249
|
-
verbose: flags.verbose,
|
|
1250
|
-
privateKey,
|
|
1251
|
-
rpcUrl,
|
|
1252
|
-
environment,
|
|
1253
|
-
clientId: getClientId(),
|
|
1254
|
-
skipTelemetry: true
|
|
1255
|
-
// CLI already has telemetry, skip SDK telemetry
|
|
1256
|
-
});
|
|
1257
|
-
}
|
|
1258
|
-
async function createBuildClient(flags) {
|
|
1259
|
-
flags = await validateCommonFlags(flags, { requirePrivateKey: false });
|
|
1260
|
-
return createBuildModule({
|
|
1261
|
-
verbose: flags.verbose,
|
|
1262
|
-
privateKey: flags["private-key"],
|
|
1263
|
-
environment: flags.environment,
|
|
1264
|
-
clientId: getClientId(),
|
|
1265
|
-
skipTelemetry: true
|
|
1266
|
-
// CLI already has telemetry, skip SDK telemetry
|
|
1267
|
-
});
|
|
1268
|
-
}
|
|
1269
1011
|
|
|
1270
1012
|
// src/commands/compute/app/upgrade.ts
|
|
1271
1013
|
import chalk from "chalk";
|
|
1272
|
-
|
|
1273
|
-
// src/utils/build.ts
|
|
1274
|
-
function formatSourceLink(repoUrl, gitRef) {
|
|
1275
|
-
const normalizedRepo = repoUrl.replace(/\.git$/, "");
|
|
1276
|
-
try {
|
|
1277
|
-
const url = new URL(normalizedRepo);
|
|
1278
|
-
const host = url.host.toLowerCase();
|
|
1279
|
-
if (host === "github.com") {
|
|
1280
|
-
const path4 = url.pathname.replace(/\/+$/, "");
|
|
1281
|
-
if (path4.split("/").filter(Boolean).length >= 2) {
|
|
1282
|
-
return `https://github.com${path4}/tree/${gitRef}`;
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
} catch {
|
|
1286
|
-
}
|
|
1287
|
-
return `${repoUrl}@${gitRef}`;
|
|
1288
|
-
}
|
|
1289
|
-
function extractRepoName(repoUrl) {
|
|
1290
|
-
const normalized = repoUrl.replace(/\.git$/, "");
|
|
1291
|
-
const match = normalized.match(/\/([^/]+?)$/);
|
|
1292
|
-
return match?.[1];
|
|
1293
|
-
}
|
|
1294
|
-
function formatDependencyLines(dependencies) {
|
|
1295
|
-
if (!dependencies || Object.keys(dependencies).length === 0) return [];
|
|
1296
|
-
const lines = [];
|
|
1297
|
-
lines.push("Dependencies (resolved builds):");
|
|
1298
|
-
for (const [digest, dep] of Object.entries(dependencies)) {
|
|
1299
|
-
const name = extractRepoName(dep.repoUrl);
|
|
1300
|
-
const depSource = formatSourceLink(dep.repoUrl, dep.gitRef);
|
|
1301
|
-
lines.push(` - ${digest} \u2713${name ? ` ${name}` : ""}`);
|
|
1302
|
-
lines.push(` ${depSource}`);
|
|
1303
|
-
}
|
|
1304
|
-
return lines;
|
|
1305
|
-
}
|
|
1306
|
-
function formatVerifiableBuildSummary(options) {
|
|
1307
|
-
const lines = [];
|
|
1308
|
-
lines.push("Build completed successfully \u2713");
|
|
1309
|
-
lines.push("");
|
|
1310
|
-
lines.push(`Image: ${options.imageUrl}`);
|
|
1311
|
-
lines.push(`Digest: ${options.imageDigest}`);
|
|
1312
|
-
lines.push(`Source: ${formatSourceLink(options.repoUrl, options.gitRef)}`);
|
|
1313
|
-
const depLines = formatDependencyLines(options.dependencies);
|
|
1314
|
-
if (depLines.length) {
|
|
1315
|
-
lines.push("");
|
|
1316
|
-
lines.push(...depLines);
|
|
1317
|
-
}
|
|
1318
|
-
lines.push("");
|
|
1319
|
-
lines.push("Provenance signature verified \u2713");
|
|
1320
|
-
lines.push(`provenance_signature: ${options.provenanceSignature}`);
|
|
1321
|
-
if (options.buildId) {
|
|
1322
|
-
lines.push("");
|
|
1323
|
-
lines.push(`Build ID: ${options.buildId}`);
|
|
1324
|
-
}
|
|
1325
|
-
return lines;
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
// src/utils/verifiableBuild.ts
|
|
1329
|
-
import { BUILD_STATUS } from "@layr-labs/ecloud-sdk";
|
|
1330
|
-
function assertCommitSha40(commit) {
|
|
1331
|
-
if (!/^[0-9a-f]{40}$/i.test(commit)) {
|
|
1332
|
-
throw new Error("Commit must be a 40-character hexadecimal SHA");
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
async function runVerifiableBuildAndVerify(client, request, options = {}) {
|
|
1336
|
-
const { buildId } = await client.submit(request);
|
|
1337
|
-
const completed = await client.waitForBuild(buildId, { onLog: options.onLog });
|
|
1338
|
-
if (completed.status !== BUILD_STATUS.SUCCESS) {
|
|
1339
|
-
throw new Error(`Build did not complete successfully (status: ${completed.status})`);
|
|
1340
|
-
}
|
|
1341
|
-
const [build, verify] = await Promise.all([client.get(buildId), client.verify(buildId)]);
|
|
1342
|
-
if (verify.status !== "verified") {
|
|
1343
|
-
throw new Error(`Provenance verification failed: ${verify.error}`);
|
|
1344
|
-
}
|
|
1345
|
-
return { build, verified: verify };
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
// src/utils/dockerhub.ts
|
|
1349
|
-
var DOCKERHUB_OWNER = "eigenlayer";
|
|
1350
|
-
var DOCKERHUB_REPO = "eigencloud-containers";
|
|
1351
|
-
function parseEigencloudContainersImageRef(imageRef) {
|
|
1352
|
-
const trimmed = imageRef.trim();
|
|
1353
|
-
const match = /^docker\.io\/([^/]+)\/([^:@]+):([^@\s]+)$/i.exec(trimmed);
|
|
1354
|
-
if (!match) {
|
|
1355
|
-
throw new Error("Image ref must match docker.io/eigenlayer/eigencloud-containers:<tag>");
|
|
1356
|
-
}
|
|
1357
|
-
const owner = match[1].toLowerCase();
|
|
1358
|
-
const repo = match[2].toLowerCase();
|
|
1359
|
-
const tag = match[3];
|
|
1360
|
-
if (owner !== DOCKERHUB_OWNER || repo !== DOCKERHUB_REPO) {
|
|
1361
|
-
throw new Error(`Image ref must be from docker.io/${DOCKERHUB_OWNER}/${DOCKERHUB_REPO}:<tag>`);
|
|
1362
|
-
}
|
|
1363
|
-
if (!tag.trim()) {
|
|
1364
|
-
throw new Error("Image tag cannot be empty");
|
|
1365
|
-
}
|
|
1366
|
-
return { owner, repo, tag };
|
|
1367
|
-
}
|
|
1368
|
-
function assertEigencloudContainersImageRef(imageRef) {
|
|
1369
|
-
parseEigencloudContainersImageRef(imageRef);
|
|
1370
|
-
}
|
|
1371
|
-
async function getDockerHubToken(owner, repo) {
|
|
1372
|
-
const url = new URL("https://auth.docker.io/token");
|
|
1373
|
-
url.searchParams.set("service", "registry.docker.io");
|
|
1374
|
-
url.searchParams.set("scope", `repository:${owner}/${repo}:pull`);
|
|
1375
|
-
const res = await fetch(url.toString(), { method: "GET" });
|
|
1376
|
-
if (!res.ok) {
|
|
1377
|
-
const body = await safeReadText(res);
|
|
1378
|
-
throw new Error(`Failed to fetch Docker Hub token (${res.status}): ${body || res.statusText}`);
|
|
1379
|
-
}
|
|
1380
|
-
const data = await res.json();
|
|
1381
|
-
if (!data.token) {
|
|
1382
|
-
throw new Error("Docker Hub token response missing 'token'");
|
|
1383
|
-
}
|
|
1384
|
-
return data.token;
|
|
1385
|
-
}
|
|
1386
|
-
async function safeReadText(res) {
|
|
1387
|
-
try {
|
|
1388
|
-
return (await res.text()).trim();
|
|
1389
|
-
} catch {
|
|
1390
|
-
return "";
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
async function resolveDockerHubImageDigest(imageRef) {
|
|
1394
|
-
const { owner, repo, tag } = parseEigencloudContainersImageRef(imageRef);
|
|
1395
|
-
const token = await getDockerHubToken(owner, repo);
|
|
1396
|
-
const manifestUrl = `https://registry-1.docker.io/v2/${owner}/${repo}/manifests/${encodeURIComponent(tag)}`;
|
|
1397
|
-
const headers = {
|
|
1398
|
-
Authorization: `Bearer ${token}`,
|
|
1399
|
-
Accept: "application/vnd.docker.distribution.manifest.v2+json"
|
|
1400
|
-
};
|
|
1401
|
-
let res = await fetch(manifestUrl, { method: "HEAD", headers });
|
|
1402
|
-
if (!res.ok) {
|
|
1403
|
-
res = await fetch(manifestUrl, { method: "GET", headers });
|
|
1404
|
-
}
|
|
1405
|
-
if (!res.ok) {
|
|
1406
|
-
const body = await safeReadText(res);
|
|
1407
|
-
throw new Error(
|
|
1408
|
-
`Failed to resolve digest for ${imageRef} (${res.status}) at ${manifestUrl}: ${body || res.statusText}`
|
|
1409
|
-
);
|
|
1410
|
-
}
|
|
1411
|
-
const digest = res.headers.get("docker-content-digest") || res.headers.get("Docker-Content-Digest");
|
|
1412
|
-
if (!digest) {
|
|
1413
|
-
throw new Error(
|
|
1414
|
-
`Docker registry response missing Docker-Content-Digest header for ${imageRef}`
|
|
1415
|
-
);
|
|
1416
|
-
}
|
|
1417
|
-
if (!/^sha256:[0-9a-f]{64}$/i.test(digest)) {
|
|
1418
|
-
throw new Error(`Unexpected digest format from Docker registry: ${digest}`);
|
|
1419
|
-
}
|
|
1420
|
-
return digest;
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1423
|
-
// src/utils/tls.ts
|
|
1424
|
-
import fs4 from "fs";
|
|
1425
|
-
function isTlsEnabledFromDomain(domain) {
|
|
1426
|
-
const d = (domain ?? "").trim();
|
|
1427
|
-
if (!d) return false;
|
|
1428
|
-
if (d.toLowerCase() === "localhost") return false;
|
|
1429
|
-
return true;
|
|
1430
|
-
}
|
|
1431
|
-
function isTlsEnabledFromEnvFile(envFilePath) {
|
|
1432
|
-
if (!envFilePath) return false;
|
|
1433
|
-
if (!fs4.existsSync(envFilePath)) return false;
|
|
1434
|
-
const envContent = fs4.readFileSync(envFilePath, "utf-8");
|
|
1435
|
-
const match = envContent.match(/^DOMAIN=(.+)$/m);
|
|
1436
|
-
if (!match?.[1]) return false;
|
|
1437
|
-
return isTlsEnabledFromDomain(match[1]);
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
// src/commands/compute/app/upgrade.ts
|
|
1441
1014
|
var AppUpgrade = class _AppUpgrade extends Command {
|
|
1442
1015
|
static description = "Upgrade existing deployment";
|
|
1443
1016
|
static args = {
|
|
@@ -1480,43 +1053,21 @@ var AppUpgrade = class _AppUpgrade extends Command {
|
|
|
1480
1053
|
description: "Resource usage monitoring: enable or disable",
|
|
1481
1054
|
options: ["enable", "disable"],
|
|
1482
1055
|
env: "ECLOUD_RESOURCE_USAGE_MONITORING"
|
|
1483
|
-
}),
|
|
1484
|
-
// Verifiable build flags
|
|
1485
|
-
verifiable: Flags2.boolean({
|
|
1486
|
-
description: "Enable verifiable build mode (either build from git source via --repo/--commit, or upgrade to a prebuilt verifiable image via --image-ref)",
|
|
1487
|
-
default: false
|
|
1488
|
-
}),
|
|
1489
|
-
repo: Flags2.string({
|
|
1490
|
-
description: "Git repository URL (required with --verifiable git source mode)",
|
|
1491
|
-
env: "ECLOUD_BUILD_REPO"
|
|
1492
|
-
}),
|
|
1493
|
-
commit: Flags2.string({
|
|
1494
|
-
description: "Git commit SHA (required with --verifiable git source mode)",
|
|
1495
|
-
env: "ECLOUD_BUILD_COMMIT"
|
|
1496
|
-
}),
|
|
1497
|
-
"build-dockerfile": Flags2.string({
|
|
1498
|
-
description: "Dockerfile path for verifiable build (git source mode)",
|
|
1499
|
-
default: "Dockerfile",
|
|
1500
|
-
env: "ECLOUD_BUILD_DOCKERFILE"
|
|
1501
|
-
}),
|
|
1502
|
-
"build-context": Flags2.string({
|
|
1503
|
-
description: "Build context path for verifiable build (git source mode)",
|
|
1504
|
-
default: ".",
|
|
1505
|
-
env: "ECLOUD_BUILD_CONTEXT"
|
|
1506
|
-
}),
|
|
1507
|
-
"build-dependencies": Flags2.string({
|
|
1508
|
-
description: "Dependency digests for verifiable build (git source mode) (sha256:...)",
|
|
1509
|
-
multiple: true
|
|
1510
1056
|
})
|
|
1511
1057
|
};
|
|
1512
1058
|
async run() {
|
|
1513
1059
|
return withTelemetry(this, async () => {
|
|
1514
1060
|
const { args, flags } = await this.parse(_AppUpgrade);
|
|
1515
|
-
const
|
|
1516
|
-
|
|
1517
|
-
|
|
1061
|
+
const logger = {
|
|
1062
|
+
info: (msg) => this.log(msg),
|
|
1063
|
+
warn: (msg) => this.warn(msg),
|
|
1064
|
+
error: (msg) => this.error(msg),
|
|
1065
|
+
debug: (msg) => flags.verbose && this.log(msg)
|
|
1066
|
+
};
|
|
1067
|
+
const environment = flags.environment || "sepolia";
|
|
1068
|
+
const environmentConfig = getEnvironmentConfig2(environment);
|
|
1518
1069
|
const rpcUrl = flags["rpc-url"] || environmentConfig.defaultRPCURL;
|
|
1519
|
-
const privateKey = flags["private-key"];
|
|
1070
|
+
const privateKey = await getPrivateKeyInteractive(flags["private-key"]);
|
|
1520
1071
|
const appID = await getOrPromptAppID({
|
|
1521
1072
|
appID: args["app-id"],
|
|
1522
1073
|
environment,
|
|
@@ -1524,125 +1075,10 @@ var AppUpgrade = class _AppUpgrade extends Command {
|
|
|
1524
1075
|
rpcUrl,
|
|
1525
1076
|
action: "upgrade"
|
|
1526
1077
|
});
|
|
1527
|
-
|
|
1528
|
-
const getBuildClient = async () => {
|
|
1529
|
-
if (buildClient) return buildClient;
|
|
1530
|
-
buildClient = await createBuildClient({
|
|
1531
|
-
...flags,
|
|
1532
|
-
"private-key": privateKey
|
|
1533
|
-
});
|
|
1534
|
-
return buildClient;
|
|
1535
|
-
};
|
|
1536
|
-
let verifiableImageUrl;
|
|
1537
|
-
let verifiableImageDigest;
|
|
1538
|
-
let verifiableMode = "none";
|
|
1539
|
-
let envFilePath;
|
|
1540
|
-
if (flags.verifiable) {
|
|
1541
|
-
if (flags.repo || flags.commit) {
|
|
1542
|
-
verifiableMode = "git";
|
|
1543
|
-
if (!flags.repo)
|
|
1544
|
-
this.error("--repo is required when using --verifiable (git source mode)");
|
|
1545
|
-
if (!flags.commit)
|
|
1546
|
-
this.error("--commit is required when using --verifiable (git source mode)");
|
|
1547
|
-
try {
|
|
1548
|
-
assertCommitSha40(flags.commit);
|
|
1549
|
-
} catch (e) {
|
|
1550
|
-
this.error(e?.message || String(e));
|
|
1551
|
-
}
|
|
1552
|
-
} else if (flags["image-ref"]) {
|
|
1553
|
-
verifiableMode = "prebuilt";
|
|
1554
|
-
try {
|
|
1555
|
-
assertEigencloudContainersImageRef(flags["image-ref"]);
|
|
1556
|
-
} catch (e) {
|
|
1557
|
-
this.error(e?.message || String(e));
|
|
1558
|
-
}
|
|
1559
|
-
} else {
|
|
1560
|
-
this.error(
|
|
1561
|
-
"When using --verifiable, you must provide either --repo/--commit or --image-ref"
|
|
1562
|
-
);
|
|
1563
|
-
}
|
|
1564
|
-
} else {
|
|
1565
|
-
if (!flags.dockerfile) {
|
|
1566
|
-
const useVerifiable = await promptUseVerifiableBuild();
|
|
1567
|
-
if (useVerifiable) {
|
|
1568
|
-
const sourceType = await promptVerifiableSourceType();
|
|
1569
|
-
verifiableMode = sourceType;
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
if (verifiableMode === "git") {
|
|
1574
|
-
const inputs = flags.verifiable ? {
|
|
1575
|
-
repoUrl: flags.repo,
|
|
1576
|
-
gitRef: flags.commit,
|
|
1577
|
-
dockerfilePath: flags["build-dockerfile"],
|
|
1578
|
-
caddyfilePath: void 0,
|
|
1579
|
-
buildContextPath: flags["build-context"],
|
|
1580
|
-
dependencies: flags["build-dependencies"]
|
|
1581
|
-
} : await promptVerifiableGitSourceInputs();
|
|
1582
|
-
envFilePath = await getEnvFileInteractive(flags["env-file"]);
|
|
1583
|
-
const includeTlsCaddyfile = isTlsEnabledFromEnvFile(envFilePath);
|
|
1584
|
-
if (includeTlsCaddyfile && !inputs.caddyfilePath) {
|
|
1585
|
-
inputs.caddyfilePath = "Caddyfile";
|
|
1586
|
-
}
|
|
1587
|
-
this.log(chalk.blue("Building from source with verifiable build..."));
|
|
1588
|
-
this.log("");
|
|
1589
|
-
const buildClient2 = await getBuildClient();
|
|
1590
|
-
const { build, verified } = await runVerifiableBuildAndVerify(buildClient2, inputs, {
|
|
1591
|
-
onLog: (chunk) => process.stdout.write(chunk)
|
|
1592
|
-
});
|
|
1593
|
-
if (!build.imageUrl || !build.imageDigest) {
|
|
1594
|
-
this.error(
|
|
1595
|
-
"Build completed but did not return imageUrl/imageDigest; cannot upgrade verifiable build"
|
|
1596
|
-
);
|
|
1597
|
-
}
|
|
1598
|
-
verifiableImageUrl = build.imageUrl;
|
|
1599
|
-
verifiableImageDigest = build.imageDigest;
|
|
1600
|
-
for (const line of formatVerifiableBuildSummary({
|
|
1601
|
-
buildId: build.buildId,
|
|
1602
|
-
imageUrl: build.imageUrl,
|
|
1603
|
-
imageDigest: build.imageDigest,
|
|
1604
|
-
repoUrl: build.repoUrl,
|
|
1605
|
-
gitRef: build.gitRef,
|
|
1606
|
-
dependencies: build.dependencies,
|
|
1607
|
-
provenanceSignature: verified.provenanceSignature
|
|
1608
|
-
})) {
|
|
1609
|
-
this.log(line);
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1612
|
-
if (verifiableMode === "prebuilt") {
|
|
1613
|
-
const imageRef2 = flags.verifiable ? flags["image-ref"] : await promptVerifiablePrebuiltImageRef();
|
|
1614
|
-
try {
|
|
1615
|
-
assertEigencloudContainersImageRef(imageRef2);
|
|
1616
|
-
} catch (e) {
|
|
1617
|
-
this.error(e?.message || String(e));
|
|
1618
|
-
}
|
|
1619
|
-
this.log(chalk.blue("Resolving and verifying prebuilt verifiable image..."));
|
|
1620
|
-
this.log("");
|
|
1621
|
-
const digest = await resolveDockerHubImageDigest(imageRef2);
|
|
1622
|
-
const buildClient2 = await getBuildClient();
|
|
1623
|
-
const verify = await buildClient2.verify(digest);
|
|
1624
|
-
if (verify.status !== "verified") {
|
|
1625
|
-
this.error(`Provenance verification failed: ${verify.error}`);
|
|
1626
|
-
}
|
|
1627
|
-
verifiableImageUrl = imageRef2;
|
|
1628
|
-
verifiableImageDigest = digest;
|
|
1629
|
-
for (const line of formatVerifiableBuildSummary({
|
|
1630
|
-
buildId: verify.buildId,
|
|
1631
|
-
imageUrl: imageRef2,
|
|
1632
|
-
imageDigest: digest,
|
|
1633
|
-
repoUrl: verify.repoUrl,
|
|
1634
|
-
gitRef: verify.gitRef,
|
|
1635
|
-
dependencies: void 0,
|
|
1636
|
-
provenanceSignature: verify.provenanceSignature
|
|
1637
|
-
})) {
|
|
1638
|
-
this.log(line);
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
const isVerifiable = verifiableMode !== "none";
|
|
1642
|
-
const dockerfilePath = isVerifiable ? "" : await getDockerfileInteractive(flags.dockerfile);
|
|
1078
|
+
const dockerfilePath = await getDockerfileInteractive(flags.dockerfile);
|
|
1643
1079
|
const buildFromDockerfile = dockerfilePath !== "";
|
|
1644
|
-
const imageRef =
|
|
1645
|
-
envFilePath =
|
|
1080
|
+
const imageRef = await getImageReferenceInteractive(flags["image-ref"], buildFromDockerfile);
|
|
1081
|
+
const envFilePath = await getEnvFileInteractive(flags["env-file"]);
|
|
1646
1082
|
let currentInstanceType = "";
|
|
1647
1083
|
try {
|
|
1648
1084
|
const userApiClient = new UserApiClient3(
|
|
@@ -1674,21 +1110,22 @@ var AppUpgrade = class _AppUpgrade extends Command {
|
|
|
1674
1110
|
flags["resource-usage-monitoring"]
|
|
1675
1111
|
);
|
|
1676
1112
|
const logVisibility = logSettings.publicLogs ? "public" : logSettings.logRedirect ? "private" : "off";
|
|
1677
|
-
const { prepared, gasEstimate } =
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1113
|
+
const { prepared, gasEstimate } = await prepareUpgrade(
|
|
1114
|
+
{
|
|
1115
|
+
appId: appID,
|
|
1116
|
+
privateKey,
|
|
1117
|
+
rpcUrl,
|
|
1118
|
+
environment,
|
|
1119
|
+
dockerfilePath,
|
|
1120
|
+
imageRef,
|
|
1121
|
+
envFilePath,
|
|
1122
|
+
instanceType,
|
|
1123
|
+
logVisibility,
|
|
1124
|
+
resourceUsageMonitoring,
|
|
1125
|
+
skipTelemetry: true
|
|
1126
|
+
},
|
|
1127
|
+
logger
|
|
1128
|
+
);
|
|
1692
1129
|
this.log(`
|
|
1693
1130
|
Estimated transaction cost: ${chalk.cyan(gasEstimate.maxCostEth)} ETH`);
|
|
1694
1131
|
if (isMainnet(environmentConfig)) {
|
|
@@ -1699,17 +1136,17 @@ ${chalk.gray(`Upgrade cancelled`)}`);
|
|
|
1699
1136
|
return;
|
|
1700
1137
|
}
|
|
1701
1138
|
}
|
|
1702
|
-
const res = await
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1139
|
+
const res = await executeUpgrade(
|
|
1140
|
+
prepared,
|
|
1141
|
+
{
|
|
1142
|
+
maxFeePerGas: gasEstimate.maxFeePerGas,
|
|
1143
|
+
maxPriorityFeePerGas: gasEstimate.maxPriorityFeePerGas
|
|
1144
|
+
},
|
|
1145
|
+
logger,
|
|
1146
|
+
true
|
|
1147
|
+
// skipTelemetry
|
|
1148
|
+
);
|
|
1149
|
+
await watchUpgrade(res.appId, privateKey, rpcUrl, environment, logger, getClientId(), true);
|
|
1713
1150
|
this.log(
|
|
1714
1151
|
`
|
|
1715
1152
|
\u2705 ${chalk.green(`App upgraded successfully ${chalk.bold(`(id: ${res.appId}, image: ${res.imageRef})`)}`)}`
|