@layr-labs/ecloud-sdk 0.2.0-dev.2 → 0.2.0
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/billing.cjs +1 -1
- package/dist/billing.cjs.map +1 -1
- package/dist/billing.d.cts +1 -1
- package/dist/billing.d.ts +1 -1
- package/dist/billing.js +2 -2
- package/dist/{chunk-ZEZS5CNB.js → chunk-CA5Y4OVI.js} +107 -31
- package/dist/chunk-CA5Y4OVI.js.map +1 -0
- package/dist/{chunk-2RORGPLX.js → chunk-ZDXN2WKP.js} +2 -2
- package/dist/chunk-ZDXN2WKP.js.map +1 -0
- package/dist/{chunk-4SKRNFKQ.js → chunk-ZTLKZMSW.js} +535 -105
- package/dist/chunk-ZTLKZMSW.js.map +1 -0
- package/dist/{compute-B_ibIORD.d.cts → compute-CF2HOXed.d.ts} +101 -15
- package/dist/{compute-gpepEsn3.d.ts → compute-CbmjA8kJ.d.cts} +101 -15
- package/dist/compute.cjs +851 -63
- package/dist/compute.cjs.map +1 -1
- package/dist/compute.d.cts +2 -2
- package/dist/compute.d.ts +2 -2
- package/dist/compute.js +2 -2
- package/dist/{index-D-SUX3IG.d.ts → index-D2QufVB9.d.cts} +130 -6
- package/dist/{index-D-SUX3IG.d.cts → index-D2QufVB9.d.ts} +130 -6
- package/dist/index.cjs +990 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +334 -231
- package/dist/index.d.ts +334 -231
- package/dist/index.js +376 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/dist/chunk-2RORGPLX.js.map +0 -1
- package/dist/chunk-4SKRNFKQ.js.map +0 -1
- package/dist/chunk-ZEZS5CNB.js.map +0 -1
package/dist/compute.cjs
CHANGED
|
@@ -40,6 +40,7 @@ module.exports = __toCommonJS(compute_exports);
|
|
|
40
40
|
|
|
41
41
|
// src/client/modules/compute/app/index.ts
|
|
42
42
|
var import_viem9 = require("viem");
|
|
43
|
+
var import_accounts5 = require("viem/accounts");
|
|
43
44
|
|
|
44
45
|
// src/client/common/config/environment.ts
|
|
45
46
|
var SEPOLIA_CHAIN_ID = 11155111;
|
|
@@ -114,7 +115,7 @@ function getEnvironmentConfig(environment, chainID) {
|
|
|
114
115
|
};
|
|
115
116
|
}
|
|
116
117
|
function getBuildType() {
|
|
117
|
-
const buildTimeType = true ? "
|
|
118
|
+
const buildTimeType = true ? "prod"?.toLowerCase() : void 0;
|
|
118
119
|
const runtimeType = process.env.BUILD_TYPE?.toLowerCase();
|
|
119
120
|
const buildType = buildTimeType || runtimeType;
|
|
120
121
|
if (buildType === "dev") {
|
|
@@ -162,6 +163,7 @@ async function buildDockerImage(buildContext, dockerfilePath, tag, logger) {
|
|
|
162
163
|
tag,
|
|
163
164
|
"-f",
|
|
164
165
|
dockerfilePath,
|
|
166
|
+
"--load",
|
|
165
167
|
"--progress=plain",
|
|
166
168
|
buildContext
|
|
167
169
|
];
|
|
@@ -287,7 +289,7 @@ async function pullDockerImage(docker, imageTag, platform2 = "linux/amd64", logg
|
|
|
287
289
|
var child_process2 = __toESM(require("child_process"), 1);
|
|
288
290
|
var import_child_process = require("child_process");
|
|
289
291
|
var import_util2 = require("util");
|
|
290
|
-
var
|
|
292
|
+
var execFileAsync = (0, import_util2.promisify)(import_child_process.execFile);
|
|
291
293
|
async function pushDockerImage(docker, imageRef, logger) {
|
|
292
294
|
logger?.info?.(`Pushing image ${imageRef}...`);
|
|
293
295
|
return new Promise((resolve2, reject) => {
|
|
@@ -328,9 +330,9 @@ async function pushDockerImage(docker, imageRef, logger) {
|
|
|
328
330
|
if (!output.includes("digest:") && !output.includes("pushed") && !output.includes("Pushed")) {
|
|
329
331
|
logger?.debug?.("No clear success indicator in push output, verifying...");
|
|
330
332
|
}
|
|
331
|
-
logger?.info?.("Image push completed successfully");
|
|
332
333
|
try {
|
|
333
334
|
await verifyImageExists(imageRef, logger);
|
|
335
|
+
logger?.info?.("Image push completed successfully");
|
|
334
336
|
resolve2();
|
|
335
337
|
} catch (error) {
|
|
336
338
|
reject(error);
|
|
@@ -354,7 +356,7 @@ async function verifyImageExists(imageRef, logger) {
|
|
|
354
356
|
let retries = 5;
|
|
355
357
|
while (retries > 0) {
|
|
356
358
|
try {
|
|
357
|
-
await
|
|
359
|
+
await execFileAsync("docker", ["manifest", "inspect", imageRef], {
|
|
358
360
|
maxBuffer: 10 * 1024 * 1024,
|
|
359
361
|
timeout: 1e4
|
|
360
362
|
// 10 second timeout
|
|
@@ -828,10 +830,10 @@ async function setupLayeredBuildDirectory(environmentConfig, layeredDockerfileCo
|
|
|
828
830
|
// src/client/common/registry/digest.ts
|
|
829
831
|
var child_process3 = __toESM(require("child_process"), 1);
|
|
830
832
|
var import_util3 = require("util");
|
|
831
|
-
var
|
|
833
|
+
var execFileAsync2 = (0, import_util3.promisify)(child_process3.execFile);
|
|
832
834
|
async function getImageDigestAndName(imageRef) {
|
|
833
835
|
try {
|
|
834
|
-
const { stdout } = await
|
|
836
|
+
const { stdout } = await execFileAsync2(
|
|
835
837
|
"docker",
|
|
836
838
|
["manifest", "inspect", imageRef],
|
|
837
839
|
{ maxBuffer: 10 * 1024 * 1024 }
|
|
@@ -871,7 +873,7 @@ function extractDigestFromMultiPlatform(manifest, imageRef) {
|
|
|
871
873
|
}
|
|
872
874
|
async function extractDigestFromSinglePlatform(manifest, imageRef) {
|
|
873
875
|
try {
|
|
874
|
-
const { stdout } = await
|
|
876
|
+
const { stdout } = await execFileAsync2("docker", ["inspect", imageRef], {
|
|
875
877
|
maxBuffer: 10 * 1024 * 1024
|
|
876
878
|
});
|
|
877
879
|
const inspectData = JSON.parse(stdout);
|
|
@@ -1169,6 +1171,67 @@ Please verify the image exists: docker manifest inspect ${finalImageRef}`
|
|
|
1169
1171
|
};
|
|
1170
1172
|
}
|
|
1171
1173
|
|
|
1174
|
+
// src/client/common/release/prebuilt.ts
|
|
1175
|
+
async function createReleaseFromImageDigest(options, logger) {
|
|
1176
|
+
const { imageRef, imageDigest, envFilePath, instanceType, environmentConfig, appId } = options;
|
|
1177
|
+
if (!/^sha256:[0-9a-f]{64}$/i.test(imageDigest)) {
|
|
1178
|
+
throw new Error(`imageDigest must be in format sha256:<64 hex>, got: ${imageDigest}`);
|
|
1179
|
+
}
|
|
1180
|
+
let publicEnv = {};
|
|
1181
|
+
let privateEnv = {};
|
|
1182
|
+
if (envFilePath) {
|
|
1183
|
+
logger.info("Parsing environment file...");
|
|
1184
|
+
const parsed = parseAndValidateEnvFile(envFilePath);
|
|
1185
|
+
publicEnv = parsed.public;
|
|
1186
|
+
privateEnv = parsed.private;
|
|
1187
|
+
} else {
|
|
1188
|
+
logger.info("Continuing without environment file");
|
|
1189
|
+
}
|
|
1190
|
+
publicEnv["EIGEN_MACHINE_TYPE_PUBLIC"] = instanceType;
|
|
1191
|
+
logger.info(`Instance type: ${instanceType}`);
|
|
1192
|
+
logger.info("Encrypting environment variables...");
|
|
1193
|
+
const { encryptionKey } = getKMSKeysForEnvironment(
|
|
1194
|
+
environmentConfig.name,
|
|
1195
|
+
environmentConfig.build
|
|
1196
|
+
);
|
|
1197
|
+
const protectedHeaders = getAppProtectedHeaders(appId);
|
|
1198
|
+
const privateEnvBytes = Buffer.from(JSON.stringify(privateEnv));
|
|
1199
|
+
const encryptedEnvStr = await encryptRSAOAEPAndAES256GCM(
|
|
1200
|
+
encryptionKey,
|
|
1201
|
+
privateEnvBytes,
|
|
1202
|
+
protectedHeaders
|
|
1203
|
+
);
|
|
1204
|
+
const digestHex = imageDigest.split(":")[1];
|
|
1205
|
+
const digestBytes = new Uint8Array(Buffer.from(digestHex, "hex"));
|
|
1206
|
+
if (digestBytes.length !== 32) {
|
|
1207
|
+
throw new Error(`Digest must be exactly 32 bytes, got ${digestBytes.length}`);
|
|
1208
|
+
}
|
|
1209
|
+
const registry = extractRegistryNameNoDocker(imageRef);
|
|
1210
|
+
return {
|
|
1211
|
+
rmsRelease: {
|
|
1212
|
+
artifacts: [{ digest: digestBytes, registry }],
|
|
1213
|
+
upgradeByTime: Math.floor(Date.now() / 1e3) + 3600
|
|
1214
|
+
},
|
|
1215
|
+
publicEnv: new Uint8Array(Buffer.from(JSON.stringify(publicEnv))),
|
|
1216
|
+
encryptedEnv: new Uint8Array(Buffer.from(encryptedEnvStr))
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
function extractRegistryNameNoDocker(imageRef) {
|
|
1220
|
+
let name = imageRef;
|
|
1221
|
+
const tagIndex = name.lastIndexOf(":");
|
|
1222
|
+
if (tagIndex !== -1 && !name.substring(tagIndex + 1).includes("/")) {
|
|
1223
|
+
name = name.substring(0, tagIndex);
|
|
1224
|
+
}
|
|
1225
|
+
const digestIndex = name.indexOf("@");
|
|
1226
|
+
if (digestIndex !== -1) {
|
|
1227
|
+
name = name.substring(0, digestIndex);
|
|
1228
|
+
}
|
|
1229
|
+
if ([...name].filter((c) => c === "/").length === 1) {
|
|
1230
|
+
name = `docker.io/${name}`;
|
|
1231
|
+
}
|
|
1232
|
+
return name;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1172
1235
|
// src/client/common/contract/caller.ts
|
|
1173
1236
|
var import_accounts2 = require("viem/accounts");
|
|
1174
1237
|
|
|
@@ -2205,8 +2268,55 @@ var ERC7702Delegator_default = [
|
|
|
2205
2268
|
];
|
|
2206
2269
|
|
|
2207
2270
|
// src/client/common/contract/eip7702.ts
|
|
2271
|
+
var EXECUTE_BATCH_MODE = "0x0100000000000000000000000000000000000000000000000000000000000000";
|
|
2272
|
+
var GAS_LIMIT_BUFFER_PERCENTAGE = 20n;
|
|
2273
|
+
var GAS_PRICE_BUFFER_PERCENTAGE = 100n;
|
|
2274
|
+
function encodeExecuteBatchData(executions) {
|
|
2275
|
+
const encodedExecutions = (0, import_viem.encodeAbiParameters)(
|
|
2276
|
+
[
|
|
2277
|
+
{
|
|
2278
|
+
type: "tuple[]",
|
|
2279
|
+
components: [
|
|
2280
|
+
{ name: "target", type: "address" },
|
|
2281
|
+
{ name: "value", type: "uint256" },
|
|
2282
|
+
{ name: "callData", type: "bytes" }
|
|
2283
|
+
]
|
|
2284
|
+
}
|
|
2285
|
+
],
|
|
2286
|
+
[executions]
|
|
2287
|
+
);
|
|
2288
|
+
return (0, import_viem.encodeFunctionData)({
|
|
2289
|
+
abi: ERC7702Delegator_default,
|
|
2290
|
+
functionName: "execute",
|
|
2291
|
+
args: [EXECUTE_BATCH_MODE, encodedExecutions]
|
|
2292
|
+
});
|
|
2293
|
+
}
|
|
2294
|
+
async function estimateBatchGas(options) {
|
|
2295
|
+
const { publicClient, account, executions } = options;
|
|
2296
|
+
const executeBatchData = encodeExecuteBatchData(executions);
|
|
2297
|
+
const [gasTipCap, block, estimatedGas] = await Promise.all([
|
|
2298
|
+
publicClient.estimateMaxPriorityFeePerGas(),
|
|
2299
|
+
publicClient.getBlock(),
|
|
2300
|
+
publicClient.estimateGas({
|
|
2301
|
+
account,
|
|
2302
|
+
to: account,
|
|
2303
|
+
data: executeBatchData
|
|
2304
|
+
})
|
|
2305
|
+
]);
|
|
2306
|
+
const baseFee = block.baseFeePerGas ?? 0n;
|
|
2307
|
+
const maxFeePerGas = (baseFee + gasTipCap) * (100n + GAS_PRICE_BUFFER_PERCENTAGE) / 100n;
|
|
2308
|
+
const gasLimit = estimatedGas * (100n + GAS_LIMIT_BUFFER_PERCENTAGE) / 100n;
|
|
2309
|
+
const maxCostWei = gasLimit * maxFeePerGas;
|
|
2310
|
+
return {
|
|
2311
|
+
gasLimit,
|
|
2312
|
+
maxFeePerGas,
|
|
2313
|
+
maxPriorityFeePerGas: gasTipCap,
|
|
2314
|
+
maxCostWei,
|
|
2315
|
+
maxCostEth: formatETH(maxCostWei)
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2208
2318
|
async function checkERC7702Delegation(publicClient, account, delegatorAddress) {
|
|
2209
|
-
const code = await publicClient.
|
|
2319
|
+
const code = await publicClient.getCode({ address: account });
|
|
2210
2320
|
if (!code) {
|
|
2211
2321
|
return false;
|
|
2212
2322
|
}
|
|
@@ -2223,36 +2333,7 @@ async function executeBatch(options, logger) {
|
|
|
2223
2333
|
if (!chain) {
|
|
2224
2334
|
throw new Error("Wallet client must have a chain");
|
|
2225
2335
|
}
|
|
2226
|
-
const
|
|
2227
|
-
[
|
|
2228
|
-
{
|
|
2229
|
-
type: "tuple[]",
|
|
2230
|
-
components: [
|
|
2231
|
-
{ name: "target", type: "address" },
|
|
2232
|
-
{ name: "value", type: "uint256" },
|
|
2233
|
-
{ name: "callData", type: "bytes" }
|
|
2234
|
-
]
|
|
2235
|
-
}
|
|
2236
|
-
],
|
|
2237
|
-
[executions]
|
|
2238
|
-
);
|
|
2239
|
-
const executeBatchMode = "0x0100000000000000000000000000000000000000000000000000000000000000";
|
|
2240
|
-
let executeBatchData;
|
|
2241
|
-
try {
|
|
2242
|
-
executeBatchData = (0, import_viem.encodeFunctionData)({
|
|
2243
|
-
abi: ERC7702Delegator_default,
|
|
2244
|
-
functionName: "execute",
|
|
2245
|
-
args: [executeBatchMode, encodedExecutions]
|
|
2246
|
-
});
|
|
2247
|
-
} catch {
|
|
2248
|
-
const functionSignature = "execute(bytes32,bytes)";
|
|
2249
|
-
const selector = (0, import_viem.keccak256)((0, import_viem.toBytes)(functionSignature)).slice(0, 10);
|
|
2250
|
-
const encodedParams = (0, import_viem.encodeAbiParameters)(
|
|
2251
|
-
[{ type: "bytes32" }, { type: "bytes" }],
|
|
2252
|
-
[executeBatchMode, encodedExecutions]
|
|
2253
|
-
);
|
|
2254
|
-
executeBatchData = (0, import_viem.concat)([selector, encodedParams]);
|
|
2255
|
-
}
|
|
2336
|
+
const executeBatchData = encodeExecuteBatchData(executions);
|
|
2256
2337
|
const isDelegated2 = await checkERC7702Delegation(
|
|
2257
2338
|
publicClient,
|
|
2258
2339
|
account.address,
|
|
@@ -2385,12 +2466,23 @@ function stripHexPrefix(value) {
|
|
|
2385
2466
|
}
|
|
2386
2467
|
|
|
2387
2468
|
// src/client/common/utils/userapi.ts
|
|
2469
|
+
function isJsonObject(value) {
|
|
2470
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2471
|
+
}
|
|
2472
|
+
function readString(obj, key) {
|
|
2473
|
+
const v = obj[key];
|
|
2474
|
+
return typeof v === "string" ? v : void 0;
|
|
2475
|
+
}
|
|
2476
|
+
function readNumber(obj, key) {
|
|
2477
|
+
const v = obj[key];
|
|
2478
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
2479
|
+
}
|
|
2388
2480
|
var MAX_ADDRESS_COUNT = 5;
|
|
2389
2481
|
var CanViewAppLogsPermission = "0x2fd3f2fe";
|
|
2390
2482
|
var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
|
|
2391
2483
|
var CanUpdateAppProfilePermission = "0x036fef61";
|
|
2392
2484
|
function getDefaultClientId() {
|
|
2393
|
-
const version = true ? "0.2.0
|
|
2485
|
+
const version = true ? "0.2.0" : "0.0.0";
|
|
2394
2486
|
return `ecloud-sdk/v${version}`;
|
|
2395
2487
|
}
|
|
2396
2488
|
var UserApiClient = class {
|
|
@@ -2424,6 +2516,31 @@ var UserApiClient = class {
|
|
|
2424
2516
|
};
|
|
2425
2517
|
});
|
|
2426
2518
|
}
|
|
2519
|
+
/**
|
|
2520
|
+
* Get app details from UserAPI (includes releases and build/provenance info when available).
|
|
2521
|
+
*
|
|
2522
|
+
* Endpoint: GET /apps/:appAddress
|
|
2523
|
+
*/
|
|
2524
|
+
async getApp(appAddress) {
|
|
2525
|
+
const endpoint = `${this.config.userApiServerURL}/apps/${appAddress}`;
|
|
2526
|
+
const res = await this.makeAuthenticatedRequest(endpoint);
|
|
2527
|
+
const raw = await res.json();
|
|
2528
|
+
if (!isJsonObject(raw)) {
|
|
2529
|
+
throw new Error("Unexpected /apps/:id response: expected object");
|
|
2530
|
+
}
|
|
2531
|
+
const id = readString(raw, "id");
|
|
2532
|
+
if (!id) {
|
|
2533
|
+
throw new Error("Unexpected /apps/:id response: missing 'id'");
|
|
2534
|
+
}
|
|
2535
|
+
const releasesRaw = raw.releases;
|
|
2536
|
+
const releases = Array.isArray(releasesRaw) ? releasesRaw.map((r) => transformAppRelease(r)).filter((r) => !!r) : [];
|
|
2537
|
+
return {
|
|
2538
|
+
id,
|
|
2539
|
+
creator: readString(raw, "creator"),
|
|
2540
|
+
contractStatus: readString(raw, "contract_status") ?? readString(raw, "contractStatus"),
|
|
2541
|
+
releases
|
|
2542
|
+
};
|
|
2543
|
+
}
|
|
2427
2544
|
/**
|
|
2428
2545
|
* Get available SKUs (instance types) from UserAPI
|
|
2429
2546
|
*/
|
|
@@ -2596,6 +2713,48 @@ Please check:
|
|
|
2596
2713
|
};
|
|
2597
2714
|
}
|
|
2598
2715
|
};
|
|
2716
|
+
function transformAppReleaseBuild(raw) {
|
|
2717
|
+
if (!isJsonObject(raw)) return void 0;
|
|
2718
|
+
const depsRaw = raw.dependencies;
|
|
2719
|
+
const deps = isJsonObject(depsRaw) ? Object.fromEntries(
|
|
2720
|
+
Object.entries(depsRaw).flatMap(([digest, depRaw]) => {
|
|
2721
|
+
const parsed = transformAppReleaseBuild(depRaw);
|
|
2722
|
+
return parsed ? [[digest, parsed]] : [];
|
|
2723
|
+
})
|
|
2724
|
+
) : void 0;
|
|
2725
|
+
return {
|
|
2726
|
+
buildId: readString(raw, "build_id") ?? readString(raw, "buildId"),
|
|
2727
|
+
billingAddress: readString(raw, "billing_address") ?? readString(raw, "billingAddress"),
|
|
2728
|
+
repoUrl: readString(raw, "repo_url") ?? readString(raw, "repoUrl"),
|
|
2729
|
+
gitRef: readString(raw, "git_ref") ?? readString(raw, "gitRef"),
|
|
2730
|
+
status: readString(raw, "status"),
|
|
2731
|
+
buildType: readString(raw, "build_type") ?? readString(raw, "buildType"),
|
|
2732
|
+
imageName: readString(raw, "image_name") ?? readString(raw, "imageName"),
|
|
2733
|
+
imageDigest: readString(raw, "image_digest") ?? readString(raw, "imageDigest"),
|
|
2734
|
+
imageUrl: readString(raw, "image_url") ?? readString(raw, "imageUrl"),
|
|
2735
|
+
provenanceJson: raw.provenance_json ?? raw.provenanceJson,
|
|
2736
|
+
provenanceSignature: readString(raw, "provenance_signature") ?? readString(raw, "provenanceSignature"),
|
|
2737
|
+
createdAt: readString(raw, "created_at") ?? readString(raw, "createdAt"),
|
|
2738
|
+
updatedAt: readString(raw, "updated_at") ?? readString(raw, "updatedAt"),
|
|
2739
|
+
errorMessage: readString(raw, "error_message") ?? readString(raw, "errorMessage"),
|
|
2740
|
+
dependencies: deps
|
|
2741
|
+
};
|
|
2742
|
+
}
|
|
2743
|
+
function transformAppRelease(raw) {
|
|
2744
|
+
if (!isJsonObject(raw)) return void 0;
|
|
2745
|
+
return {
|
|
2746
|
+
appId: readString(raw, "appId") ?? readString(raw, "app_id"),
|
|
2747
|
+
rmsReleaseId: readString(raw, "rmsReleaseId") ?? readString(raw, "rms_release_id"),
|
|
2748
|
+
imageDigest: readString(raw, "imageDigest") ?? readString(raw, "image_digest"),
|
|
2749
|
+
registryUrl: readString(raw, "registryUrl") ?? readString(raw, "registry_url"),
|
|
2750
|
+
publicEnv: readString(raw, "publicEnv") ?? readString(raw, "public_env"),
|
|
2751
|
+
encryptedEnv: readString(raw, "encryptedEnv") ?? readString(raw, "encrypted_env"),
|
|
2752
|
+
upgradeByTime: readNumber(raw, "upgradeByTime") ?? readNumber(raw, "upgrade_by_time"),
|
|
2753
|
+
createdAt: readString(raw, "createdAt") ?? readString(raw, "created_at"),
|
|
2754
|
+
createdAtBlock: readString(raw, "createdAtBlock") ?? readString(raw, "created_at_block"),
|
|
2755
|
+
build: raw.build ? transformAppReleaseBuild(raw.build) : void 0
|
|
2756
|
+
};
|
|
2757
|
+
}
|
|
2599
2758
|
|
|
2600
2759
|
// src/client/common/abis/AppController.json
|
|
2601
2760
|
var AppController_default = [
|
|
@@ -4142,6 +4301,15 @@ var PermissionController_default = [
|
|
|
4142
4301
|
];
|
|
4143
4302
|
|
|
4144
4303
|
// src/client/common/contract/caller.ts
|
|
4304
|
+
function formatETH(wei) {
|
|
4305
|
+
const eth = Number(wei) / 1e18;
|
|
4306
|
+
const costStr = eth.toFixed(6);
|
|
4307
|
+
const trimmed = costStr.replace(/\.?0+$/, "");
|
|
4308
|
+
if (trimmed === "0" && wei > 0n) {
|
|
4309
|
+
return "<0.000001";
|
|
4310
|
+
}
|
|
4311
|
+
return trimmed;
|
|
4312
|
+
}
|
|
4145
4313
|
async function calculateAppID(privateKey, rpcUrl, environmentConfig, salt) {
|
|
4146
4314
|
const privateKeyHex = addHexPrefix(privateKey);
|
|
4147
4315
|
const account = (0, import_accounts2.privateKeyToAccount)(privateKeyHex);
|
|
@@ -4246,20 +4414,20 @@ async function prepareDeployBatch(options, logger) {
|
|
|
4246
4414
|
environmentConfig
|
|
4247
4415
|
};
|
|
4248
4416
|
}
|
|
4249
|
-
async function executeDeployBatch(
|
|
4417
|
+
async function executeDeployBatch(data, context, gas, logger) {
|
|
4250
4418
|
const pendingMessage = "Deploying new app...";
|
|
4251
4419
|
const txHash = await executeBatch(
|
|
4252
4420
|
{
|
|
4253
|
-
walletClient:
|
|
4254
|
-
publicClient:
|
|
4255
|
-
environmentConfig:
|
|
4256
|
-
executions:
|
|
4421
|
+
walletClient: context.walletClient,
|
|
4422
|
+
publicClient: context.publicClient,
|
|
4423
|
+
environmentConfig: context.environmentConfig,
|
|
4424
|
+
executions: data.executions,
|
|
4257
4425
|
pendingMessage,
|
|
4258
4426
|
gas
|
|
4259
4427
|
},
|
|
4260
4428
|
logger
|
|
4261
4429
|
);
|
|
4262
|
-
return { appId:
|
|
4430
|
+
return { appId: data.appId, txHash };
|
|
4263
4431
|
}
|
|
4264
4432
|
async function deployApp(options, logger) {
|
|
4265
4433
|
const prepared = await prepareDeployBatch(
|
|
@@ -4273,7 +4441,17 @@ async function deployApp(options, logger) {
|
|
|
4273
4441
|
},
|
|
4274
4442
|
logger
|
|
4275
4443
|
);
|
|
4276
|
-
|
|
4444
|
+
const data = {
|
|
4445
|
+
appId: prepared.appId,
|
|
4446
|
+
salt: prepared.salt,
|
|
4447
|
+
executions: prepared.executions
|
|
4448
|
+
};
|
|
4449
|
+
const context = {
|
|
4450
|
+
walletClient: prepared.walletClient,
|
|
4451
|
+
publicClient: prepared.publicClient,
|
|
4452
|
+
environmentConfig: prepared.environmentConfig
|
|
4453
|
+
};
|
|
4454
|
+
return executeDeployBatch(data, context, options.gas, logger);
|
|
4277
4455
|
}
|
|
4278
4456
|
async function prepareUpgradeBatch(options) {
|
|
4279
4457
|
const {
|
|
@@ -4369,14 +4547,14 @@ async function prepareUpgradeBatch(options) {
|
|
|
4369
4547
|
environmentConfig
|
|
4370
4548
|
};
|
|
4371
4549
|
}
|
|
4372
|
-
async function executeUpgradeBatch(
|
|
4373
|
-
const pendingMessage = `Upgrading app ${
|
|
4550
|
+
async function executeUpgradeBatch(data, context, gas, logger) {
|
|
4551
|
+
const pendingMessage = `Upgrading app ${data.appId}...`;
|
|
4374
4552
|
const txHash = await executeBatch(
|
|
4375
4553
|
{
|
|
4376
|
-
walletClient:
|
|
4377
|
-
publicClient:
|
|
4378
|
-
environmentConfig:
|
|
4379
|
-
executions:
|
|
4554
|
+
walletClient: context.walletClient,
|
|
4555
|
+
publicClient: context.publicClient,
|
|
4556
|
+
environmentConfig: context.environmentConfig,
|
|
4557
|
+
executions: data.executions,
|
|
4380
4558
|
pendingMessage,
|
|
4381
4559
|
gas
|
|
4382
4560
|
},
|
|
@@ -4394,7 +4572,16 @@ async function upgradeApp(options, logger) {
|
|
|
4394
4572
|
publicLogs: options.publicLogs,
|
|
4395
4573
|
needsPermissionChange: options.needsPermissionChange
|
|
4396
4574
|
});
|
|
4397
|
-
|
|
4575
|
+
const data = {
|
|
4576
|
+
appId: prepared.appId,
|
|
4577
|
+
executions: prepared.executions
|
|
4578
|
+
};
|
|
4579
|
+
const context = {
|
|
4580
|
+
walletClient: prepared.walletClient,
|
|
4581
|
+
publicClient: prepared.publicClient,
|
|
4582
|
+
environmentConfig: prepared.environmentConfig
|
|
4583
|
+
};
|
|
4584
|
+
return executeUpgradeBatch(data, context, options.gas, logger);
|
|
4398
4585
|
}
|
|
4399
4586
|
async function sendAndWaitForTransaction(options, logger) {
|
|
4400
4587
|
const {
|
|
@@ -5065,6 +5252,97 @@ async function withSDKTelemetry(options, action) {
|
|
|
5065
5252
|
}
|
|
5066
5253
|
|
|
5067
5254
|
// src/client/modules/compute/app/deploy.ts
|
|
5255
|
+
async function prepareDeployFromVerifiableBuild(options, logger = defaultLogger) {
|
|
5256
|
+
return withSDKTelemetry(
|
|
5257
|
+
{
|
|
5258
|
+
functionName: "prepareDeployFromVerifiableBuild",
|
|
5259
|
+
skipTelemetry: options.skipTelemetry,
|
|
5260
|
+
properties: {
|
|
5261
|
+
environment: options.environment || "sepolia"
|
|
5262
|
+
}
|
|
5263
|
+
},
|
|
5264
|
+
async () => {
|
|
5265
|
+
if (!options.privateKey) throw new Error("privateKey is required for deployment");
|
|
5266
|
+
if (!options.imageRef) throw new Error("imageRef is required for deployment");
|
|
5267
|
+
if (!options.imageDigest) throw new Error("imageDigest is required for deployment");
|
|
5268
|
+
assertValidImageReference(options.imageRef);
|
|
5269
|
+
validateAppName(options.appName);
|
|
5270
|
+
validateLogVisibility(options.logVisibility);
|
|
5271
|
+
if (!/^sha256:[0-9a-f]{64}$/i.test(options.imageDigest)) {
|
|
5272
|
+
throw new Error(
|
|
5273
|
+
`imageDigest must be in format sha256:<64 hex>, got: ${options.imageDigest}`
|
|
5274
|
+
);
|
|
5275
|
+
}
|
|
5276
|
+
const { publicLogs } = validateLogVisibility(options.logVisibility);
|
|
5277
|
+
validateResourceUsageMonitoring(options.resourceUsageMonitoring);
|
|
5278
|
+
logger.debug("Performing preflight checks...");
|
|
5279
|
+
const preflightCtx = await doPreflightChecks(
|
|
5280
|
+
{
|
|
5281
|
+
privateKey: options.privateKey,
|
|
5282
|
+
rpcUrl: options.rpcUrl,
|
|
5283
|
+
environment: options.environment
|
|
5284
|
+
},
|
|
5285
|
+
logger
|
|
5286
|
+
);
|
|
5287
|
+
logger.debug("Checking quota availability...");
|
|
5288
|
+
await checkQuotaAvailable(preflightCtx);
|
|
5289
|
+
const salt = generateRandomSalt();
|
|
5290
|
+
logger.debug(`Generated salt: ${Buffer.from(salt).toString("hex")}`);
|
|
5291
|
+
logger.debug("Calculating app ID...");
|
|
5292
|
+
const appIDToBeDeployed = await calculateAppID(
|
|
5293
|
+
preflightCtx.privateKey,
|
|
5294
|
+
options.rpcUrl || preflightCtx.rpcUrl,
|
|
5295
|
+
preflightCtx.environmentConfig,
|
|
5296
|
+
salt
|
|
5297
|
+
);
|
|
5298
|
+
logger.info(``);
|
|
5299
|
+
logger.info(`App ID: ${appIDToBeDeployed}`);
|
|
5300
|
+
logger.info(``);
|
|
5301
|
+
const release = await createReleaseFromImageDigest(
|
|
5302
|
+
{
|
|
5303
|
+
imageRef: options.imageRef,
|
|
5304
|
+
imageDigest: options.imageDigest,
|
|
5305
|
+
envFilePath: options.envFilePath,
|
|
5306
|
+
instanceType: options.instanceType,
|
|
5307
|
+
environmentConfig: preflightCtx.environmentConfig,
|
|
5308
|
+
appId: appIDToBeDeployed
|
|
5309
|
+
},
|
|
5310
|
+
logger
|
|
5311
|
+
);
|
|
5312
|
+
logger.debug("Preparing deploy batch...");
|
|
5313
|
+
const batch = await prepareDeployBatch(
|
|
5314
|
+
{
|
|
5315
|
+
privateKey: preflightCtx.privateKey,
|
|
5316
|
+
rpcUrl: options.rpcUrl || preflightCtx.rpcUrl,
|
|
5317
|
+
environmentConfig: preflightCtx.environmentConfig,
|
|
5318
|
+
salt,
|
|
5319
|
+
release,
|
|
5320
|
+
publicLogs
|
|
5321
|
+
},
|
|
5322
|
+
logger
|
|
5323
|
+
);
|
|
5324
|
+
logger.debug("Estimating gas...");
|
|
5325
|
+
const gasEstimate = await estimateBatchGas({
|
|
5326
|
+
publicClient: batch.publicClient,
|
|
5327
|
+
account: batch.walletClient.account.address,
|
|
5328
|
+
executions: batch.executions
|
|
5329
|
+
});
|
|
5330
|
+
const data = {
|
|
5331
|
+
appId: batch.appId,
|
|
5332
|
+
salt: batch.salt,
|
|
5333
|
+
executions: batch.executions
|
|
5334
|
+
};
|
|
5335
|
+
return {
|
|
5336
|
+
prepared: {
|
|
5337
|
+
data,
|
|
5338
|
+
appName: options.appName,
|
|
5339
|
+
imageRef: options.imageRef
|
|
5340
|
+
},
|
|
5341
|
+
gasEstimate
|
|
5342
|
+
};
|
|
5343
|
+
}
|
|
5344
|
+
);
|
|
5345
|
+
}
|
|
5068
5346
|
function validateDeployOptions(options) {
|
|
5069
5347
|
if (!options.privateKey) {
|
|
5070
5348
|
throw new Error("privateKey is required for deployment");
|
|
@@ -5213,6 +5491,141 @@ function generateRandomSalt() {
|
|
|
5213
5491
|
crypto.getRandomValues(salt);
|
|
5214
5492
|
return salt;
|
|
5215
5493
|
}
|
|
5494
|
+
async function prepareDeploy(options, logger = defaultLogger) {
|
|
5495
|
+
return withSDKTelemetry(
|
|
5496
|
+
{
|
|
5497
|
+
functionName: "prepareDeploy",
|
|
5498
|
+
skipTelemetry: options.skipTelemetry,
|
|
5499
|
+
properties: {
|
|
5500
|
+
environment: options.environment || "sepolia"
|
|
5501
|
+
}
|
|
5502
|
+
},
|
|
5503
|
+
async () => {
|
|
5504
|
+
validateDeployOptions(options);
|
|
5505
|
+
const { logRedirect, publicLogs } = validateLogVisibility(options.logVisibility);
|
|
5506
|
+
const resourceUsageAllow = validateResourceUsageMonitoring(options.resourceUsageMonitoring);
|
|
5507
|
+
logger.debug("Performing preflight checks...");
|
|
5508
|
+
const preflightCtx = await doPreflightChecks(
|
|
5509
|
+
{
|
|
5510
|
+
privateKey: options.privateKey,
|
|
5511
|
+
rpcUrl: options.rpcUrl,
|
|
5512
|
+
environment: options.environment
|
|
5513
|
+
},
|
|
5514
|
+
logger
|
|
5515
|
+
);
|
|
5516
|
+
logger.debug("Checking quota availability...");
|
|
5517
|
+
await checkQuotaAvailable(preflightCtx);
|
|
5518
|
+
logger.debug("Checking Docker...");
|
|
5519
|
+
await ensureDockerIsRunning();
|
|
5520
|
+
const dockerfilePath = options.dockerfilePath || "";
|
|
5521
|
+
const imageRef = options.imageRef || "";
|
|
5522
|
+
const appName = options.appName;
|
|
5523
|
+
const envFilePath = options.envFilePath || "";
|
|
5524
|
+
const instanceType = options.instanceType;
|
|
5525
|
+
const salt = generateRandomSalt();
|
|
5526
|
+
logger.debug(`Generated salt: ${Buffer.from(salt).toString("hex")}`);
|
|
5527
|
+
logger.debug("Calculating app ID...");
|
|
5528
|
+
const appIDToBeDeployed = await calculateAppID(
|
|
5529
|
+
preflightCtx.privateKey,
|
|
5530
|
+
options.rpcUrl || preflightCtx.rpcUrl,
|
|
5531
|
+
preflightCtx.environmentConfig,
|
|
5532
|
+
salt
|
|
5533
|
+
);
|
|
5534
|
+
logger.info(``);
|
|
5535
|
+
logger.info(`App ID: ${appIDToBeDeployed}`);
|
|
5536
|
+
logger.info(``);
|
|
5537
|
+
logger.info("Preparing release...");
|
|
5538
|
+
const { release, finalImageRef } = await prepareRelease(
|
|
5539
|
+
{
|
|
5540
|
+
dockerfilePath,
|
|
5541
|
+
imageRef,
|
|
5542
|
+
envFilePath,
|
|
5543
|
+
logRedirect,
|
|
5544
|
+
resourceUsageAllow,
|
|
5545
|
+
instanceType,
|
|
5546
|
+
environmentConfig: preflightCtx.environmentConfig,
|
|
5547
|
+
appId: appIDToBeDeployed
|
|
5548
|
+
},
|
|
5549
|
+
logger
|
|
5550
|
+
);
|
|
5551
|
+
logger.debug("Preparing deploy batch...");
|
|
5552
|
+
const batch = await prepareDeployBatch(
|
|
5553
|
+
{
|
|
5554
|
+
privateKey: preflightCtx.privateKey,
|
|
5555
|
+
rpcUrl: options.rpcUrl || preflightCtx.rpcUrl,
|
|
5556
|
+
environmentConfig: preflightCtx.environmentConfig,
|
|
5557
|
+
salt,
|
|
5558
|
+
release,
|
|
5559
|
+
publicLogs
|
|
5560
|
+
},
|
|
5561
|
+
logger
|
|
5562
|
+
);
|
|
5563
|
+
logger.debug("Estimating gas...");
|
|
5564
|
+
const gasEstimate = await estimateBatchGas({
|
|
5565
|
+
publicClient: batch.publicClient,
|
|
5566
|
+
account: batch.walletClient.account.address,
|
|
5567
|
+
executions: batch.executions
|
|
5568
|
+
});
|
|
5569
|
+
const data = {
|
|
5570
|
+
appId: batch.appId,
|
|
5571
|
+
salt: batch.salt,
|
|
5572
|
+
executions: batch.executions
|
|
5573
|
+
};
|
|
5574
|
+
return {
|
|
5575
|
+
prepared: {
|
|
5576
|
+
data,
|
|
5577
|
+
appName,
|
|
5578
|
+
imageRef: finalImageRef
|
|
5579
|
+
},
|
|
5580
|
+
gasEstimate
|
|
5581
|
+
};
|
|
5582
|
+
}
|
|
5583
|
+
);
|
|
5584
|
+
}
|
|
5585
|
+
async function executeDeploy(options) {
|
|
5586
|
+
const { prepared, context, gas, logger = defaultLogger, skipTelemetry } = options;
|
|
5587
|
+
return withSDKTelemetry(
|
|
5588
|
+
{
|
|
5589
|
+
functionName: "executeDeploy",
|
|
5590
|
+
skipTelemetry
|
|
5591
|
+
},
|
|
5592
|
+
async () => {
|
|
5593
|
+
logger.info("Deploying on-chain...");
|
|
5594
|
+
const { appId, txHash } = await executeDeployBatch(prepared.data, context, gas, logger);
|
|
5595
|
+
return {
|
|
5596
|
+
appId,
|
|
5597
|
+
txHash,
|
|
5598
|
+
appName: prepared.appName,
|
|
5599
|
+
imageRef: prepared.imageRef
|
|
5600
|
+
};
|
|
5601
|
+
}
|
|
5602
|
+
);
|
|
5603
|
+
}
|
|
5604
|
+
async function watchDeployment(appId, privateKey, rpcUrl, environment, logger = defaultLogger, clientId, skipTelemetry) {
|
|
5605
|
+
return withSDKTelemetry(
|
|
5606
|
+
{
|
|
5607
|
+
functionName: "watchDeployment",
|
|
5608
|
+
skipTelemetry,
|
|
5609
|
+
properties: {
|
|
5610
|
+
environment
|
|
5611
|
+
}
|
|
5612
|
+
},
|
|
5613
|
+
async () => {
|
|
5614
|
+
const environmentConfig = getEnvironmentConfig(environment);
|
|
5615
|
+
logger.info("Waiting for app to start...");
|
|
5616
|
+
return watchUntilRunning(
|
|
5617
|
+
{
|
|
5618
|
+
privateKey,
|
|
5619
|
+
rpcUrl,
|
|
5620
|
+
environmentConfig,
|
|
5621
|
+
appId,
|
|
5622
|
+
clientId
|
|
5623
|
+
},
|
|
5624
|
+
logger
|
|
5625
|
+
);
|
|
5626
|
+
}
|
|
5627
|
+
);
|
|
5628
|
+
}
|
|
5216
5629
|
|
|
5217
5630
|
// src/client/common/utils/permissions.ts
|
|
5218
5631
|
var import_viem8 = require("viem");
|
|
@@ -5240,6 +5653,81 @@ async function checkAppLogPermission(preflightCtx, appAddress, logger) {
|
|
|
5240
5653
|
}
|
|
5241
5654
|
|
|
5242
5655
|
// src/client/modules/compute/app/upgrade.ts
|
|
5656
|
+
async function prepareUpgradeFromVerifiableBuild(options, logger = defaultLogger) {
|
|
5657
|
+
return withSDKTelemetry(
|
|
5658
|
+
{
|
|
5659
|
+
functionName: "prepareUpgradeFromVerifiableBuild",
|
|
5660
|
+
skipTelemetry: options.skipTelemetry,
|
|
5661
|
+
properties: {
|
|
5662
|
+
environment: options.environment || "sepolia"
|
|
5663
|
+
}
|
|
5664
|
+
},
|
|
5665
|
+
async () => {
|
|
5666
|
+
logger.debug("Performing preflight checks...");
|
|
5667
|
+
const preflightCtx = await doPreflightChecks(
|
|
5668
|
+
{
|
|
5669
|
+
privateKey: options.privateKey,
|
|
5670
|
+
rpcUrl: options.rpcUrl,
|
|
5671
|
+
environment: options.environment
|
|
5672
|
+
},
|
|
5673
|
+
logger
|
|
5674
|
+
);
|
|
5675
|
+
const appID = validateUpgradeOptions(options);
|
|
5676
|
+
assertValidImageReference(options.imageRef);
|
|
5677
|
+
if (!/^sha256:[0-9a-f]{64}$/i.test(options.imageDigest)) {
|
|
5678
|
+
throw new Error(
|
|
5679
|
+
`imageDigest must be in format sha256:<64 hex>, got: ${options.imageDigest}`
|
|
5680
|
+
);
|
|
5681
|
+
}
|
|
5682
|
+
const { publicLogs } = validateLogVisibility(options.logVisibility);
|
|
5683
|
+
validateResourceUsageMonitoring(options.resourceUsageMonitoring);
|
|
5684
|
+
const envFilePath = options.envFilePath || "";
|
|
5685
|
+
logger.info("Preparing release (verifiable build, no local layering)...");
|
|
5686
|
+
const release = await createReleaseFromImageDigest(
|
|
5687
|
+
{
|
|
5688
|
+
imageRef: options.imageRef,
|
|
5689
|
+
imageDigest: options.imageDigest,
|
|
5690
|
+
envFilePath,
|
|
5691
|
+
instanceType: options.instanceType,
|
|
5692
|
+
environmentConfig: preflightCtx.environmentConfig,
|
|
5693
|
+
appId: appID
|
|
5694
|
+
},
|
|
5695
|
+
logger
|
|
5696
|
+
);
|
|
5697
|
+
logger.debug("Checking current log permission state...");
|
|
5698
|
+
const currentlyPublic = await checkAppLogPermission(preflightCtx, appID, logger);
|
|
5699
|
+
const needsPermissionChange = currentlyPublic !== publicLogs;
|
|
5700
|
+
logger.debug("Preparing upgrade batch...");
|
|
5701
|
+
const batch = await prepareUpgradeBatch({
|
|
5702
|
+
privateKey: preflightCtx.privateKey,
|
|
5703
|
+
rpcUrl: options.rpcUrl || preflightCtx.rpcUrl,
|
|
5704
|
+
environmentConfig: preflightCtx.environmentConfig,
|
|
5705
|
+
appId: appID,
|
|
5706
|
+
release,
|
|
5707
|
+
publicLogs,
|
|
5708
|
+
needsPermissionChange
|
|
5709
|
+
});
|
|
5710
|
+
logger.debug("Estimating gas...");
|
|
5711
|
+
const gasEstimate = await estimateBatchGas({
|
|
5712
|
+
publicClient: batch.publicClient,
|
|
5713
|
+
account: batch.walletClient.account.address,
|
|
5714
|
+
executions: batch.executions
|
|
5715
|
+
});
|
|
5716
|
+
const data = {
|
|
5717
|
+
appId: batch.appId,
|
|
5718
|
+
executions: batch.executions
|
|
5719
|
+
};
|
|
5720
|
+
return {
|
|
5721
|
+
prepared: {
|
|
5722
|
+
data,
|
|
5723
|
+
appId: appID,
|
|
5724
|
+
imageRef: options.imageRef
|
|
5725
|
+
},
|
|
5726
|
+
gasEstimate
|
|
5727
|
+
};
|
|
5728
|
+
}
|
|
5729
|
+
);
|
|
5730
|
+
}
|
|
5243
5731
|
function validateUpgradeOptions(options) {
|
|
5244
5732
|
if (!options.privateKey) {
|
|
5245
5733
|
throw new Error("privateKey is required for upgrade");
|
|
@@ -5344,6 +5832,125 @@ async function upgrade(options, logger = defaultLogger) {
|
|
|
5344
5832
|
}
|
|
5345
5833
|
);
|
|
5346
5834
|
}
|
|
5835
|
+
async function prepareUpgrade(options, logger = defaultLogger) {
|
|
5836
|
+
return withSDKTelemetry(
|
|
5837
|
+
{
|
|
5838
|
+
functionName: "prepareUpgrade",
|
|
5839
|
+
skipTelemetry: options.skipTelemetry,
|
|
5840
|
+
properties: {
|
|
5841
|
+
environment: options.environment || "sepolia"
|
|
5842
|
+
}
|
|
5843
|
+
},
|
|
5844
|
+
async () => {
|
|
5845
|
+
logger.debug("Performing preflight checks...");
|
|
5846
|
+
const preflightCtx = await doPreflightChecks(
|
|
5847
|
+
{
|
|
5848
|
+
privateKey: options.privateKey,
|
|
5849
|
+
rpcUrl: options.rpcUrl,
|
|
5850
|
+
environment: options.environment
|
|
5851
|
+
},
|
|
5852
|
+
logger
|
|
5853
|
+
);
|
|
5854
|
+
const appID = validateUpgradeOptions(options);
|
|
5855
|
+
const { logRedirect, publicLogs } = validateLogVisibility(options.logVisibility);
|
|
5856
|
+
const resourceUsageAllow = validateResourceUsageMonitoring(options.resourceUsageMonitoring);
|
|
5857
|
+
logger.debug("Checking Docker...");
|
|
5858
|
+
await ensureDockerIsRunning();
|
|
5859
|
+
const dockerfilePath = options.dockerfilePath || "";
|
|
5860
|
+
const imageRef = options.imageRef || "";
|
|
5861
|
+
const envFilePath = options.envFilePath || "";
|
|
5862
|
+
const instanceType = options.instanceType;
|
|
5863
|
+
logger.info("Preparing release...");
|
|
5864
|
+
const { release, finalImageRef } = await prepareRelease(
|
|
5865
|
+
{
|
|
5866
|
+
dockerfilePath,
|
|
5867
|
+
imageRef,
|
|
5868
|
+
envFilePath,
|
|
5869
|
+
logRedirect,
|
|
5870
|
+
resourceUsageAllow,
|
|
5871
|
+
instanceType,
|
|
5872
|
+
environmentConfig: preflightCtx.environmentConfig,
|
|
5873
|
+
appId: appID
|
|
5874
|
+
},
|
|
5875
|
+
logger
|
|
5876
|
+
);
|
|
5877
|
+
logger.debug("Checking current log permission state...");
|
|
5878
|
+
const currentlyPublic = await checkAppLogPermission(preflightCtx, appID, logger);
|
|
5879
|
+
const needsPermissionChange = currentlyPublic !== publicLogs;
|
|
5880
|
+
logger.debug("Preparing upgrade batch...");
|
|
5881
|
+
const batch = await prepareUpgradeBatch({
|
|
5882
|
+
privateKey: preflightCtx.privateKey,
|
|
5883
|
+
rpcUrl: options.rpcUrl || preflightCtx.rpcUrl,
|
|
5884
|
+
environmentConfig: preflightCtx.environmentConfig,
|
|
5885
|
+
appId: appID,
|
|
5886
|
+
release,
|
|
5887
|
+
publicLogs,
|
|
5888
|
+
needsPermissionChange
|
|
5889
|
+
});
|
|
5890
|
+
logger.debug("Estimating gas...");
|
|
5891
|
+
const gasEstimate = await estimateBatchGas({
|
|
5892
|
+
publicClient: batch.publicClient,
|
|
5893
|
+
account: batch.walletClient.account.address,
|
|
5894
|
+
executions: batch.executions
|
|
5895
|
+
});
|
|
5896
|
+
const data = {
|
|
5897
|
+
appId: batch.appId,
|
|
5898
|
+
executions: batch.executions
|
|
5899
|
+
};
|
|
5900
|
+
return {
|
|
5901
|
+
prepared: {
|
|
5902
|
+
data,
|
|
5903
|
+
appId: appID,
|
|
5904
|
+
imageRef: finalImageRef
|
|
5905
|
+
},
|
|
5906
|
+
gasEstimate
|
|
5907
|
+
};
|
|
5908
|
+
}
|
|
5909
|
+
);
|
|
5910
|
+
}
|
|
5911
|
+
async function executeUpgrade(options) {
|
|
5912
|
+
const { prepared, context, gas, logger = defaultLogger, skipTelemetry } = options;
|
|
5913
|
+
return withSDKTelemetry(
|
|
5914
|
+
{
|
|
5915
|
+
functionName: "executeUpgrade",
|
|
5916
|
+
skipTelemetry
|
|
5917
|
+
},
|
|
5918
|
+
async () => {
|
|
5919
|
+
logger.info("Upgrading on-chain...");
|
|
5920
|
+
const txHash = await executeUpgradeBatch(prepared.data, context, gas, logger);
|
|
5921
|
+
return {
|
|
5922
|
+
appId: prepared.appId,
|
|
5923
|
+
imageRef: prepared.imageRef,
|
|
5924
|
+
txHash
|
|
5925
|
+
};
|
|
5926
|
+
}
|
|
5927
|
+
);
|
|
5928
|
+
}
|
|
5929
|
+
async function watchUpgrade(appId, privateKey, rpcUrl, environment, logger = defaultLogger, clientId, skipTelemetry) {
|
|
5930
|
+
return withSDKTelemetry(
|
|
5931
|
+
{
|
|
5932
|
+
functionName: "watchUpgrade",
|
|
5933
|
+
skipTelemetry,
|
|
5934
|
+
properties: {
|
|
5935
|
+
environment
|
|
5936
|
+
}
|
|
5937
|
+
},
|
|
5938
|
+
async () => {
|
|
5939
|
+
const environmentConfig = getEnvironmentConfig(environment);
|
|
5940
|
+
logger.info("Waiting for upgrade to complete...");
|
|
5941
|
+
await watchUntilUpgradeComplete(
|
|
5942
|
+
{
|
|
5943
|
+
privateKey,
|
|
5944
|
+
rpcUrl,
|
|
5945
|
+
environmentConfig,
|
|
5946
|
+
appId,
|
|
5947
|
+
clientId
|
|
5948
|
+
},
|
|
5949
|
+
logger
|
|
5950
|
+
);
|
|
5951
|
+
}
|
|
5952
|
+
);
|
|
5953
|
+
}
|
|
5347
5954
|
|
|
5348
5955
|
// src/client/modules/compute/app/create.ts
|
|
5349
5956
|
var fs7 = __toESM(require("fs"), 1);
|
|
@@ -5441,8 +6048,8 @@ var path4 = __toESM(require("path"), 1);
|
|
|
5441
6048
|
var os3 = __toESM(require("os"), 1);
|
|
5442
6049
|
var import_child_process2 = require("child_process");
|
|
5443
6050
|
var import_util4 = require("util");
|
|
5444
|
-
var
|
|
5445
|
-
var
|
|
6051
|
+
var execAsync = (0, import_util4.promisify)(import_child_process2.exec);
|
|
6052
|
+
var execFileAsync3 = (0, import_util4.promisify)(import_child_process2.execFile);
|
|
5446
6053
|
async function fetchTemplate(repoURL, ref, targetDir, config, logger) {
|
|
5447
6054
|
if (!repoURL) {
|
|
5448
6055
|
throw new Error("repoURL is required");
|
|
@@ -5451,13 +6058,13 @@ async function fetchTemplate(repoURL, ref, targetDir, config, logger) {
|
|
|
5451
6058
|
Cloning repo: ${repoURL} \u2192 ${targetDir}
|
|
5452
6059
|
`);
|
|
5453
6060
|
try {
|
|
5454
|
-
await
|
|
6061
|
+
await execAsync(`git clone --no-checkout --progress ${repoURL} ${targetDir}`, {
|
|
5455
6062
|
maxBuffer: 10 * 1024 * 1024
|
|
5456
6063
|
});
|
|
5457
|
-
await
|
|
6064
|
+
await execFileAsync3("git", ["-C", targetDir, "checkout", "--quiet", ref], {
|
|
5458
6065
|
maxBuffer: 10 * 1024 * 1024
|
|
5459
6066
|
});
|
|
5460
|
-
await
|
|
6067
|
+
await execFileAsync3(
|
|
5461
6068
|
"git",
|
|
5462
6069
|
["-C", targetDir, "submodule", "update", "--init", "--recursive", "--progress"],
|
|
5463
6070
|
{ maxBuffer: 10 * 1024 * 1024 }
|
|
@@ -5502,14 +6109,14 @@ Cloning template: ${repoURL} \u2192 extracting ${subPath}
|
|
|
5502
6109
|
}
|
|
5503
6110
|
async function cloneSparse(repoURL, ref, subPath, tempDir) {
|
|
5504
6111
|
try {
|
|
5505
|
-
await
|
|
5506
|
-
await
|
|
5507
|
-
await
|
|
6112
|
+
await execFileAsync3("git", ["init", tempDir]);
|
|
6113
|
+
await execFileAsync3("git", ["-C", tempDir, "remote", "add", "origin", repoURL]);
|
|
6114
|
+
await execFileAsync3("git", ["-C", tempDir, "config", "core.sparseCheckout", "true"]);
|
|
5508
6115
|
const sparseCheckoutPath = path4.join(tempDir, ".git/info/sparse-checkout");
|
|
5509
6116
|
fs5.writeFileSync(sparseCheckoutPath, `${subPath}
|
|
5510
6117
|
`);
|
|
5511
|
-
await
|
|
5512
|
-
await
|
|
6118
|
+
await execFileAsync3("git", ["-C", tempDir, "fetch", "origin", ref]);
|
|
6119
|
+
await execFileAsync3("git", ["-C", tempDir, "checkout", ref]);
|
|
5513
6120
|
} catch (error) {
|
|
5514
6121
|
throw new Error(`Failed to clone sparse repository: ${error.message}`);
|
|
5515
6122
|
}
|
|
@@ -6084,6 +6691,187 @@ function createAppModule(ctx) {
|
|
|
6084
6691
|
imageRef: result.imageRef
|
|
6085
6692
|
};
|
|
6086
6693
|
},
|
|
6694
|
+
// Granular deploy control
|
|
6695
|
+
async prepareDeploy(opts) {
|
|
6696
|
+
return prepareDeploy(
|
|
6697
|
+
{
|
|
6698
|
+
privateKey,
|
|
6699
|
+
rpcUrl: ctx.rpcUrl,
|
|
6700
|
+
environment: ctx.environment,
|
|
6701
|
+
appName: opts.name,
|
|
6702
|
+
instanceType: opts.instanceType,
|
|
6703
|
+
dockerfilePath: opts.dockerfile,
|
|
6704
|
+
envFilePath: opts.envFile,
|
|
6705
|
+
imageRef: opts.imageRef,
|
|
6706
|
+
logVisibility: opts.logVisibility,
|
|
6707
|
+
resourceUsageMonitoring: opts.resourceUsageMonitoring,
|
|
6708
|
+
skipTelemetry
|
|
6709
|
+
},
|
|
6710
|
+
logger
|
|
6711
|
+
);
|
|
6712
|
+
},
|
|
6713
|
+
async prepareDeployFromVerifiableBuild(opts) {
|
|
6714
|
+
return prepareDeployFromVerifiableBuild(
|
|
6715
|
+
{
|
|
6716
|
+
privateKey,
|
|
6717
|
+
rpcUrl: ctx.rpcUrl,
|
|
6718
|
+
environment: ctx.environment,
|
|
6719
|
+
appName: opts.name,
|
|
6720
|
+
instanceType: opts.instanceType,
|
|
6721
|
+
envFilePath: opts.envFile,
|
|
6722
|
+
imageRef: opts.imageRef,
|
|
6723
|
+
imageDigest: opts.imageDigest,
|
|
6724
|
+
logVisibility: opts.logVisibility,
|
|
6725
|
+
resourceUsageMonitoring: opts.resourceUsageMonitoring,
|
|
6726
|
+
skipTelemetry
|
|
6727
|
+
},
|
|
6728
|
+
logger
|
|
6729
|
+
);
|
|
6730
|
+
},
|
|
6731
|
+
async executeDeploy(prepared, gas) {
|
|
6732
|
+
const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
|
|
6733
|
+
const chain = getChainFromID(environment.chainID);
|
|
6734
|
+
const publicClient = (0, import_viem9.createPublicClient)({
|
|
6735
|
+
chain,
|
|
6736
|
+
transport: (0, import_viem9.http)(ctx.rpcUrl)
|
|
6737
|
+
});
|
|
6738
|
+
const walletClient = (0, import_viem9.createWalletClient)({
|
|
6739
|
+
account,
|
|
6740
|
+
chain,
|
|
6741
|
+
transport: (0, import_viem9.http)(ctx.rpcUrl)
|
|
6742
|
+
});
|
|
6743
|
+
const result = await executeDeploy({
|
|
6744
|
+
prepared,
|
|
6745
|
+
context: {
|
|
6746
|
+
walletClient,
|
|
6747
|
+
publicClient,
|
|
6748
|
+
environmentConfig: environment
|
|
6749
|
+
},
|
|
6750
|
+
gas,
|
|
6751
|
+
logger,
|
|
6752
|
+
skipTelemetry
|
|
6753
|
+
});
|
|
6754
|
+
return {
|
|
6755
|
+
appId: result.appId,
|
|
6756
|
+
txHash: result.txHash,
|
|
6757
|
+
appName: result.appName,
|
|
6758
|
+
imageRef: result.imageRef
|
|
6759
|
+
};
|
|
6760
|
+
},
|
|
6761
|
+
async watchDeployment(appId) {
|
|
6762
|
+
return watchDeployment(
|
|
6763
|
+
appId,
|
|
6764
|
+
privateKey,
|
|
6765
|
+
ctx.rpcUrl,
|
|
6766
|
+
ctx.environment,
|
|
6767
|
+
logger,
|
|
6768
|
+
ctx.clientId,
|
|
6769
|
+
skipTelemetry
|
|
6770
|
+
);
|
|
6771
|
+
},
|
|
6772
|
+
// Granular upgrade control
|
|
6773
|
+
async prepareUpgrade(appId, opts) {
|
|
6774
|
+
return prepareUpgrade(
|
|
6775
|
+
{
|
|
6776
|
+
appId,
|
|
6777
|
+
privateKey,
|
|
6778
|
+
rpcUrl: ctx.rpcUrl,
|
|
6779
|
+
environment: ctx.environment,
|
|
6780
|
+
instanceType: opts.instanceType,
|
|
6781
|
+
dockerfilePath: opts.dockerfile,
|
|
6782
|
+
envFilePath: opts.envFile,
|
|
6783
|
+
imageRef: opts.imageRef,
|
|
6784
|
+
logVisibility: opts.logVisibility,
|
|
6785
|
+
resourceUsageMonitoring: opts.resourceUsageMonitoring,
|
|
6786
|
+
skipTelemetry
|
|
6787
|
+
},
|
|
6788
|
+
logger
|
|
6789
|
+
);
|
|
6790
|
+
},
|
|
6791
|
+
async prepareUpgradeFromVerifiableBuild(appId, opts) {
|
|
6792
|
+
return prepareUpgradeFromVerifiableBuild(
|
|
6793
|
+
{
|
|
6794
|
+
appId,
|
|
6795
|
+
privateKey,
|
|
6796
|
+
rpcUrl: ctx.rpcUrl,
|
|
6797
|
+
environment: ctx.environment,
|
|
6798
|
+
instanceType: opts.instanceType,
|
|
6799
|
+
envFilePath: opts.envFile,
|
|
6800
|
+
imageRef: opts.imageRef,
|
|
6801
|
+
imageDigest: opts.imageDigest,
|
|
6802
|
+
logVisibility: opts.logVisibility,
|
|
6803
|
+
resourceUsageMonitoring: opts.resourceUsageMonitoring,
|
|
6804
|
+
skipTelemetry
|
|
6805
|
+
},
|
|
6806
|
+
logger
|
|
6807
|
+
);
|
|
6808
|
+
},
|
|
6809
|
+
async executeUpgrade(prepared, gas) {
|
|
6810
|
+
const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
|
|
6811
|
+
const chain = getChainFromID(environment.chainID);
|
|
6812
|
+
const publicClient = (0, import_viem9.createPublicClient)({
|
|
6813
|
+
chain,
|
|
6814
|
+
transport: (0, import_viem9.http)(ctx.rpcUrl)
|
|
6815
|
+
});
|
|
6816
|
+
const walletClient = (0, import_viem9.createWalletClient)({
|
|
6817
|
+
account,
|
|
6818
|
+
chain,
|
|
6819
|
+
transport: (0, import_viem9.http)(ctx.rpcUrl)
|
|
6820
|
+
});
|
|
6821
|
+
const result = await executeUpgrade({
|
|
6822
|
+
prepared,
|
|
6823
|
+
context: {
|
|
6824
|
+
walletClient,
|
|
6825
|
+
publicClient,
|
|
6826
|
+
environmentConfig: environment
|
|
6827
|
+
},
|
|
6828
|
+
gas,
|
|
6829
|
+
logger,
|
|
6830
|
+
skipTelemetry
|
|
6831
|
+
});
|
|
6832
|
+
return {
|
|
6833
|
+
appId: result.appId,
|
|
6834
|
+
txHash: result.txHash,
|
|
6835
|
+
imageRef: result.imageRef
|
|
6836
|
+
};
|
|
6837
|
+
},
|
|
6838
|
+
async watchUpgrade(appId) {
|
|
6839
|
+
return watchUpgrade(
|
|
6840
|
+
appId,
|
|
6841
|
+
privateKey,
|
|
6842
|
+
ctx.rpcUrl,
|
|
6843
|
+
ctx.environment,
|
|
6844
|
+
logger,
|
|
6845
|
+
ctx.clientId,
|
|
6846
|
+
skipTelemetry
|
|
6847
|
+
);
|
|
6848
|
+
},
|
|
6849
|
+
// Profile management
|
|
6850
|
+
async setProfile(appId, profile) {
|
|
6851
|
+
return withSDKTelemetry(
|
|
6852
|
+
{
|
|
6853
|
+
functionName: "setProfile",
|
|
6854
|
+
skipTelemetry,
|
|
6855
|
+
properties: { environment: ctx.environment }
|
|
6856
|
+
},
|
|
6857
|
+
async () => {
|
|
6858
|
+
const userApiClient = new UserApiClient(
|
|
6859
|
+
environment,
|
|
6860
|
+
privateKey,
|
|
6861
|
+
ctx.rpcUrl,
|
|
6862
|
+
ctx.clientId
|
|
6863
|
+
);
|
|
6864
|
+
return userApiClient.uploadAppProfile(
|
|
6865
|
+
appId,
|
|
6866
|
+
profile.name,
|
|
6867
|
+
profile.website,
|
|
6868
|
+
profile.description,
|
|
6869
|
+
profile.xURL,
|
|
6870
|
+
profile.imagePath
|
|
6871
|
+
);
|
|
6872
|
+
}
|
|
6873
|
+
);
|
|
6874
|
+
},
|
|
6087
6875
|
async logs(opts) {
|
|
6088
6876
|
return logs(
|
|
6089
6877
|
{
|