@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/dist/index.cjs CHANGED
@@ -30,10 +30,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ AuthRequiredError: () => AuthRequiredError,
34
+ BUILD_STATUS: () => BUILD_STATUS,
35
+ BadRequestError: () => BadRequestError,
36
+ BuildError: () => BuildError,
37
+ BuildFailedError: () => BuildFailedError,
38
+ ConflictError: () => ConflictError,
39
+ ForbiddenError: () => ForbiddenError,
33
40
  NoopClient: () => NoopClient,
41
+ NotFoundError: () => NotFoundError,
34
42
  PRIMARY_LANGUAGES: () => PRIMARY_LANGUAGES,
35
43
  PostHogClient: () => PostHogClient,
44
+ TimeoutError: () => TimeoutError,
36
45
  UserApiClient: () => UserApiClient,
46
+ addHexPrefix: () => addHexPrefix,
37
47
  addMetric: () => addMetric,
38
48
  addMetricWithDimensions: () => addMetricWithDimensions,
39
49
  assertValidFilePath: () => assertValidFilePath,
@@ -43,6 +53,7 @@ __export(index_exports, {
43
53
  createApp: () => createApp,
44
54
  createAppEnvironment: () => createAppEnvironment,
45
55
  createBillingModule: () => createBillingModule,
56
+ createBuildModule: () => createBuildModule,
46
57
  createComputeModule: () => createComputeModule,
47
58
  createECloudClient: () => createECloudClient,
48
59
  createMetricsContext: () => createMetricsContext,
@@ -86,12 +97,15 @@ __export(index_exports, {
86
97
  listStoredKeys: () => listStoredKeys,
87
98
  logs: () => logs,
88
99
  prepareDeploy: () => prepareDeploy,
100
+ prepareDeployFromVerifiableBuild: () => prepareDeployFromVerifiableBuild,
89
101
  prepareUpgrade: () => prepareUpgrade,
102
+ prepareUpgradeFromVerifiableBuild: () => prepareUpgradeFromVerifiableBuild,
90
103
  requirePrivateKey: () => requirePrivateKey,
91
104
  sanitizeString: () => sanitizeString,
92
105
  sanitizeURL: () => sanitizeURL,
93
106
  sanitizeXURL: () => sanitizeXURL,
94
107
  storePrivateKey: () => storePrivateKey,
108
+ stripHexPrefix: () => stripHexPrefix,
95
109
  validateAppID: () => validateAppID,
96
110
  validateAppName: () => validateAppName,
97
111
  validateCreateAppParams: () => validateCreateAppParams,
@@ -117,6 +131,7 @@ module.exports = __toCommonJS(index_exports);
117
131
 
118
132
  // src/client/modules/compute/app/index.ts
119
133
  var import_viem9 = require("viem");
134
+ var import_accounts5 = require("viem/accounts");
120
135
 
121
136
  // src/client/common/config/environment.ts
122
137
  var SEPOLIA_CHAIN_ID = 11155111;
@@ -206,7 +221,7 @@ function getBillingEnvironmentConfig(build) {
206
221
  return config;
207
222
  }
208
223
  function getBuildType() {
209
- const buildTimeType = true ? "dev"?.toLowerCase() : void 0;
224
+ const buildTimeType = true ? "prod"?.toLowerCase() : void 0;
210
225
  const runtimeType = process.env.BUILD_TYPE?.toLowerCase();
211
226
  const buildType = buildTimeType || runtimeType;
212
227
  if (buildType === "dev") {
@@ -257,6 +272,7 @@ async function buildDockerImage(buildContext, dockerfilePath, tag, logger) {
257
272
  tag,
258
273
  "-f",
259
274
  dockerfilePath,
275
+ "--load",
260
276
  "--progress=plain",
261
277
  buildContext
262
278
  ];
@@ -382,7 +398,7 @@ async function pullDockerImage(docker, imageTag, platform2 = "linux/amd64", logg
382
398
  var child_process2 = __toESM(require("child_process"), 1);
383
399
  var import_child_process = require("child_process");
384
400
  var import_util2 = require("util");
385
- var execAsync = (0, import_util2.promisify)(import_child_process.exec);
401
+ var execFileAsync = (0, import_util2.promisify)(import_child_process.execFile);
386
402
  async function pushDockerImage(docker, imageRef, logger) {
387
403
  logger?.info?.(`Pushing image ${imageRef}...`);
388
404
  return new Promise((resolve2, reject) => {
@@ -423,9 +439,9 @@ async function pushDockerImage(docker, imageRef, logger) {
423
439
  if (!output.includes("digest:") && !output.includes("pushed") && !output.includes("Pushed")) {
424
440
  logger?.debug?.("No clear success indicator in push output, verifying...");
425
441
  }
426
- logger?.info?.("Image push completed successfully");
427
442
  try {
428
443
  await verifyImageExists(imageRef, logger);
444
+ logger?.info?.("Image push completed successfully");
429
445
  resolve2();
430
446
  } catch (error) {
431
447
  reject(error);
@@ -449,7 +465,7 @@ async function verifyImageExists(imageRef, logger) {
449
465
  let retries = 5;
450
466
  while (retries > 0) {
451
467
  try {
452
- await execAsync(`docker manifest inspect ${imageRef}`, {
468
+ await execFileAsync("docker", ["manifest", "inspect", imageRef], {
453
469
  maxBuffer: 10 * 1024 * 1024,
454
470
  timeout: 1e4
455
471
  // 10 second timeout
@@ -923,10 +939,10 @@ async function setupLayeredBuildDirectory(environmentConfig, layeredDockerfileCo
923
939
  // src/client/common/registry/digest.ts
924
940
  var child_process3 = __toESM(require("child_process"), 1);
925
941
  var import_util3 = require("util");
926
- var execFileAsync = (0, import_util3.promisify)(child_process3.execFile);
942
+ var execFileAsync2 = (0, import_util3.promisify)(child_process3.execFile);
927
943
  async function getImageDigestAndName(imageRef) {
928
944
  try {
929
- const { stdout } = await execFileAsync(
945
+ const { stdout } = await execFileAsync2(
930
946
  "docker",
931
947
  ["manifest", "inspect", imageRef],
932
948
  { maxBuffer: 10 * 1024 * 1024 }
@@ -966,7 +982,7 @@ function extractDigestFromMultiPlatform(manifest, imageRef) {
966
982
  }
967
983
  async function extractDigestFromSinglePlatform(manifest, imageRef) {
968
984
  try {
969
- const { stdout } = await execFileAsync("docker", ["inspect", imageRef], {
985
+ const { stdout } = await execFileAsync2("docker", ["inspect", imageRef], {
970
986
  maxBuffer: 10 * 1024 * 1024
971
987
  });
972
988
  const inspectData = JSON.parse(stdout);
@@ -1264,6 +1280,67 @@ Please verify the image exists: docker manifest inspect ${finalImageRef}`
1264
1280
  };
1265
1281
  }
1266
1282
 
1283
+ // src/client/common/release/prebuilt.ts
1284
+ async function createReleaseFromImageDigest(options, logger) {
1285
+ const { imageRef, imageDigest, envFilePath, instanceType, environmentConfig, appId } = options;
1286
+ if (!/^sha256:[0-9a-f]{64}$/i.test(imageDigest)) {
1287
+ throw new Error(`imageDigest must be in format sha256:<64 hex>, got: ${imageDigest}`);
1288
+ }
1289
+ let publicEnv = {};
1290
+ let privateEnv = {};
1291
+ if (envFilePath) {
1292
+ logger.info("Parsing environment file...");
1293
+ const parsed = parseAndValidateEnvFile(envFilePath);
1294
+ publicEnv = parsed.public;
1295
+ privateEnv = parsed.private;
1296
+ } else {
1297
+ logger.info("Continuing without environment file");
1298
+ }
1299
+ publicEnv["EIGEN_MACHINE_TYPE_PUBLIC"] = instanceType;
1300
+ logger.info(`Instance type: ${instanceType}`);
1301
+ logger.info("Encrypting environment variables...");
1302
+ const { encryptionKey } = getKMSKeysForEnvironment(
1303
+ environmentConfig.name,
1304
+ environmentConfig.build
1305
+ );
1306
+ const protectedHeaders = getAppProtectedHeaders(appId);
1307
+ const privateEnvBytes = Buffer.from(JSON.stringify(privateEnv));
1308
+ const encryptedEnvStr = await encryptRSAOAEPAndAES256GCM(
1309
+ encryptionKey,
1310
+ privateEnvBytes,
1311
+ protectedHeaders
1312
+ );
1313
+ const digestHex = imageDigest.split(":")[1];
1314
+ const digestBytes = new Uint8Array(Buffer.from(digestHex, "hex"));
1315
+ if (digestBytes.length !== 32) {
1316
+ throw new Error(`Digest must be exactly 32 bytes, got ${digestBytes.length}`);
1317
+ }
1318
+ const registry = extractRegistryNameNoDocker(imageRef);
1319
+ return {
1320
+ rmsRelease: {
1321
+ artifacts: [{ digest: digestBytes, registry }],
1322
+ upgradeByTime: Math.floor(Date.now() / 1e3) + 3600
1323
+ },
1324
+ publicEnv: new Uint8Array(Buffer.from(JSON.stringify(publicEnv))),
1325
+ encryptedEnv: new Uint8Array(Buffer.from(encryptedEnvStr))
1326
+ };
1327
+ }
1328
+ function extractRegistryNameNoDocker(imageRef) {
1329
+ let name = imageRef;
1330
+ const tagIndex = name.lastIndexOf(":");
1331
+ if (tagIndex !== -1 && !name.substring(tagIndex + 1).includes("/")) {
1332
+ name = name.substring(0, tagIndex);
1333
+ }
1334
+ const digestIndex = name.indexOf("@");
1335
+ if (digestIndex !== -1) {
1336
+ name = name.substring(0, digestIndex);
1337
+ }
1338
+ if ([...name].filter((c) => c === "/").length === 1) {
1339
+ name = `docker.io/${name}`;
1340
+ }
1341
+ return name;
1342
+ }
1343
+
1267
1344
  // src/client/common/contract/caller.ts
1268
1345
  var import_accounts2 = require("viem/accounts");
1269
1346
 
@@ -2300,27 +2377,55 @@ var ERC7702Delegator_default = [
2300
2377
  ];
2301
2378
 
2302
2379
  // src/client/common/contract/eip7702.ts
2380
+ var EXECUTE_BATCH_MODE = "0x0100000000000000000000000000000000000000000000000000000000000000";
2381
+ var GAS_LIMIT_BUFFER_PERCENTAGE = 20n;
2382
+ var GAS_PRICE_BUFFER_PERCENTAGE = 100n;
2383
+ function encodeExecuteBatchData(executions) {
2384
+ const encodedExecutions = (0, import_viem.encodeAbiParameters)(
2385
+ [
2386
+ {
2387
+ type: "tuple[]",
2388
+ components: [
2389
+ { name: "target", type: "address" },
2390
+ { name: "value", type: "uint256" },
2391
+ { name: "callData", type: "bytes" }
2392
+ ]
2393
+ }
2394
+ ],
2395
+ [executions]
2396
+ );
2397
+ return (0, import_viem.encodeFunctionData)({
2398
+ abi: ERC7702Delegator_default,
2399
+ functionName: "execute",
2400
+ args: [EXECUTE_BATCH_MODE, encodedExecutions]
2401
+ });
2402
+ }
2303
2403
  async function estimateBatchGas(options) {
2304
- const { publicClient, executions } = options;
2305
- const fees = await publicClient.estimateFeesPerGas();
2306
- const baseGas = 100000n;
2307
- const perExecutionGas = 50000n;
2308
- const estimatedGas = baseGas + BigInt(executions.length) * perExecutionGas;
2309
- const gasLimit = estimatedGas * 120n / 100n;
2310
- const maxFeePerGas = fees.maxFeePerGas;
2311
- const maxPriorityFeePerGas = fees.maxPriorityFeePerGas;
2404
+ const { publicClient, account, executions } = options;
2405
+ const executeBatchData = encodeExecuteBatchData(executions);
2406
+ const [gasTipCap, block, estimatedGas] = await Promise.all([
2407
+ publicClient.estimateMaxPriorityFeePerGas(),
2408
+ publicClient.getBlock(),
2409
+ publicClient.estimateGas({
2410
+ account,
2411
+ to: account,
2412
+ data: executeBatchData
2413
+ })
2414
+ ]);
2415
+ const baseFee = block.baseFeePerGas ?? 0n;
2416
+ const maxFeePerGas = (baseFee + gasTipCap) * (100n + GAS_PRICE_BUFFER_PERCENTAGE) / 100n;
2417
+ const gasLimit = estimatedGas * (100n + GAS_LIMIT_BUFFER_PERCENTAGE) / 100n;
2312
2418
  const maxCostWei = gasLimit * maxFeePerGas;
2313
- const maxCostEth = formatETH(maxCostWei);
2314
2419
  return {
2315
2420
  gasLimit,
2316
2421
  maxFeePerGas,
2317
- maxPriorityFeePerGas,
2422
+ maxPriorityFeePerGas: gasTipCap,
2318
2423
  maxCostWei,
2319
- maxCostEth
2424
+ maxCostEth: formatETH(maxCostWei)
2320
2425
  };
2321
2426
  }
2322
2427
  async function checkERC7702Delegation(publicClient, account, delegatorAddress) {
2323
- const code = await publicClient.getBytecode({ address: account });
2428
+ const code = await publicClient.getCode({ address: account });
2324
2429
  if (!code) {
2325
2430
  return false;
2326
2431
  }
@@ -2337,36 +2442,7 @@ async function executeBatch(options, logger) {
2337
2442
  if (!chain) {
2338
2443
  throw new Error("Wallet client must have a chain");
2339
2444
  }
2340
- const encodedExecutions = (0, import_viem.encodeAbiParameters)(
2341
- [
2342
- {
2343
- type: "tuple[]",
2344
- components: [
2345
- { name: "target", type: "address" },
2346
- { name: "value", type: "uint256" },
2347
- { name: "callData", type: "bytes" }
2348
- ]
2349
- }
2350
- ],
2351
- [executions]
2352
- );
2353
- const executeBatchMode = "0x0100000000000000000000000000000000000000000000000000000000000000";
2354
- let executeBatchData;
2355
- try {
2356
- executeBatchData = (0, import_viem.encodeFunctionData)({
2357
- abi: ERC7702Delegator_default,
2358
- functionName: "execute",
2359
- args: [executeBatchMode, encodedExecutions]
2360
- });
2361
- } catch {
2362
- const functionSignature = "execute(bytes32,bytes)";
2363
- const selector = (0, import_viem.keccak256)((0, import_viem.toBytes)(functionSignature)).slice(0, 10);
2364
- const encodedParams = (0, import_viem.encodeAbiParameters)(
2365
- [{ type: "bytes32" }, { type: "bytes" }],
2366
- [executeBatchMode, encodedExecutions]
2367
- );
2368
- executeBatchData = (0, import_viem.concat)([selector, encodedParams]);
2369
- }
2445
+ const executeBatchData = encodeExecuteBatchData(executions);
2370
2446
  const isDelegated2 = await checkERC7702Delegation(
2371
2447
  publicClient,
2372
2448
  account.address,
@@ -2520,12 +2596,23 @@ function stripHexPrefix(value) {
2520
2596
  }
2521
2597
 
2522
2598
  // src/client/common/utils/userapi.ts
2599
+ function isJsonObject(value) {
2600
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2601
+ }
2602
+ function readString(obj, key) {
2603
+ const v = obj[key];
2604
+ return typeof v === "string" ? v : void 0;
2605
+ }
2606
+ function readNumber(obj, key) {
2607
+ const v = obj[key];
2608
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
2609
+ }
2523
2610
  var MAX_ADDRESS_COUNT = 5;
2524
2611
  var CanViewAppLogsPermission = "0x2fd3f2fe";
2525
2612
  var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
2526
2613
  var CanUpdateAppProfilePermission = "0x036fef61";
2527
2614
  function getDefaultClientId() {
2528
- const version = true ? "0.2.0-dev.2" : "0.0.0";
2615
+ const version = true ? "0.2.0" : "0.0.0";
2529
2616
  return `ecloud-sdk/v${version}`;
2530
2617
  }
2531
2618
  var UserApiClient = class {
@@ -2559,6 +2646,31 @@ var UserApiClient = class {
2559
2646
  };
2560
2647
  });
2561
2648
  }
2649
+ /**
2650
+ * Get app details from UserAPI (includes releases and build/provenance info when available).
2651
+ *
2652
+ * Endpoint: GET /apps/:appAddress
2653
+ */
2654
+ async getApp(appAddress) {
2655
+ const endpoint = `${this.config.userApiServerURL}/apps/${appAddress}`;
2656
+ const res = await this.makeAuthenticatedRequest(endpoint);
2657
+ const raw = await res.json();
2658
+ if (!isJsonObject(raw)) {
2659
+ throw new Error("Unexpected /apps/:id response: expected object");
2660
+ }
2661
+ const id = readString(raw, "id");
2662
+ if (!id) {
2663
+ throw new Error("Unexpected /apps/:id response: missing 'id'");
2664
+ }
2665
+ const releasesRaw = raw.releases;
2666
+ const releases = Array.isArray(releasesRaw) ? releasesRaw.map((r) => transformAppRelease(r)).filter((r) => !!r) : [];
2667
+ return {
2668
+ id,
2669
+ creator: readString(raw, "creator"),
2670
+ contractStatus: readString(raw, "contract_status") ?? readString(raw, "contractStatus"),
2671
+ releases
2672
+ };
2673
+ }
2562
2674
  /**
2563
2675
  * Get available SKUs (instance types) from UserAPI
2564
2676
  */
@@ -2731,6 +2843,48 @@ Please check:
2731
2843
  };
2732
2844
  }
2733
2845
  };
2846
+ function transformAppReleaseBuild(raw) {
2847
+ if (!isJsonObject(raw)) return void 0;
2848
+ const depsRaw = raw.dependencies;
2849
+ const deps = isJsonObject(depsRaw) ? Object.fromEntries(
2850
+ Object.entries(depsRaw).flatMap(([digest, depRaw]) => {
2851
+ const parsed = transformAppReleaseBuild(depRaw);
2852
+ return parsed ? [[digest, parsed]] : [];
2853
+ })
2854
+ ) : void 0;
2855
+ return {
2856
+ buildId: readString(raw, "build_id") ?? readString(raw, "buildId"),
2857
+ billingAddress: readString(raw, "billing_address") ?? readString(raw, "billingAddress"),
2858
+ repoUrl: readString(raw, "repo_url") ?? readString(raw, "repoUrl"),
2859
+ gitRef: readString(raw, "git_ref") ?? readString(raw, "gitRef"),
2860
+ status: readString(raw, "status"),
2861
+ buildType: readString(raw, "build_type") ?? readString(raw, "buildType"),
2862
+ imageName: readString(raw, "image_name") ?? readString(raw, "imageName"),
2863
+ imageDigest: readString(raw, "image_digest") ?? readString(raw, "imageDigest"),
2864
+ imageUrl: readString(raw, "image_url") ?? readString(raw, "imageUrl"),
2865
+ provenanceJson: raw.provenance_json ?? raw.provenanceJson,
2866
+ provenanceSignature: readString(raw, "provenance_signature") ?? readString(raw, "provenanceSignature"),
2867
+ createdAt: readString(raw, "created_at") ?? readString(raw, "createdAt"),
2868
+ updatedAt: readString(raw, "updated_at") ?? readString(raw, "updatedAt"),
2869
+ errorMessage: readString(raw, "error_message") ?? readString(raw, "errorMessage"),
2870
+ dependencies: deps
2871
+ };
2872
+ }
2873
+ function transformAppRelease(raw) {
2874
+ if (!isJsonObject(raw)) return void 0;
2875
+ return {
2876
+ appId: readString(raw, "appId") ?? readString(raw, "app_id"),
2877
+ rmsReleaseId: readString(raw, "rmsReleaseId") ?? readString(raw, "rms_release_id"),
2878
+ imageDigest: readString(raw, "imageDigest") ?? readString(raw, "image_digest"),
2879
+ registryUrl: readString(raw, "registryUrl") ?? readString(raw, "registry_url"),
2880
+ publicEnv: readString(raw, "publicEnv") ?? readString(raw, "public_env"),
2881
+ encryptedEnv: readString(raw, "encryptedEnv") ?? readString(raw, "encrypted_env"),
2882
+ upgradeByTime: readNumber(raw, "upgradeByTime") ?? readNumber(raw, "upgrade_by_time"),
2883
+ createdAt: readString(raw, "createdAt") ?? readString(raw, "created_at"),
2884
+ createdAtBlock: readString(raw, "createdAtBlock") ?? readString(raw, "created_at_block"),
2885
+ build: raw.build ? transformAppReleaseBuild(raw.build) : void 0
2886
+ };
2887
+ }
2734
2888
 
2735
2889
  // src/client/common/utils/billing.ts
2736
2890
  function isSubscriptionActive(status) {
@@ -4423,20 +4577,20 @@ async function prepareDeployBatch(options, logger) {
4423
4577
  environmentConfig
4424
4578
  };
4425
4579
  }
4426
- async function executeDeployBatch(prepared, gas, logger) {
4580
+ async function executeDeployBatch(data, context, gas, logger) {
4427
4581
  const pendingMessage = "Deploying new app...";
4428
4582
  const txHash = await executeBatch(
4429
4583
  {
4430
- walletClient: prepared.walletClient,
4431
- publicClient: prepared.publicClient,
4432
- environmentConfig: prepared.environmentConfig,
4433
- executions: prepared.executions,
4584
+ walletClient: context.walletClient,
4585
+ publicClient: context.publicClient,
4586
+ environmentConfig: context.environmentConfig,
4587
+ executions: data.executions,
4434
4588
  pendingMessage,
4435
4589
  gas
4436
4590
  },
4437
4591
  logger
4438
4592
  );
4439
- return { appId: prepared.appId, txHash };
4593
+ return { appId: data.appId, txHash };
4440
4594
  }
4441
4595
  async function deployApp(options, logger) {
4442
4596
  const prepared = await prepareDeployBatch(
@@ -4450,7 +4604,17 @@ async function deployApp(options, logger) {
4450
4604
  },
4451
4605
  logger
4452
4606
  );
4453
- return executeDeployBatch(prepared, options.gas, logger);
4607
+ const data = {
4608
+ appId: prepared.appId,
4609
+ salt: prepared.salt,
4610
+ executions: prepared.executions
4611
+ };
4612
+ const context = {
4613
+ walletClient: prepared.walletClient,
4614
+ publicClient: prepared.publicClient,
4615
+ environmentConfig: prepared.environmentConfig
4616
+ };
4617
+ return executeDeployBatch(data, context, options.gas, logger);
4454
4618
  }
4455
4619
  async function prepareUpgradeBatch(options) {
4456
4620
  const {
@@ -4546,14 +4710,14 @@ async function prepareUpgradeBatch(options) {
4546
4710
  environmentConfig
4547
4711
  };
4548
4712
  }
4549
- async function executeUpgradeBatch(prepared, gas, logger) {
4550
- const pendingMessage = `Upgrading app ${prepared.appId}...`;
4713
+ async function executeUpgradeBatch(data, context, gas, logger) {
4714
+ const pendingMessage = `Upgrading app ${data.appId}...`;
4551
4715
  const txHash = await executeBatch(
4552
4716
  {
4553
- walletClient: prepared.walletClient,
4554
- publicClient: prepared.publicClient,
4555
- environmentConfig: prepared.environmentConfig,
4556
- executions: prepared.executions,
4717
+ walletClient: context.walletClient,
4718
+ publicClient: context.publicClient,
4719
+ environmentConfig: context.environmentConfig,
4720
+ executions: data.executions,
4557
4721
  pendingMessage,
4558
4722
  gas
4559
4723
  },
@@ -4571,7 +4735,16 @@ async function upgradeApp(options, logger) {
4571
4735
  publicLogs: options.publicLogs,
4572
4736
  needsPermissionChange: options.needsPermissionChange
4573
4737
  });
4574
- return executeUpgradeBatch(prepared, options.gas, logger);
4738
+ const data = {
4739
+ appId: prepared.appId,
4740
+ executions: prepared.executions
4741
+ };
4742
+ const context = {
4743
+ walletClient: prepared.walletClient,
4744
+ publicClient: prepared.publicClient,
4745
+ environmentConfig: prepared.environmentConfig
4746
+ };
4747
+ return executeUpgradeBatch(data, context, options.gas, logger);
4575
4748
  }
4576
4749
  async function sendAndWaitForTransaction(options, logger) {
4577
4750
  const {
@@ -5533,6 +5706,97 @@ async function withSDKTelemetry(options, action) {
5533
5706
  }
5534
5707
 
5535
5708
  // src/client/modules/compute/app/deploy.ts
5709
+ async function prepareDeployFromVerifiableBuild(options, logger = defaultLogger) {
5710
+ return withSDKTelemetry(
5711
+ {
5712
+ functionName: "prepareDeployFromVerifiableBuild",
5713
+ skipTelemetry: options.skipTelemetry,
5714
+ properties: {
5715
+ environment: options.environment || "sepolia"
5716
+ }
5717
+ },
5718
+ async () => {
5719
+ if (!options.privateKey) throw new Error("privateKey is required for deployment");
5720
+ if (!options.imageRef) throw new Error("imageRef is required for deployment");
5721
+ if (!options.imageDigest) throw new Error("imageDigest is required for deployment");
5722
+ assertValidImageReference(options.imageRef);
5723
+ validateAppName(options.appName);
5724
+ validateLogVisibility(options.logVisibility);
5725
+ if (!/^sha256:[0-9a-f]{64}$/i.test(options.imageDigest)) {
5726
+ throw new Error(
5727
+ `imageDigest must be in format sha256:<64 hex>, got: ${options.imageDigest}`
5728
+ );
5729
+ }
5730
+ const { publicLogs } = validateLogVisibility(options.logVisibility);
5731
+ validateResourceUsageMonitoring(options.resourceUsageMonitoring);
5732
+ logger.debug("Performing preflight checks...");
5733
+ const preflightCtx = await doPreflightChecks(
5734
+ {
5735
+ privateKey: options.privateKey,
5736
+ rpcUrl: options.rpcUrl,
5737
+ environment: options.environment
5738
+ },
5739
+ logger
5740
+ );
5741
+ logger.debug("Checking quota availability...");
5742
+ await checkQuotaAvailable(preflightCtx);
5743
+ const salt = generateRandomSalt();
5744
+ logger.debug(`Generated salt: ${Buffer.from(salt).toString("hex")}`);
5745
+ logger.debug("Calculating app ID...");
5746
+ const appIDToBeDeployed = await calculateAppID(
5747
+ preflightCtx.privateKey,
5748
+ options.rpcUrl || preflightCtx.rpcUrl,
5749
+ preflightCtx.environmentConfig,
5750
+ salt
5751
+ );
5752
+ logger.info(``);
5753
+ logger.info(`App ID: ${appIDToBeDeployed}`);
5754
+ logger.info(``);
5755
+ const release = await createReleaseFromImageDigest(
5756
+ {
5757
+ imageRef: options.imageRef,
5758
+ imageDigest: options.imageDigest,
5759
+ envFilePath: options.envFilePath,
5760
+ instanceType: options.instanceType,
5761
+ environmentConfig: preflightCtx.environmentConfig,
5762
+ appId: appIDToBeDeployed
5763
+ },
5764
+ logger
5765
+ );
5766
+ logger.debug("Preparing deploy batch...");
5767
+ const batch = await prepareDeployBatch(
5768
+ {
5769
+ privateKey: preflightCtx.privateKey,
5770
+ rpcUrl: options.rpcUrl || preflightCtx.rpcUrl,
5771
+ environmentConfig: preflightCtx.environmentConfig,
5772
+ salt,
5773
+ release,
5774
+ publicLogs
5775
+ },
5776
+ logger
5777
+ );
5778
+ logger.debug("Estimating gas...");
5779
+ const gasEstimate = await estimateBatchGas({
5780
+ publicClient: batch.publicClient,
5781
+ account: batch.walletClient.account.address,
5782
+ executions: batch.executions
5783
+ });
5784
+ const data = {
5785
+ appId: batch.appId,
5786
+ salt: batch.salt,
5787
+ executions: batch.executions
5788
+ };
5789
+ return {
5790
+ prepared: {
5791
+ data,
5792
+ appName: options.appName,
5793
+ imageRef: options.imageRef
5794
+ },
5795
+ gasEstimate
5796
+ };
5797
+ }
5798
+ );
5799
+ }
5536
5800
  function validateDeployOptions(options) {
5537
5801
  if (!options.privateKey) {
5538
5802
  throw new Error("privateKey is required for deployment");
@@ -5753,26 +6017,27 @@ async function prepareDeploy(options, logger = defaultLogger) {
5753
6017
  logger.debug("Estimating gas...");
5754
6018
  const gasEstimate = await estimateBatchGas({
5755
6019
  publicClient: batch.publicClient,
5756
- environmentConfig: batch.environmentConfig,
6020
+ account: batch.walletClient.account.address,
5757
6021
  executions: batch.executions
5758
6022
  });
6023
+ const data = {
6024
+ appId: batch.appId,
6025
+ salt: batch.salt,
6026
+ executions: batch.executions
6027
+ };
5759
6028
  return {
5760
6029
  prepared: {
5761
- batch,
6030
+ data,
5762
6031
  appName,
5763
- imageRef: finalImageRef,
5764
- preflightCtx: {
5765
- privateKey: preflightCtx.privateKey,
5766
- rpcUrl: preflightCtx.rpcUrl,
5767
- environmentConfig: preflightCtx.environmentConfig
5768
- }
6032
+ imageRef: finalImageRef
5769
6033
  },
5770
6034
  gasEstimate
5771
6035
  };
5772
6036
  }
5773
6037
  );
5774
6038
  }
5775
- async function executeDeploy(prepared, gas, logger = defaultLogger, skipTelemetry) {
6039
+ async function executeDeploy(options) {
6040
+ const { prepared, context, gas, logger = defaultLogger, skipTelemetry } = options;
5776
6041
  return withSDKTelemetry(
5777
6042
  {
5778
6043
  functionName: "executeDeploy",
@@ -5780,7 +6045,7 @@ async function executeDeploy(prepared, gas, logger = defaultLogger, skipTelemetr
5780
6045
  },
5781
6046
  async () => {
5782
6047
  logger.info("Deploying on-chain...");
5783
- const { appId, txHash } = await executeDeployBatch(prepared.batch, gas, logger);
6048
+ const { appId, txHash } = await executeDeployBatch(prepared.data, context, gas, logger);
5784
6049
  return {
5785
6050
  appId,
5786
6051
  txHash,
@@ -5842,6 +6107,81 @@ async function checkAppLogPermission(preflightCtx, appAddress, logger) {
5842
6107
  }
5843
6108
 
5844
6109
  // src/client/modules/compute/app/upgrade.ts
6110
+ async function prepareUpgradeFromVerifiableBuild(options, logger = defaultLogger) {
6111
+ return withSDKTelemetry(
6112
+ {
6113
+ functionName: "prepareUpgradeFromVerifiableBuild",
6114
+ skipTelemetry: options.skipTelemetry,
6115
+ properties: {
6116
+ environment: options.environment || "sepolia"
6117
+ }
6118
+ },
6119
+ async () => {
6120
+ logger.debug("Performing preflight checks...");
6121
+ const preflightCtx = await doPreflightChecks(
6122
+ {
6123
+ privateKey: options.privateKey,
6124
+ rpcUrl: options.rpcUrl,
6125
+ environment: options.environment
6126
+ },
6127
+ logger
6128
+ );
6129
+ const appID = validateUpgradeOptions(options);
6130
+ assertValidImageReference(options.imageRef);
6131
+ if (!/^sha256:[0-9a-f]{64}$/i.test(options.imageDigest)) {
6132
+ throw new Error(
6133
+ `imageDigest must be in format sha256:<64 hex>, got: ${options.imageDigest}`
6134
+ );
6135
+ }
6136
+ const { publicLogs } = validateLogVisibility(options.logVisibility);
6137
+ validateResourceUsageMonitoring(options.resourceUsageMonitoring);
6138
+ const envFilePath = options.envFilePath || "";
6139
+ logger.info("Preparing release (verifiable build, no local layering)...");
6140
+ const release = await createReleaseFromImageDigest(
6141
+ {
6142
+ imageRef: options.imageRef,
6143
+ imageDigest: options.imageDigest,
6144
+ envFilePath,
6145
+ instanceType: options.instanceType,
6146
+ environmentConfig: preflightCtx.environmentConfig,
6147
+ appId: appID
6148
+ },
6149
+ logger
6150
+ );
6151
+ logger.debug("Checking current log permission state...");
6152
+ const currentlyPublic = await checkAppLogPermission(preflightCtx, appID, logger);
6153
+ const needsPermissionChange = currentlyPublic !== publicLogs;
6154
+ logger.debug("Preparing upgrade batch...");
6155
+ const batch = await prepareUpgradeBatch({
6156
+ privateKey: preflightCtx.privateKey,
6157
+ rpcUrl: options.rpcUrl || preflightCtx.rpcUrl,
6158
+ environmentConfig: preflightCtx.environmentConfig,
6159
+ appId: appID,
6160
+ release,
6161
+ publicLogs,
6162
+ needsPermissionChange
6163
+ });
6164
+ logger.debug("Estimating gas...");
6165
+ const gasEstimate = await estimateBatchGas({
6166
+ publicClient: batch.publicClient,
6167
+ account: batch.walletClient.account.address,
6168
+ executions: batch.executions
6169
+ });
6170
+ const data = {
6171
+ appId: batch.appId,
6172
+ executions: batch.executions
6173
+ };
6174
+ return {
6175
+ prepared: {
6176
+ data,
6177
+ appId: appID,
6178
+ imageRef: options.imageRef
6179
+ },
6180
+ gasEstimate
6181
+ };
6182
+ }
6183
+ );
6184
+ }
5845
6185
  function validateUpgradeOptions(options) {
5846
6186
  if (!options.privateKey) {
5847
6187
  throw new Error("privateKey is required for upgrade");
@@ -6004,26 +6344,26 @@ async function prepareUpgrade(options, logger = defaultLogger) {
6004
6344
  logger.debug("Estimating gas...");
6005
6345
  const gasEstimate = await estimateBatchGas({
6006
6346
  publicClient: batch.publicClient,
6007
- environmentConfig: batch.environmentConfig,
6347
+ account: batch.walletClient.account.address,
6008
6348
  executions: batch.executions
6009
6349
  });
6350
+ const data = {
6351
+ appId: batch.appId,
6352
+ executions: batch.executions
6353
+ };
6010
6354
  return {
6011
6355
  prepared: {
6012
- batch,
6356
+ data,
6013
6357
  appId: appID,
6014
- imageRef: finalImageRef,
6015
- preflightCtx: {
6016
- privateKey: preflightCtx.privateKey,
6017
- rpcUrl: preflightCtx.rpcUrl,
6018
- environmentConfig: preflightCtx.environmentConfig
6019
- }
6358
+ imageRef: finalImageRef
6020
6359
  },
6021
6360
  gasEstimate
6022
6361
  };
6023
6362
  }
6024
6363
  );
6025
6364
  }
6026
- async function executeUpgrade(prepared, gas, logger = defaultLogger, skipTelemetry) {
6365
+ async function executeUpgrade(options) {
6366
+ const { prepared, context, gas, logger = defaultLogger, skipTelemetry } = options;
6027
6367
  return withSDKTelemetry(
6028
6368
  {
6029
6369
  functionName: "executeUpgrade",
@@ -6031,7 +6371,7 @@ async function executeUpgrade(prepared, gas, logger = defaultLogger, skipTelemet
6031
6371
  },
6032
6372
  async () => {
6033
6373
  logger.info("Upgrading on-chain...");
6034
- const txHash = await executeUpgradeBatch(prepared.batch, gas, logger);
6374
+ const txHash = await executeUpgradeBatch(prepared.data, context, gas, logger);
6035
6375
  return {
6036
6376
  appId: prepared.appId,
6037
6377
  imageRef: prepared.imageRef,
@@ -6162,8 +6502,8 @@ var path5 = __toESM(require("path"), 1);
6162
6502
  var os3 = __toESM(require("os"), 1);
6163
6503
  var import_child_process2 = require("child_process");
6164
6504
  var import_util4 = require("util");
6165
- var execAsync2 = (0, import_util4.promisify)(import_child_process2.exec);
6166
- var execFileAsync2 = (0, import_util4.promisify)(import_child_process2.execFile);
6505
+ var execAsync = (0, import_util4.promisify)(import_child_process2.exec);
6506
+ var execFileAsync3 = (0, import_util4.promisify)(import_child_process2.execFile);
6167
6507
  async function fetchTemplate(repoURL, ref, targetDir, config, logger) {
6168
6508
  if (!repoURL) {
6169
6509
  throw new Error("repoURL is required");
@@ -6172,13 +6512,13 @@ async function fetchTemplate(repoURL, ref, targetDir, config, logger) {
6172
6512
  Cloning repo: ${repoURL} \u2192 ${targetDir}
6173
6513
  `);
6174
6514
  try {
6175
- await execAsync2(`git clone --no-checkout --progress ${repoURL} ${targetDir}`, {
6515
+ await execAsync(`git clone --no-checkout --progress ${repoURL} ${targetDir}`, {
6176
6516
  maxBuffer: 10 * 1024 * 1024
6177
6517
  });
6178
- await execFileAsync2("git", ["-C", targetDir, "checkout", "--quiet", ref], {
6518
+ await execFileAsync3("git", ["-C", targetDir, "checkout", "--quiet", ref], {
6179
6519
  maxBuffer: 10 * 1024 * 1024
6180
6520
  });
6181
- await execFileAsync2(
6521
+ await execFileAsync3(
6182
6522
  "git",
6183
6523
  ["-C", targetDir, "submodule", "update", "--init", "--recursive", "--progress"],
6184
6524
  { maxBuffer: 10 * 1024 * 1024 }
@@ -6223,14 +6563,14 @@ Cloning template: ${repoURL} \u2192 extracting ${subPath}
6223
6563
  }
6224
6564
  async function cloneSparse(repoURL, ref, subPath, tempDir) {
6225
6565
  try {
6226
- await execFileAsync2("git", ["init", tempDir]);
6227
- await execFileAsync2("git", ["-C", tempDir, "remote", "add", "origin", repoURL]);
6228
- await execFileAsync2("git", ["-C", tempDir, "config", "core.sparseCheckout", "true"]);
6566
+ await execFileAsync3("git", ["init", tempDir]);
6567
+ await execFileAsync3("git", ["-C", tempDir, "remote", "add", "origin", repoURL]);
6568
+ await execFileAsync3("git", ["-C", tempDir, "config", "core.sparseCheckout", "true"]);
6229
6569
  const sparseCheckoutPath = path5.join(tempDir, ".git/info/sparse-checkout");
6230
6570
  fs5.writeFileSync(sparseCheckoutPath, `${subPath}
6231
6571
  `);
6232
- await execFileAsync2("git", ["-C", tempDir, "fetch", "origin", ref]);
6233
- await execFileAsync2("git", ["-C", tempDir, "checkout", ref]);
6572
+ await execFileAsync3("git", ["-C", tempDir, "fetch", "origin", ref]);
6573
+ await execFileAsync3("git", ["-C", tempDir, "checkout", ref]);
6234
6574
  } catch (error) {
6235
6575
  throw new Error(`Failed to clone sparse repository: ${error.message}`);
6236
6576
  }
@@ -6805,6 +7145,187 @@ function createAppModule(ctx) {
6805
7145
  imageRef: result.imageRef
6806
7146
  };
6807
7147
  },
7148
+ // Granular deploy control
7149
+ async prepareDeploy(opts) {
7150
+ return prepareDeploy(
7151
+ {
7152
+ privateKey,
7153
+ rpcUrl: ctx.rpcUrl,
7154
+ environment: ctx.environment,
7155
+ appName: opts.name,
7156
+ instanceType: opts.instanceType,
7157
+ dockerfilePath: opts.dockerfile,
7158
+ envFilePath: opts.envFile,
7159
+ imageRef: opts.imageRef,
7160
+ logVisibility: opts.logVisibility,
7161
+ resourceUsageMonitoring: opts.resourceUsageMonitoring,
7162
+ skipTelemetry
7163
+ },
7164
+ logger
7165
+ );
7166
+ },
7167
+ async prepareDeployFromVerifiableBuild(opts) {
7168
+ return prepareDeployFromVerifiableBuild(
7169
+ {
7170
+ privateKey,
7171
+ rpcUrl: ctx.rpcUrl,
7172
+ environment: ctx.environment,
7173
+ appName: opts.name,
7174
+ instanceType: opts.instanceType,
7175
+ envFilePath: opts.envFile,
7176
+ imageRef: opts.imageRef,
7177
+ imageDigest: opts.imageDigest,
7178
+ logVisibility: opts.logVisibility,
7179
+ resourceUsageMonitoring: opts.resourceUsageMonitoring,
7180
+ skipTelemetry
7181
+ },
7182
+ logger
7183
+ );
7184
+ },
7185
+ async executeDeploy(prepared, gas) {
7186
+ const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
7187
+ const chain = getChainFromID(environment.chainID);
7188
+ const publicClient = (0, import_viem9.createPublicClient)({
7189
+ chain,
7190
+ transport: (0, import_viem9.http)(ctx.rpcUrl)
7191
+ });
7192
+ const walletClient = (0, import_viem9.createWalletClient)({
7193
+ account,
7194
+ chain,
7195
+ transport: (0, import_viem9.http)(ctx.rpcUrl)
7196
+ });
7197
+ const result = await executeDeploy({
7198
+ prepared,
7199
+ context: {
7200
+ walletClient,
7201
+ publicClient,
7202
+ environmentConfig: environment
7203
+ },
7204
+ gas,
7205
+ logger,
7206
+ skipTelemetry
7207
+ });
7208
+ return {
7209
+ appId: result.appId,
7210
+ txHash: result.txHash,
7211
+ appName: result.appName,
7212
+ imageRef: result.imageRef
7213
+ };
7214
+ },
7215
+ async watchDeployment(appId) {
7216
+ return watchDeployment(
7217
+ appId,
7218
+ privateKey,
7219
+ ctx.rpcUrl,
7220
+ ctx.environment,
7221
+ logger,
7222
+ ctx.clientId,
7223
+ skipTelemetry
7224
+ );
7225
+ },
7226
+ // Granular upgrade control
7227
+ async prepareUpgrade(appId, opts) {
7228
+ return prepareUpgrade(
7229
+ {
7230
+ appId,
7231
+ privateKey,
7232
+ rpcUrl: ctx.rpcUrl,
7233
+ environment: ctx.environment,
7234
+ instanceType: opts.instanceType,
7235
+ dockerfilePath: opts.dockerfile,
7236
+ envFilePath: opts.envFile,
7237
+ imageRef: opts.imageRef,
7238
+ logVisibility: opts.logVisibility,
7239
+ resourceUsageMonitoring: opts.resourceUsageMonitoring,
7240
+ skipTelemetry
7241
+ },
7242
+ logger
7243
+ );
7244
+ },
7245
+ async prepareUpgradeFromVerifiableBuild(appId, opts) {
7246
+ return prepareUpgradeFromVerifiableBuild(
7247
+ {
7248
+ appId,
7249
+ privateKey,
7250
+ rpcUrl: ctx.rpcUrl,
7251
+ environment: ctx.environment,
7252
+ instanceType: opts.instanceType,
7253
+ envFilePath: opts.envFile,
7254
+ imageRef: opts.imageRef,
7255
+ imageDigest: opts.imageDigest,
7256
+ logVisibility: opts.logVisibility,
7257
+ resourceUsageMonitoring: opts.resourceUsageMonitoring,
7258
+ skipTelemetry
7259
+ },
7260
+ logger
7261
+ );
7262
+ },
7263
+ async executeUpgrade(prepared, gas) {
7264
+ const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
7265
+ const chain = getChainFromID(environment.chainID);
7266
+ const publicClient = (0, import_viem9.createPublicClient)({
7267
+ chain,
7268
+ transport: (0, import_viem9.http)(ctx.rpcUrl)
7269
+ });
7270
+ const walletClient = (0, import_viem9.createWalletClient)({
7271
+ account,
7272
+ chain,
7273
+ transport: (0, import_viem9.http)(ctx.rpcUrl)
7274
+ });
7275
+ const result = await executeUpgrade({
7276
+ prepared,
7277
+ context: {
7278
+ walletClient,
7279
+ publicClient,
7280
+ environmentConfig: environment
7281
+ },
7282
+ gas,
7283
+ logger,
7284
+ skipTelemetry
7285
+ });
7286
+ return {
7287
+ appId: result.appId,
7288
+ txHash: result.txHash,
7289
+ imageRef: result.imageRef
7290
+ };
7291
+ },
7292
+ async watchUpgrade(appId) {
7293
+ return watchUpgrade(
7294
+ appId,
7295
+ privateKey,
7296
+ ctx.rpcUrl,
7297
+ ctx.environment,
7298
+ logger,
7299
+ ctx.clientId,
7300
+ skipTelemetry
7301
+ );
7302
+ },
7303
+ // Profile management
7304
+ async setProfile(appId, profile) {
7305
+ return withSDKTelemetry(
7306
+ {
7307
+ functionName: "setProfile",
7308
+ skipTelemetry,
7309
+ properties: { environment: ctx.environment }
7310
+ },
7311
+ async () => {
7312
+ const userApiClient = new UserApiClient(
7313
+ environment,
7314
+ privateKey,
7315
+ ctx.rpcUrl,
7316
+ ctx.clientId
7317
+ );
7318
+ return userApiClient.uploadAppProfile(
7319
+ appId,
7320
+ profile.name,
7321
+ profile.website,
7322
+ profile.description,
7323
+ profile.xURL,
7324
+ profile.imagePath
7325
+ );
7326
+ }
7327
+ );
7328
+ },
6808
7329
  async logs(opts) {
6809
7330
  return logs(
6810
7331
  {
@@ -6955,10 +7476,10 @@ function createComputeModule(config) {
6955
7476
 
6956
7477
  // src/client/common/utils/billingapi.ts
6957
7478
  var import_axios2 = __toESM(require("axios"), 1);
6958
- var import_accounts5 = require("viem/accounts");
7479
+ var import_accounts6 = require("viem/accounts");
6959
7480
  var BillingApiClient = class {
6960
7481
  constructor(config, privateKey) {
6961
- this.account = (0, import_accounts5.privateKeyToAccount)(privateKey);
7482
+ this.account = (0, import_accounts6.privateKeyToAccount)(privateKey);
6962
7483
  this.config = config;
6963
7484
  }
6964
7485
  async createSubscription(productId = "compute") {
@@ -7028,7 +7549,7 @@ Please check:
7028
7549
 
7029
7550
  // src/client/common/auth/keyring.ts
7030
7551
  var import_keyring = require("@napi-rs/keyring");
7031
- var import_accounts6 = require("viem/accounts");
7552
+ var import_accounts7 = require("viem/accounts");
7032
7553
  var SERVICE_NAME = "ecloud";
7033
7554
  var ACCOUNT_NAME = "key";
7034
7555
  var EIGENX_SERVICE_NAME = "eigenx-cli";
@@ -7173,7 +7694,7 @@ function validatePrivateKey2(privateKey) {
7173
7694
  }
7174
7695
  function getAddressFromPrivateKey(privateKey) {
7175
7696
  const normalized = normalizePrivateKey(privateKey);
7176
- return (0, import_accounts6.privateKeyToAddress)(normalized);
7697
+ return (0, import_accounts7.privateKeyToAddress)(normalized);
7177
7698
  }
7178
7699
  function decodeGoKeyringValue(rawValue) {
7179
7700
  if (rawValue.startsWith(GO_KEYRING_BASE64_PREFIX)) {
@@ -7255,10 +7776,10 @@ async function requirePrivateKey(options) {
7255
7776
  }
7256
7777
 
7257
7778
  // src/client/common/auth/generate.ts
7258
- var import_accounts7 = require("viem/accounts");
7779
+ var import_accounts8 = require("viem/accounts");
7259
7780
  function generateNewPrivateKey() {
7260
- const privateKey = (0, import_accounts7.generatePrivateKey)();
7261
- const address = (0, import_accounts7.privateKeyToAddress)(privateKey);
7781
+ const privateKey = (0, import_accounts8.generatePrivateKey)();
7782
+ const address = (0, import_accounts8.privateKeyToAddress)(privateKey);
7262
7783
  return {
7263
7784
  privateKey,
7264
7785
  address
@@ -7360,6 +7881,360 @@ function createBillingModule(config) {
7360
7881
  };
7361
7882
  }
7362
7883
 
7884
+ // src/client/common/utils/buildapi.ts
7885
+ var import_axios3 = __toESM(require("axios"), 1);
7886
+ var import_accounts9 = require("viem/accounts");
7887
+ var BuildApiClient = class {
7888
+ constructor(options) {
7889
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
7890
+ this.clientId = options.clientId;
7891
+ if (options.privateKey) {
7892
+ this.account = (0, import_accounts9.privateKeyToAccount)(options.privateKey);
7893
+ }
7894
+ }
7895
+ async submitBuild(payload) {
7896
+ return this.authenticatedJsonRequest("/builds", "POST", payload);
7897
+ }
7898
+ async getBuild(buildId) {
7899
+ return this.publicJsonRequest(`/builds/${encodeURIComponent(buildId)}`);
7900
+ }
7901
+ async getBuildByDigest(digest) {
7902
+ return this.publicJsonRequest(`/builds/image/${encodeURIComponent(digest)}`);
7903
+ }
7904
+ async verify(identifier) {
7905
+ return this.publicJsonRequest(`/builds/verify/${encodeURIComponent(identifier)}`);
7906
+ }
7907
+ async getLogs(buildId) {
7908
+ return this.authenticatedTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
7909
+ }
7910
+ async listBuilds(params) {
7911
+ const res = await (0, import_axios3.default)({
7912
+ url: `${this.baseUrl}/builds`,
7913
+ method: "GET",
7914
+ params,
7915
+ headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
7916
+ timeout: 6e4,
7917
+ validateStatus: () => true
7918
+ });
7919
+ if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7920
+ return res.data;
7921
+ }
7922
+ async publicJsonRequest(path8) {
7923
+ const res = await (0, import_axios3.default)({
7924
+ url: `${this.baseUrl}${path8}`,
7925
+ method: "GET",
7926
+ headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
7927
+ timeout: 6e4,
7928
+ validateStatus: () => true
7929
+ });
7930
+ if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7931
+ return res.data;
7932
+ }
7933
+ async authenticatedJsonRequest(path8, method, body) {
7934
+ if (!this.account) throw new Error("Private key required for authenticated requests");
7935
+ const headers = {
7936
+ "Content-Type": "application/json"
7937
+ };
7938
+ if (this.clientId) headers["x-client-id"] = this.clientId;
7939
+ const expiry = BigInt(Math.floor(Date.now() / 1e3) + 60);
7940
+ const { signature } = await calculateBillingAuthSignature({
7941
+ account: this.account,
7942
+ product: "compute",
7943
+ expiry
7944
+ });
7945
+ headers.Authorization = `Bearer ${signature}`;
7946
+ headers["X-eigenx-expiry"] = expiry.toString();
7947
+ headers["X-Account"] = this.account.address;
7948
+ const res = await (0, import_axios3.default)({
7949
+ url: `${this.baseUrl}${path8}`,
7950
+ method,
7951
+ headers,
7952
+ data: body,
7953
+ timeout: 6e4,
7954
+ validateStatus: () => true
7955
+ });
7956
+ if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7957
+ return res.data;
7958
+ }
7959
+ async authenticatedTextRequest(path8) {
7960
+ if (!this.account) throw new Error("Private key required for authenticated requests");
7961
+ const headers = {};
7962
+ if (this.clientId) headers["x-client-id"] = this.clientId;
7963
+ const expiry = BigInt(Math.floor(Date.now() / 1e3) + 60);
7964
+ const { signature } = await calculateBillingAuthSignature({
7965
+ account: this.account,
7966
+ product: "compute",
7967
+ expiry
7968
+ });
7969
+ headers.Authorization = `Bearer ${signature}`;
7970
+ headers["X-eigenx-expiry"] = expiry.toString();
7971
+ headers["X-Account"] = this.account.address;
7972
+ const res = await (0, import_axios3.default)({
7973
+ url: `${this.baseUrl}${path8}`,
7974
+ method: "GET",
7975
+ headers,
7976
+ timeout: 6e4,
7977
+ responseType: "text",
7978
+ validateStatus: () => true
7979
+ });
7980
+ if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7981
+ return typeof res.data === "string" ? res.data : JSON.stringify(res.data);
7982
+ }
7983
+ };
7984
+ function buildApiHttpError(res) {
7985
+ const status = res.status;
7986
+ const body = typeof res.data === "string" ? res.data : res.data ? JSON.stringify(res.data) : "";
7987
+ const url = res.config?.url ? ` ${res.config.url}` : "";
7988
+ return new Error(`BuildAPI request failed: ${status}${url} - ${body || "Unknown error"}`);
7989
+ }
7990
+
7991
+ // src/client/modules/build/types.ts
7992
+ var BUILD_STATUS = {
7993
+ BUILDING: "building",
7994
+ SUCCESS: "success",
7995
+ FAILED: "failed"
7996
+ };
7997
+
7998
+ // src/client/modules/build/errors.ts
7999
+ var BuildError = class extends Error {
8000
+ constructor(message) {
8001
+ super(message);
8002
+ this.name = "BuildError";
8003
+ }
8004
+ };
8005
+ var AuthRequiredError = class extends BuildError {
8006
+ constructor(message = "Authentication required") {
8007
+ super(message);
8008
+ this.name = "AuthRequiredError";
8009
+ }
8010
+ };
8011
+ var BuildFailedError = class extends BuildError {
8012
+ constructor(message, buildId) {
8013
+ super(message);
8014
+ this.buildId = buildId;
8015
+ this.name = "BuildFailedError";
8016
+ }
8017
+ };
8018
+ var ConflictError = class extends BuildError {
8019
+ constructor(message = "Build already in progress") {
8020
+ super(message);
8021
+ this.name = "ConflictError";
8022
+ }
8023
+ };
8024
+ var NotFoundError = class extends BuildError {
8025
+ constructor(message = "Build not found") {
8026
+ super(message);
8027
+ this.name = "NotFoundError";
8028
+ }
8029
+ };
8030
+ var ForbiddenError = class extends BuildError {
8031
+ constructor(message = "Permission denied") {
8032
+ super(message);
8033
+ this.name = "ForbiddenError";
8034
+ }
8035
+ };
8036
+ var TimeoutError = class extends BuildError {
8037
+ constructor(message = "Operation timed out") {
8038
+ super(message);
8039
+ this.name = "TimeoutError";
8040
+ }
8041
+ };
8042
+ var BadRequestError = class extends BuildError {
8043
+ constructor(message = "Bad request") {
8044
+ super(message);
8045
+ this.name = "BadRequestError";
8046
+ }
8047
+ };
8048
+
8049
+ // src/client/modules/build/index.ts
8050
+ var DEFAULT_POLL_INTERVAL = 2e3;
8051
+ var DEFAULT_TIMEOUT = 30 * 60 * 1e3;
8052
+ function createBuildModule(config) {
8053
+ const { verbose = false, skipTelemetry = false } = config;
8054
+ const logger = getLogger(verbose);
8055
+ const environment = config.environment || "sepolia";
8056
+ const environmentConfig = getEnvironmentConfig(environment);
8057
+ const api = new BuildApiClient({
8058
+ baseUrl: environmentConfig.userApiServerURL,
8059
+ privateKey: config.privateKey ? addHexPrefix(config.privateKey) : void 0,
8060
+ clientId: config.clientId
8061
+ });
8062
+ return {
8063
+ async submit(request) {
8064
+ return withSDKTelemetry(
8065
+ {
8066
+ functionName: "build.submit",
8067
+ skipTelemetry,
8068
+ properties: { environment, repoUrl: request.repoUrl }
8069
+ },
8070
+ async () => {
8071
+ if (!config.privateKey) throw new AuthRequiredError("Private key required for submit()");
8072
+ const data = await api.submitBuild({
8073
+ repo_url: request.repoUrl,
8074
+ git_ref: request.gitRef,
8075
+ dockerfile_path: request.dockerfilePath ?? "Dockerfile",
8076
+ caddyfile_path: request.caddyfilePath,
8077
+ build_context_path: request.buildContextPath ?? ".",
8078
+ dependencies: request.dependencies ?? []
8079
+ });
8080
+ logger.debug(`Submitted build: ${data.build_id}`);
8081
+ return { buildId: data.build_id };
8082
+ }
8083
+ );
8084
+ },
8085
+ async list(options) {
8086
+ const { billingAddress, limit, offset } = options;
8087
+ return withSDKTelemetry(
8088
+ {
8089
+ functionName: "build.list",
8090
+ skipTelemetry,
8091
+ properties: {
8092
+ environment,
8093
+ billingAddress,
8094
+ ...limit !== void 0 ? { limit: String(limit) } : {},
8095
+ ...offset !== void 0 ? { offset: String(offset) } : {}
8096
+ }
8097
+ },
8098
+ async () => {
8099
+ const data = await api.listBuilds({
8100
+ billing_address: billingAddress,
8101
+ limit,
8102
+ offset
8103
+ });
8104
+ return Array.isArray(data) ? data.map(transformBuild) : [];
8105
+ }
8106
+ );
8107
+ },
8108
+ async get(buildId) {
8109
+ return withSDKTelemetry(
8110
+ { functionName: "build.get", skipTelemetry, properties: { environment, buildId } },
8111
+ async () => transformBuild(await api.getBuild(buildId))
8112
+ );
8113
+ },
8114
+ async getByDigest(digest) {
8115
+ return withSDKTelemetry(
8116
+ { functionName: "build.getByDigest", skipTelemetry, properties: { environment, digest } },
8117
+ async () => transformBuild(await api.getBuildByDigest(digest))
8118
+ );
8119
+ },
8120
+ async verify(identifier) {
8121
+ return withSDKTelemetry(
8122
+ { functionName: "build.verify", skipTelemetry, properties: { environment, identifier } },
8123
+ async () => transformVerifyResult(await api.verify(identifier))
8124
+ );
8125
+ },
8126
+ async getLogs(buildId) {
8127
+ return withSDKTelemetry(
8128
+ { functionName: "build.getLogs", skipTelemetry, properties: { environment, buildId } },
8129
+ async () => {
8130
+ if (!config.privateKey) throw new AuthRequiredError("Private key required for getLogs()");
8131
+ return api.getLogs(buildId);
8132
+ }
8133
+ );
8134
+ },
8135
+ async submitAndWait(request, options = {}) {
8136
+ const { buildId } = await this.submit(request);
8137
+ return this.waitForBuild(buildId, options);
8138
+ },
8139
+ async waitForBuild(buildId, options = {}) {
8140
+ const {
8141
+ onLog,
8142
+ onProgress,
8143
+ pollIntervalMs = DEFAULT_POLL_INTERVAL,
8144
+ timeoutMs = DEFAULT_TIMEOUT
8145
+ } = options;
8146
+ const startTime = Date.now();
8147
+ let lastLogLength = 0;
8148
+ while (true) {
8149
+ if (Date.now() - startTime > timeoutMs) {
8150
+ throw new TimeoutError(`Build timed out after ${timeoutMs}ms`);
8151
+ }
8152
+ const build = await this.get(buildId);
8153
+ let logs2 = "";
8154
+ try {
8155
+ logs2 = await this.getLogs(buildId);
8156
+ if (onLog && logs2.length > lastLogLength) {
8157
+ onLog(logs2.slice(lastLogLength));
8158
+ lastLogLength = logs2.length;
8159
+ }
8160
+ } catch {
8161
+ }
8162
+ onProgress?.({ build, logs: logs2 });
8163
+ if (build.status === BUILD_STATUS.SUCCESS) return build;
8164
+ if (build.status === BUILD_STATUS.FAILED) {
8165
+ throw new BuildFailedError(build.errorMessage ?? "Build failed", buildId);
8166
+ }
8167
+ await sleep2(pollIntervalMs);
8168
+ }
8169
+ },
8170
+ async *streamLogs(buildId, pollIntervalMs = DEFAULT_POLL_INTERVAL) {
8171
+ let lastLength = 0;
8172
+ while (true) {
8173
+ const build = await this.get(buildId);
8174
+ let logs2 = "";
8175
+ try {
8176
+ logs2 = await this.getLogs(buildId);
8177
+ } catch {
8178
+ }
8179
+ if (logs2.length > lastLength) {
8180
+ yield {
8181
+ content: logs2.slice(lastLength),
8182
+ totalLength: logs2.length,
8183
+ isComplete: build.status !== BUILD_STATUS.BUILDING,
8184
+ finalStatus: build.status !== BUILD_STATUS.BUILDING ? build.status : void 0
8185
+ };
8186
+ lastLength = logs2.length;
8187
+ }
8188
+ if (build.status !== BUILD_STATUS.BUILDING) break;
8189
+ await sleep2(pollIntervalMs);
8190
+ }
8191
+ }
8192
+ };
8193
+ }
8194
+ function sleep2(ms) {
8195
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
8196
+ }
8197
+ function transformBuild(raw) {
8198
+ return {
8199
+ buildId: raw.build_id,
8200
+ billingAddress: raw.billing_address,
8201
+ repoUrl: raw.repo_url,
8202
+ gitRef: raw.git_ref,
8203
+ status: raw.status,
8204
+ buildType: raw.build_type,
8205
+ imageName: raw.image_name,
8206
+ imageUrl: raw.image_url,
8207
+ imageDigest: raw.image_digest,
8208
+ provenanceJson: raw.provenance_json ?? void 0,
8209
+ provenanceSignature: raw.provenance_signature ?? void 0,
8210
+ errorMessage: raw.error_message ?? void 0,
8211
+ createdAt: raw.created_at,
8212
+ updatedAt: raw.updated_at,
8213
+ dependencies: raw.dependencies ? Object.fromEntries(Object.entries(raw.dependencies).map(([k, v]) => [k, transformBuild(v)])) : void 0
8214
+ };
8215
+ }
8216
+ function transformVerifyResult(raw) {
8217
+ if (raw.status === "verified") {
8218
+ return {
8219
+ status: "verified",
8220
+ buildId: raw.build_id,
8221
+ imageUrl: raw.image_url,
8222
+ imageDigest: raw.image_digest,
8223
+ repoUrl: raw.repo_url,
8224
+ gitRef: raw.git_ref,
8225
+ provenanceJson: raw.provenance_json,
8226
+ provenanceSignature: raw.provenance_signature,
8227
+ payloadType: raw.payload_type,
8228
+ payload: raw.payload
8229
+ };
8230
+ }
8231
+ return {
8232
+ status: "failed",
8233
+ error: raw.error,
8234
+ buildId: raw.build_id
8235
+ };
8236
+ }
8237
+
7363
8238
  // src/client/common/utils/instance.ts
7364
8239
  async function getCurrentInstanceType(preflightCtx, appID, logger, clientId) {
7365
8240
  try {
@@ -7414,10 +8289,20 @@ function createECloudClient(cfg) {
7414
8289
  }
7415
8290
  // Annotate the CommonJS export names for ESM import in node:
7416
8291
  0 && (module.exports = {
8292
+ AuthRequiredError,
8293
+ BUILD_STATUS,
8294
+ BadRequestError,
8295
+ BuildError,
8296
+ BuildFailedError,
8297
+ ConflictError,
8298
+ ForbiddenError,
7417
8299
  NoopClient,
8300
+ NotFoundError,
7418
8301
  PRIMARY_LANGUAGES,
7419
8302
  PostHogClient,
8303
+ TimeoutError,
7420
8304
  UserApiClient,
8305
+ addHexPrefix,
7421
8306
  addMetric,
7422
8307
  addMetricWithDimensions,
7423
8308
  assertValidFilePath,
@@ -7427,6 +8312,7 @@ function createECloudClient(cfg) {
7427
8312
  createApp,
7428
8313
  createAppEnvironment,
7429
8314
  createBillingModule,
8315
+ createBuildModule,
7430
8316
  createComputeModule,
7431
8317
  createECloudClient,
7432
8318
  createMetricsContext,
@@ -7470,12 +8356,15 @@ function createECloudClient(cfg) {
7470
8356
  listStoredKeys,
7471
8357
  logs,
7472
8358
  prepareDeploy,
8359
+ prepareDeployFromVerifiableBuild,
7473
8360
  prepareUpgrade,
8361
+ prepareUpgradeFromVerifiableBuild,
7474
8362
  requirePrivateKey,
7475
8363
  sanitizeString,
7476
8364
  sanitizeURL,
7477
8365
  sanitizeXURL,
7478
8366
  storePrivateKey,
8367
+ stripHexPrefix,
7479
8368
  validateAppID,
7480
8369
  validateAppName,
7481
8370
  validateCreateAppParams,