@layr-labs/ecloud-sdk 0.2.0-dev.2 → 0.2.0-dev.3

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.
@@ -17,17 +17,10 @@ import {
17
17
  getLogger,
18
18
  stripHexPrefix,
19
19
  withSDKTelemetry
20
- } from "./chunk-ZEZS5CNB.js";
20
+ } from "./chunk-QN7KAUOB.js";
21
21
 
22
22
  // src/client/common/contract/eip7702.ts
23
- import {
24
- encodeFunctionData as encodeFunctionData2,
25
- encodeAbiParameters,
26
- decodeErrorResult as decodeErrorResult2,
27
- keccak256,
28
- toBytes,
29
- concat
30
- } from "viem";
23
+ import { encodeFunctionData as encodeFunctionData2, encodeAbiParameters, decodeErrorResult as decodeErrorResult2 } from "viem";
31
24
 
32
25
  // src/client/common/abis/ERC7702Delegator.json
33
26
  var ERC7702Delegator_default = [
@@ -2756,20 +2749,20 @@ async function prepareDeployBatch(options, logger) {
2756
2749
  environmentConfig
2757
2750
  };
2758
2751
  }
2759
- async function executeDeployBatch(prepared, gas, logger) {
2752
+ async function executeDeployBatch(data, context, gas, logger) {
2760
2753
  const pendingMessage = "Deploying new app...";
2761
2754
  const txHash = await executeBatch(
2762
2755
  {
2763
- walletClient: prepared.walletClient,
2764
- publicClient: prepared.publicClient,
2765
- environmentConfig: prepared.environmentConfig,
2766
- executions: prepared.executions,
2756
+ walletClient: context.walletClient,
2757
+ publicClient: context.publicClient,
2758
+ environmentConfig: context.environmentConfig,
2759
+ executions: data.executions,
2767
2760
  pendingMessage,
2768
2761
  gas
2769
2762
  },
2770
2763
  logger
2771
2764
  );
2772
- return { appId: prepared.appId, txHash };
2765
+ return { appId: data.appId, txHash };
2773
2766
  }
2774
2767
  async function deployApp(options, logger) {
2775
2768
  const prepared = await prepareDeployBatch(
@@ -2783,7 +2776,17 @@ async function deployApp(options, logger) {
2783
2776
  },
2784
2777
  logger
2785
2778
  );
2786
- return executeDeployBatch(prepared, options.gas, logger);
2779
+ const data = {
2780
+ appId: prepared.appId,
2781
+ salt: prepared.salt,
2782
+ executions: prepared.executions
2783
+ };
2784
+ const context = {
2785
+ walletClient: prepared.walletClient,
2786
+ publicClient: prepared.publicClient,
2787
+ environmentConfig: prepared.environmentConfig
2788
+ };
2789
+ return executeDeployBatch(data, context, options.gas, logger);
2787
2790
  }
2788
2791
  async function prepareUpgradeBatch(options) {
2789
2792
  const {
@@ -2879,14 +2882,14 @@ async function prepareUpgradeBatch(options) {
2879
2882
  environmentConfig
2880
2883
  };
2881
2884
  }
2882
- async function executeUpgradeBatch(prepared, gas, logger) {
2883
- const pendingMessage = `Upgrading app ${prepared.appId}...`;
2885
+ async function executeUpgradeBatch(data, context, gas, logger) {
2886
+ const pendingMessage = `Upgrading app ${data.appId}...`;
2884
2887
  const txHash = await executeBatch(
2885
2888
  {
2886
- walletClient: prepared.walletClient,
2887
- publicClient: prepared.publicClient,
2888
- environmentConfig: prepared.environmentConfig,
2889
- executions: prepared.executions,
2889
+ walletClient: context.walletClient,
2890
+ publicClient: context.publicClient,
2891
+ environmentConfig: context.environmentConfig,
2892
+ executions: data.executions,
2890
2893
  pendingMessage,
2891
2894
  gas
2892
2895
  },
@@ -2904,7 +2907,16 @@ async function upgradeApp(options, logger) {
2904
2907
  publicLogs: options.publicLogs,
2905
2908
  needsPermissionChange: options.needsPermissionChange
2906
2909
  });
2907
- return executeUpgradeBatch(prepared, options.gas, logger);
2910
+ const data = {
2911
+ appId: prepared.appId,
2912
+ executions: prepared.executions
2913
+ };
2914
+ const context = {
2915
+ walletClient: prepared.walletClient,
2916
+ publicClient: prepared.publicClient,
2917
+ environmentConfig: prepared.environmentConfig
2918
+ };
2919
+ return executeUpgradeBatch(data, context, options.gas, logger);
2908
2920
  }
2909
2921
  async function sendAndWaitForTransaction(options, logger) {
2910
2922
  const {
@@ -3195,27 +3207,55 @@ async function undelegate(options, logger) {
3195
3207
  }
3196
3208
 
3197
3209
  // src/client/common/contract/eip7702.ts
3210
+ var EXECUTE_BATCH_MODE = "0x0100000000000000000000000000000000000000000000000000000000000000";
3211
+ var GAS_LIMIT_BUFFER_PERCENTAGE = 20n;
3212
+ var GAS_PRICE_BUFFER_PERCENTAGE = 100n;
3213
+ function encodeExecuteBatchData(executions) {
3214
+ const encodedExecutions = encodeAbiParameters(
3215
+ [
3216
+ {
3217
+ type: "tuple[]",
3218
+ components: [
3219
+ { name: "target", type: "address" },
3220
+ { name: "value", type: "uint256" },
3221
+ { name: "callData", type: "bytes" }
3222
+ ]
3223
+ }
3224
+ ],
3225
+ [executions]
3226
+ );
3227
+ return encodeFunctionData2({
3228
+ abi: ERC7702Delegator_default,
3229
+ functionName: "execute",
3230
+ args: [EXECUTE_BATCH_MODE, encodedExecutions]
3231
+ });
3232
+ }
3198
3233
  async function estimateBatchGas(options) {
3199
- const { publicClient, executions } = options;
3200
- const fees = await publicClient.estimateFeesPerGas();
3201
- const baseGas = 100000n;
3202
- const perExecutionGas = 50000n;
3203
- const estimatedGas = baseGas + BigInt(executions.length) * perExecutionGas;
3204
- const gasLimit = estimatedGas * 120n / 100n;
3205
- const maxFeePerGas = fees.maxFeePerGas;
3206
- const maxPriorityFeePerGas = fees.maxPriorityFeePerGas;
3234
+ const { publicClient, account, executions } = options;
3235
+ const executeBatchData = encodeExecuteBatchData(executions);
3236
+ const [gasTipCap, block, estimatedGas] = await Promise.all([
3237
+ publicClient.estimateMaxPriorityFeePerGas(),
3238
+ publicClient.getBlock(),
3239
+ publicClient.estimateGas({
3240
+ account,
3241
+ to: account,
3242
+ data: executeBatchData
3243
+ })
3244
+ ]);
3245
+ const baseFee = block.baseFeePerGas ?? 0n;
3246
+ const maxFeePerGas = (baseFee + gasTipCap) * (100n + GAS_PRICE_BUFFER_PERCENTAGE) / 100n;
3247
+ const gasLimit = estimatedGas * (100n + GAS_LIMIT_BUFFER_PERCENTAGE) / 100n;
3207
3248
  const maxCostWei = gasLimit * maxFeePerGas;
3208
- const maxCostEth = formatETH(maxCostWei);
3209
3249
  return {
3210
3250
  gasLimit,
3211
3251
  maxFeePerGas,
3212
- maxPriorityFeePerGas,
3252
+ maxPriorityFeePerGas: gasTipCap,
3213
3253
  maxCostWei,
3214
- maxCostEth
3254
+ maxCostEth: formatETH(maxCostWei)
3215
3255
  };
3216
3256
  }
3217
3257
  async function checkERC7702Delegation(publicClient, account, delegatorAddress) {
3218
- const code = await publicClient.getBytecode({ address: account });
3258
+ const code = await publicClient.getCode({ address: account });
3219
3259
  if (!code) {
3220
3260
  return false;
3221
3261
  }
@@ -3232,36 +3272,7 @@ async function executeBatch(options, logger) {
3232
3272
  if (!chain) {
3233
3273
  throw new Error("Wallet client must have a chain");
3234
3274
  }
3235
- const encodedExecutions = encodeAbiParameters(
3236
- [
3237
- {
3238
- type: "tuple[]",
3239
- components: [
3240
- { name: "target", type: "address" },
3241
- { name: "value", type: "uint256" },
3242
- { name: "callData", type: "bytes" }
3243
- ]
3244
- }
3245
- ],
3246
- [executions]
3247
- );
3248
- const executeBatchMode = "0x0100000000000000000000000000000000000000000000000000000000000000";
3249
- let executeBatchData;
3250
- try {
3251
- executeBatchData = encodeFunctionData2({
3252
- abi: ERC7702Delegator_default,
3253
- functionName: "execute",
3254
- args: [executeBatchMode, encodedExecutions]
3255
- });
3256
- } catch {
3257
- const functionSignature = "execute(bytes32,bytes)";
3258
- const selector = keccak256(toBytes(functionSignature)).slice(0, 10);
3259
- const encodedParams = encodeAbiParameters(
3260
- [{ type: "bytes32" }, { type: "bytes" }],
3261
- [executeBatchMode, encodedExecutions]
3262
- );
3263
- executeBatchData = concat([selector, encodedParams]);
3264
- }
3275
+ const executeBatchData = encodeExecuteBatchData(executions);
3265
3276
  const isDelegated2 = await checkERC7702Delegation(
3266
3277
  publicClient,
3267
3278
  account.address,
@@ -3643,6 +3654,7 @@ async function buildDockerImage(buildContext, dockerfilePath, tag, logger) {
3643
3654
  tag,
3644
3655
  "-f",
3645
3656
  dockerfilePath,
3657
+ "--load",
3646
3658
  "--progress=plain",
3647
3659
  buildContext
3648
3660
  ];
@@ -3766,9 +3778,9 @@ async function pullDockerImage(docker, imageTag, platform = "linux/amd64", logge
3766
3778
 
3767
3779
  // src/client/common/docker/push.ts
3768
3780
  import * as child_process2 from "child_process";
3769
- import { exec as exec3 } from "child_process";
3781
+ import { execFile } from "child_process";
3770
3782
  import { promisify as promisify2 } from "util";
3771
- var execAsync = promisify2(exec3);
3783
+ var execFileAsync = promisify2(execFile);
3772
3784
  async function pushDockerImage(docker, imageRef, logger) {
3773
3785
  logger?.info?.(`Pushing image ${imageRef}...`);
3774
3786
  return new Promise((resolve2, reject) => {
@@ -3809,9 +3821,9 @@ async function pushDockerImage(docker, imageRef, logger) {
3809
3821
  if (!output.includes("digest:") && !output.includes("pushed") && !output.includes("Pushed")) {
3810
3822
  logger?.debug?.("No clear success indicator in push output, verifying...");
3811
3823
  }
3812
- logger?.info?.("Image push completed successfully");
3813
3824
  try {
3814
3825
  await verifyImageExists(imageRef, logger);
3826
+ logger?.info?.("Image push completed successfully");
3815
3827
  resolve2();
3816
3828
  } catch (error) {
3817
3829
  reject(error);
@@ -3835,7 +3847,7 @@ async function verifyImageExists(imageRef, logger) {
3835
3847
  let retries = 5;
3836
3848
  while (retries > 0) {
3837
3849
  try {
3838
- await execAsync(`docker manifest inspect ${imageRef}`, {
3850
+ await execFileAsync("docker", ["manifest", "inspect", imageRef], {
3839
3851
  maxBuffer: 10 * 1024 * 1024,
3840
3852
  timeout: 1e4
3841
3853
  // 10 second timeout
@@ -4293,10 +4305,10 @@ async function setupLayeredBuildDirectory(environmentConfig, layeredDockerfileCo
4293
4305
  // src/client/common/registry/digest.ts
4294
4306
  import * as child_process3 from "child_process";
4295
4307
  import { promisify as promisify3 } from "util";
4296
- var execFileAsync = promisify3(child_process3.execFile);
4308
+ var execFileAsync2 = promisify3(child_process3.execFile);
4297
4309
  async function getImageDigestAndName(imageRef) {
4298
4310
  try {
4299
- const { stdout } = await execFileAsync(
4311
+ const { stdout } = await execFileAsync2(
4300
4312
  "docker",
4301
4313
  ["manifest", "inspect", imageRef],
4302
4314
  { maxBuffer: 10 * 1024 * 1024 }
@@ -4336,7 +4348,7 @@ function extractDigestFromMultiPlatform(manifest, imageRef) {
4336
4348
  }
4337
4349
  async function extractDigestFromSinglePlatform(manifest, imageRef) {
4338
4350
  try {
4339
- const { stdout } = await execFileAsync("docker", ["inspect", imageRef], {
4351
+ const { stdout } = await execFileAsync2("docker", ["inspect", imageRef], {
4340
4352
  maxBuffer: 10 * 1024 * 1024
4341
4353
  });
4342
4354
  const inspectData = JSON.parse(stdout);
@@ -4634,6 +4646,67 @@ Please verify the image exists: docker manifest inspect ${finalImageRef}`
4634
4646
  };
4635
4647
  }
4636
4648
 
4649
+ // src/client/common/release/prebuilt.ts
4650
+ async function createReleaseFromImageDigest(options, logger) {
4651
+ const { imageRef, imageDigest, envFilePath, instanceType, environmentConfig, appId } = options;
4652
+ if (!/^sha256:[0-9a-f]{64}$/i.test(imageDigest)) {
4653
+ throw new Error(`imageDigest must be in format sha256:<64 hex>, got: ${imageDigest}`);
4654
+ }
4655
+ let publicEnv = {};
4656
+ let privateEnv = {};
4657
+ if (envFilePath) {
4658
+ logger.info("Parsing environment file...");
4659
+ const parsed = parseAndValidateEnvFile(envFilePath);
4660
+ publicEnv = parsed.public;
4661
+ privateEnv = parsed.private;
4662
+ } else {
4663
+ logger.info("Continuing without environment file");
4664
+ }
4665
+ publicEnv["EIGEN_MACHINE_TYPE_PUBLIC"] = instanceType;
4666
+ logger.info(`Instance type: ${instanceType}`);
4667
+ logger.info("Encrypting environment variables...");
4668
+ const { encryptionKey } = getKMSKeysForEnvironment(
4669
+ environmentConfig.name,
4670
+ environmentConfig.build
4671
+ );
4672
+ const protectedHeaders = getAppProtectedHeaders(appId);
4673
+ const privateEnvBytes = Buffer.from(JSON.stringify(privateEnv));
4674
+ const encryptedEnvStr = await encryptRSAOAEPAndAES256GCM(
4675
+ encryptionKey,
4676
+ privateEnvBytes,
4677
+ protectedHeaders
4678
+ );
4679
+ const digestHex = imageDigest.split(":")[1];
4680
+ const digestBytes = new Uint8Array(Buffer.from(digestHex, "hex"));
4681
+ if (digestBytes.length !== 32) {
4682
+ throw new Error(`Digest must be exactly 32 bytes, got ${digestBytes.length}`);
4683
+ }
4684
+ const registry = extractRegistryNameNoDocker(imageRef);
4685
+ return {
4686
+ rmsRelease: {
4687
+ artifacts: [{ digest: digestBytes, registry }],
4688
+ upgradeByTime: Math.floor(Date.now() / 1e3) + 3600
4689
+ },
4690
+ publicEnv: new Uint8Array(Buffer.from(JSON.stringify(publicEnv))),
4691
+ encryptedEnv: new Uint8Array(Buffer.from(encryptedEnvStr))
4692
+ };
4693
+ }
4694
+ function extractRegistryNameNoDocker(imageRef) {
4695
+ let name = imageRef;
4696
+ const tagIndex = name.lastIndexOf(":");
4697
+ if (tagIndex !== -1 && !name.substring(tagIndex + 1).includes("/")) {
4698
+ name = name.substring(0, tagIndex);
4699
+ }
4700
+ const digestIndex = name.indexOf("@");
4701
+ if (digestIndex !== -1) {
4702
+ name = name.substring(0, digestIndex);
4703
+ }
4704
+ if ([...name].filter((c) => c === "/").length === 1) {
4705
+ name = `docker.io/${name}`;
4706
+ }
4707
+ return name;
4708
+ }
4709
+
4637
4710
  // src/client/common/contract/watcher.ts
4638
4711
  var WATCH_POLL_INTERVAL_SECONDS = 5;
4639
4712
  var APP_STATUS_RUNNING = "Running";
@@ -4815,6 +4888,97 @@ function validatePrivateKey(key) {
4815
4888
  }
4816
4889
 
4817
4890
  // src/client/modules/compute/app/deploy.ts
4891
+ async function prepareDeployFromVerifiableBuild(options, logger = defaultLogger) {
4892
+ return withSDKTelemetry(
4893
+ {
4894
+ functionName: "prepareDeployFromVerifiableBuild",
4895
+ skipTelemetry: options.skipTelemetry,
4896
+ properties: {
4897
+ environment: options.environment || "sepolia"
4898
+ }
4899
+ },
4900
+ async () => {
4901
+ if (!options.privateKey) throw new Error("privateKey is required for deployment");
4902
+ if (!options.imageRef) throw new Error("imageRef is required for deployment");
4903
+ if (!options.imageDigest) throw new Error("imageDigest is required for deployment");
4904
+ assertValidImageReference(options.imageRef);
4905
+ validateAppName(options.appName);
4906
+ validateLogVisibility(options.logVisibility);
4907
+ if (!/^sha256:[0-9a-f]{64}$/i.test(options.imageDigest)) {
4908
+ throw new Error(
4909
+ `imageDigest must be in format sha256:<64 hex>, got: ${options.imageDigest}`
4910
+ );
4911
+ }
4912
+ const { publicLogs } = validateLogVisibility(options.logVisibility);
4913
+ validateResourceUsageMonitoring(options.resourceUsageMonitoring);
4914
+ logger.debug("Performing preflight checks...");
4915
+ const preflightCtx = await doPreflightChecks(
4916
+ {
4917
+ privateKey: options.privateKey,
4918
+ rpcUrl: options.rpcUrl,
4919
+ environment: options.environment
4920
+ },
4921
+ logger
4922
+ );
4923
+ logger.debug("Checking quota availability...");
4924
+ await checkQuotaAvailable(preflightCtx);
4925
+ const salt = generateRandomSalt();
4926
+ logger.debug(`Generated salt: ${Buffer.from(salt).toString("hex")}`);
4927
+ logger.debug("Calculating app ID...");
4928
+ const appIDToBeDeployed = await calculateAppID(
4929
+ preflightCtx.privateKey,
4930
+ options.rpcUrl || preflightCtx.rpcUrl,
4931
+ preflightCtx.environmentConfig,
4932
+ salt
4933
+ );
4934
+ logger.info(``);
4935
+ logger.info(`App ID: ${appIDToBeDeployed}`);
4936
+ logger.info(``);
4937
+ const release = await createReleaseFromImageDigest(
4938
+ {
4939
+ imageRef: options.imageRef,
4940
+ imageDigest: options.imageDigest,
4941
+ envFilePath: options.envFilePath,
4942
+ instanceType: options.instanceType,
4943
+ environmentConfig: preflightCtx.environmentConfig,
4944
+ appId: appIDToBeDeployed
4945
+ },
4946
+ logger
4947
+ );
4948
+ logger.debug("Preparing deploy batch...");
4949
+ const batch = await prepareDeployBatch(
4950
+ {
4951
+ privateKey: preflightCtx.privateKey,
4952
+ rpcUrl: options.rpcUrl || preflightCtx.rpcUrl,
4953
+ environmentConfig: preflightCtx.environmentConfig,
4954
+ salt,
4955
+ release,
4956
+ publicLogs
4957
+ },
4958
+ logger
4959
+ );
4960
+ logger.debug("Estimating gas...");
4961
+ const gasEstimate = await estimateBatchGas({
4962
+ publicClient: batch.publicClient,
4963
+ account: batch.walletClient.account.address,
4964
+ executions: batch.executions
4965
+ });
4966
+ const data = {
4967
+ appId: batch.appId,
4968
+ salt: batch.salt,
4969
+ executions: batch.executions
4970
+ };
4971
+ return {
4972
+ prepared: {
4973
+ data,
4974
+ appName: options.appName,
4975
+ imageRef: options.imageRef
4976
+ },
4977
+ gasEstimate
4978
+ };
4979
+ }
4980
+ );
4981
+ }
4818
4982
  function validateDeployOptions(options) {
4819
4983
  if (!options.privateKey) {
4820
4984
  throw new Error("privateKey is required for deployment");
@@ -5035,26 +5199,27 @@ async function prepareDeploy(options, logger = defaultLogger) {
5035
5199
  logger.debug("Estimating gas...");
5036
5200
  const gasEstimate = await estimateBatchGas({
5037
5201
  publicClient: batch.publicClient,
5038
- environmentConfig: batch.environmentConfig,
5202
+ account: batch.walletClient.account.address,
5039
5203
  executions: batch.executions
5040
5204
  });
5205
+ const data = {
5206
+ appId: batch.appId,
5207
+ salt: batch.salt,
5208
+ executions: batch.executions
5209
+ };
5041
5210
  return {
5042
5211
  prepared: {
5043
- batch,
5212
+ data,
5044
5213
  appName,
5045
- imageRef: finalImageRef,
5046
- preflightCtx: {
5047
- privateKey: preflightCtx.privateKey,
5048
- rpcUrl: preflightCtx.rpcUrl,
5049
- environmentConfig: preflightCtx.environmentConfig
5050
- }
5214
+ imageRef: finalImageRef
5051
5215
  },
5052
5216
  gasEstimate
5053
5217
  };
5054
5218
  }
5055
5219
  );
5056
5220
  }
5057
- async function executeDeploy(prepared, gas, logger = defaultLogger, skipTelemetry) {
5221
+ async function executeDeploy(options) {
5222
+ const { prepared, context, gas, logger = defaultLogger, skipTelemetry } = options;
5058
5223
  return withSDKTelemetry(
5059
5224
  {
5060
5225
  functionName: "executeDeploy",
@@ -5062,7 +5227,7 @@ async function executeDeploy(prepared, gas, logger = defaultLogger, skipTelemetr
5062
5227
  },
5063
5228
  async () => {
5064
5229
  logger.info("Deploying on-chain...");
5065
- const { appId, txHash } = await executeDeployBatch(prepared.batch, gas, logger);
5230
+ const { appId, txHash } = await executeDeployBatch(prepared.data, context, gas, logger);
5066
5231
  return {
5067
5232
  appId,
5068
5233
  txHash,
@@ -5124,6 +5289,81 @@ async function checkAppLogPermission(preflightCtx, appAddress, logger) {
5124
5289
  }
5125
5290
 
5126
5291
  // src/client/modules/compute/app/upgrade.ts
5292
+ async function prepareUpgradeFromVerifiableBuild(options, logger = defaultLogger) {
5293
+ return withSDKTelemetry(
5294
+ {
5295
+ functionName: "prepareUpgradeFromVerifiableBuild",
5296
+ skipTelemetry: options.skipTelemetry,
5297
+ properties: {
5298
+ environment: options.environment || "sepolia"
5299
+ }
5300
+ },
5301
+ async () => {
5302
+ logger.debug("Performing preflight checks...");
5303
+ const preflightCtx = await doPreflightChecks(
5304
+ {
5305
+ privateKey: options.privateKey,
5306
+ rpcUrl: options.rpcUrl,
5307
+ environment: options.environment
5308
+ },
5309
+ logger
5310
+ );
5311
+ const appID = validateUpgradeOptions(options);
5312
+ assertValidImageReference(options.imageRef);
5313
+ if (!/^sha256:[0-9a-f]{64}$/i.test(options.imageDigest)) {
5314
+ throw new Error(
5315
+ `imageDigest must be in format sha256:<64 hex>, got: ${options.imageDigest}`
5316
+ );
5317
+ }
5318
+ const { publicLogs } = validateLogVisibility(options.logVisibility);
5319
+ validateResourceUsageMonitoring(options.resourceUsageMonitoring);
5320
+ const envFilePath = options.envFilePath || "";
5321
+ logger.info("Preparing release (verifiable build, no local layering)...");
5322
+ const release = await createReleaseFromImageDigest(
5323
+ {
5324
+ imageRef: options.imageRef,
5325
+ imageDigest: options.imageDigest,
5326
+ envFilePath,
5327
+ instanceType: options.instanceType,
5328
+ environmentConfig: preflightCtx.environmentConfig,
5329
+ appId: appID
5330
+ },
5331
+ logger
5332
+ );
5333
+ logger.debug("Checking current log permission state...");
5334
+ const currentlyPublic = await checkAppLogPermission(preflightCtx, appID, logger);
5335
+ const needsPermissionChange = currentlyPublic !== publicLogs;
5336
+ logger.debug("Preparing upgrade batch...");
5337
+ const batch = await prepareUpgradeBatch({
5338
+ privateKey: preflightCtx.privateKey,
5339
+ rpcUrl: options.rpcUrl || preflightCtx.rpcUrl,
5340
+ environmentConfig: preflightCtx.environmentConfig,
5341
+ appId: appID,
5342
+ release,
5343
+ publicLogs,
5344
+ needsPermissionChange
5345
+ });
5346
+ logger.debug("Estimating gas...");
5347
+ const gasEstimate = await estimateBatchGas({
5348
+ publicClient: batch.publicClient,
5349
+ account: batch.walletClient.account.address,
5350
+ executions: batch.executions
5351
+ });
5352
+ const data = {
5353
+ appId: batch.appId,
5354
+ executions: batch.executions
5355
+ };
5356
+ return {
5357
+ prepared: {
5358
+ data,
5359
+ appId: appID,
5360
+ imageRef: options.imageRef
5361
+ },
5362
+ gasEstimate
5363
+ };
5364
+ }
5365
+ );
5366
+ }
5127
5367
  function validateUpgradeOptions(options) {
5128
5368
  if (!options.privateKey) {
5129
5369
  throw new Error("privateKey is required for upgrade");
@@ -5286,26 +5526,26 @@ async function prepareUpgrade(options, logger = defaultLogger) {
5286
5526
  logger.debug("Estimating gas...");
5287
5527
  const gasEstimate = await estimateBatchGas({
5288
5528
  publicClient: batch.publicClient,
5289
- environmentConfig: batch.environmentConfig,
5529
+ account: batch.walletClient.account.address,
5290
5530
  executions: batch.executions
5291
5531
  });
5532
+ const data = {
5533
+ appId: batch.appId,
5534
+ executions: batch.executions
5535
+ };
5292
5536
  return {
5293
5537
  prepared: {
5294
- batch,
5538
+ data,
5295
5539
  appId: appID,
5296
- imageRef: finalImageRef,
5297
- preflightCtx: {
5298
- privateKey: preflightCtx.privateKey,
5299
- rpcUrl: preflightCtx.rpcUrl,
5300
- environmentConfig: preflightCtx.environmentConfig
5301
- }
5540
+ imageRef: finalImageRef
5302
5541
  },
5303
5542
  gasEstimate
5304
5543
  };
5305
5544
  }
5306
5545
  );
5307
5546
  }
5308
- async function executeUpgrade(prepared, gas, logger = defaultLogger, skipTelemetry) {
5547
+ async function executeUpgrade(options) {
5548
+ const { prepared, context, gas, logger = defaultLogger, skipTelemetry } = options;
5309
5549
  return withSDKTelemetry(
5310
5550
  {
5311
5551
  functionName: "executeUpgrade",
@@ -5313,7 +5553,7 @@ async function executeUpgrade(prepared, gas, logger = defaultLogger, skipTelemet
5313
5553
  },
5314
5554
  async () => {
5315
5555
  logger.info("Upgrading on-chain...");
5316
- const txHash = await executeUpgradeBatch(prepared.batch, gas, logger);
5556
+ const txHash = await executeUpgradeBatch(prepared.data, context, gas, logger);
5317
5557
  return {
5318
5558
  appId: prepared.appId,
5319
5559
  imageRef: prepared.imageRef,
@@ -5442,10 +5682,10 @@ import * as path6 from "path";
5442
5682
  import * as fs5 from "fs";
5443
5683
  import * as path4 from "path";
5444
5684
  import * as os2 from "os";
5445
- import { exec as exec4, execFile as execFile2 } from "child_process";
5685
+ import { exec as exec3, execFile as execFile3 } from "child_process";
5446
5686
  import { promisify as promisify4 } from "util";
5447
- var execAsync2 = promisify4(exec4);
5448
- var execFileAsync2 = promisify4(execFile2);
5687
+ var execAsync = promisify4(exec3);
5688
+ var execFileAsync3 = promisify4(execFile3);
5449
5689
  async function fetchTemplate(repoURL, ref, targetDir, config, logger) {
5450
5690
  if (!repoURL) {
5451
5691
  throw new Error("repoURL is required");
@@ -5454,13 +5694,13 @@ async function fetchTemplate(repoURL, ref, targetDir, config, logger) {
5454
5694
  Cloning repo: ${repoURL} \u2192 ${targetDir}
5455
5695
  `);
5456
5696
  try {
5457
- await execAsync2(`git clone --no-checkout --progress ${repoURL} ${targetDir}`, {
5697
+ await execAsync(`git clone --no-checkout --progress ${repoURL} ${targetDir}`, {
5458
5698
  maxBuffer: 10 * 1024 * 1024
5459
5699
  });
5460
- await execFileAsync2("git", ["-C", targetDir, "checkout", "--quiet", ref], {
5700
+ await execFileAsync3("git", ["-C", targetDir, "checkout", "--quiet", ref], {
5461
5701
  maxBuffer: 10 * 1024 * 1024
5462
5702
  });
5463
- await execFileAsync2(
5703
+ await execFileAsync3(
5464
5704
  "git",
5465
5705
  ["-C", targetDir, "submodule", "update", "--init", "--recursive", "--progress"],
5466
5706
  { maxBuffer: 10 * 1024 * 1024 }
@@ -5505,14 +5745,14 @@ Cloning template: ${repoURL} \u2192 extracting ${subPath}
5505
5745
  }
5506
5746
  async function cloneSparse(repoURL, ref, subPath, tempDir) {
5507
5747
  try {
5508
- await execFileAsync2("git", ["init", tempDir]);
5509
- await execFileAsync2("git", ["-C", tempDir, "remote", "add", "origin", repoURL]);
5510
- await execFileAsync2("git", ["-C", tempDir, "config", "core.sparseCheckout", "true"]);
5748
+ await execFileAsync3("git", ["init", tempDir]);
5749
+ await execFileAsync3("git", ["-C", tempDir, "remote", "add", "origin", repoURL]);
5750
+ await execFileAsync3("git", ["-C", tempDir, "config", "core.sparseCheckout", "true"]);
5511
5751
  const sparseCheckoutPath = path4.join(tempDir, ".git/info/sparse-checkout");
5512
5752
  fs5.writeFileSync(sparseCheckoutPath, `${subPath}
5513
5753
  `);
5514
- await execFileAsync2("git", ["-C", tempDir, "fetch", "origin", ref]);
5515
- await execFileAsync2("git", ["-C", tempDir, "checkout", ref]);
5754
+ await execFileAsync3("git", ["-C", tempDir, "fetch", "origin", ref]);
5755
+ await execFileAsync3("git", ["-C", tempDir, "checkout", ref]);
5516
5756
  } catch (error) {
5517
5757
  throw new Error(`Failed to clone sparse repository: ${error.message}`);
5518
5758
  }
@@ -6005,7 +6245,14 @@ async function logs(options, logger = defaultLogger, skipTelemetry = false) {
6005
6245
  }
6006
6246
 
6007
6247
  // src/client/modules/compute/app/index.ts
6008
- import { parseAbi, encodeFunctionData as encodeFunctionData3 } from "viem";
6248
+ import {
6249
+ parseAbi,
6250
+ encodeFunctionData as encodeFunctionData3,
6251
+ createWalletClient as createWalletClient2,
6252
+ createPublicClient as createPublicClient4,
6253
+ http as http4
6254
+ } from "viem";
6255
+ import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
6009
6256
  var CONTROLLER_ABI = parseAbi([
6010
6257
  "function startApp(address appId)",
6011
6258
  "function stopApp(address appId)",
@@ -6088,6 +6335,187 @@ function createAppModule(ctx) {
6088
6335
  imageRef: result.imageRef
6089
6336
  };
6090
6337
  },
6338
+ // Granular deploy control
6339
+ async prepareDeploy(opts) {
6340
+ return prepareDeploy(
6341
+ {
6342
+ privateKey,
6343
+ rpcUrl: ctx.rpcUrl,
6344
+ environment: ctx.environment,
6345
+ appName: opts.name,
6346
+ instanceType: opts.instanceType,
6347
+ dockerfilePath: opts.dockerfile,
6348
+ envFilePath: opts.envFile,
6349
+ imageRef: opts.imageRef,
6350
+ logVisibility: opts.logVisibility,
6351
+ resourceUsageMonitoring: opts.resourceUsageMonitoring,
6352
+ skipTelemetry
6353
+ },
6354
+ logger
6355
+ );
6356
+ },
6357
+ async prepareDeployFromVerifiableBuild(opts) {
6358
+ return prepareDeployFromVerifiableBuild(
6359
+ {
6360
+ privateKey,
6361
+ rpcUrl: ctx.rpcUrl,
6362
+ environment: ctx.environment,
6363
+ appName: opts.name,
6364
+ instanceType: opts.instanceType,
6365
+ envFilePath: opts.envFile,
6366
+ imageRef: opts.imageRef,
6367
+ imageDigest: opts.imageDigest,
6368
+ logVisibility: opts.logVisibility,
6369
+ resourceUsageMonitoring: opts.resourceUsageMonitoring,
6370
+ skipTelemetry
6371
+ },
6372
+ logger
6373
+ );
6374
+ },
6375
+ async executeDeploy(prepared, gas) {
6376
+ const account = privateKeyToAccount3(privateKey);
6377
+ const chain = getChainFromID(environment.chainID);
6378
+ const publicClient = createPublicClient4({
6379
+ chain,
6380
+ transport: http4(ctx.rpcUrl)
6381
+ });
6382
+ const walletClient = createWalletClient2({
6383
+ account,
6384
+ chain,
6385
+ transport: http4(ctx.rpcUrl)
6386
+ });
6387
+ const result = await executeDeploy({
6388
+ prepared,
6389
+ context: {
6390
+ walletClient,
6391
+ publicClient,
6392
+ environmentConfig: environment
6393
+ },
6394
+ gas,
6395
+ logger,
6396
+ skipTelemetry
6397
+ });
6398
+ return {
6399
+ appId: result.appId,
6400
+ txHash: result.txHash,
6401
+ appName: result.appName,
6402
+ imageRef: result.imageRef
6403
+ };
6404
+ },
6405
+ async watchDeployment(appId) {
6406
+ return watchDeployment(
6407
+ appId,
6408
+ privateKey,
6409
+ ctx.rpcUrl,
6410
+ ctx.environment,
6411
+ logger,
6412
+ ctx.clientId,
6413
+ skipTelemetry
6414
+ );
6415
+ },
6416
+ // Granular upgrade control
6417
+ async prepareUpgrade(appId, opts) {
6418
+ return prepareUpgrade(
6419
+ {
6420
+ appId,
6421
+ privateKey,
6422
+ rpcUrl: ctx.rpcUrl,
6423
+ environment: ctx.environment,
6424
+ instanceType: opts.instanceType,
6425
+ dockerfilePath: opts.dockerfile,
6426
+ envFilePath: opts.envFile,
6427
+ imageRef: opts.imageRef,
6428
+ logVisibility: opts.logVisibility,
6429
+ resourceUsageMonitoring: opts.resourceUsageMonitoring,
6430
+ skipTelemetry
6431
+ },
6432
+ logger
6433
+ );
6434
+ },
6435
+ async prepareUpgradeFromVerifiableBuild(appId, opts) {
6436
+ return prepareUpgradeFromVerifiableBuild(
6437
+ {
6438
+ appId,
6439
+ privateKey,
6440
+ rpcUrl: ctx.rpcUrl,
6441
+ environment: ctx.environment,
6442
+ instanceType: opts.instanceType,
6443
+ envFilePath: opts.envFile,
6444
+ imageRef: opts.imageRef,
6445
+ imageDigest: opts.imageDigest,
6446
+ logVisibility: opts.logVisibility,
6447
+ resourceUsageMonitoring: opts.resourceUsageMonitoring,
6448
+ skipTelemetry
6449
+ },
6450
+ logger
6451
+ );
6452
+ },
6453
+ async executeUpgrade(prepared, gas) {
6454
+ const account = privateKeyToAccount3(privateKey);
6455
+ const chain = getChainFromID(environment.chainID);
6456
+ const publicClient = createPublicClient4({
6457
+ chain,
6458
+ transport: http4(ctx.rpcUrl)
6459
+ });
6460
+ const walletClient = createWalletClient2({
6461
+ account,
6462
+ chain,
6463
+ transport: http4(ctx.rpcUrl)
6464
+ });
6465
+ const result = await executeUpgrade({
6466
+ prepared,
6467
+ context: {
6468
+ walletClient,
6469
+ publicClient,
6470
+ environmentConfig: environment
6471
+ },
6472
+ gas,
6473
+ logger,
6474
+ skipTelemetry
6475
+ });
6476
+ return {
6477
+ appId: result.appId,
6478
+ txHash: result.txHash,
6479
+ imageRef: result.imageRef
6480
+ };
6481
+ },
6482
+ async watchUpgrade(appId) {
6483
+ return watchUpgrade(
6484
+ appId,
6485
+ privateKey,
6486
+ ctx.rpcUrl,
6487
+ ctx.environment,
6488
+ logger,
6489
+ ctx.clientId,
6490
+ skipTelemetry
6491
+ );
6492
+ },
6493
+ // Profile management
6494
+ async setProfile(appId, profile) {
6495
+ return withSDKTelemetry(
6496
+ {
6497
+ functionName: "setProfile",
6498
+ skipTelemetry,
6499
+ properties: { environment: ctx.environment }
6500
+ },
6501
+ async () => {
6502
+ const userApiClient = new UserApiClient(
6503
+ environment,
6504
+ privateKey,
6505
+ ctx.rpcUrl,
6506
+ ctx.clientId
6507
+ );
6508
+ return userApiClient.uploadAppProfile(
6509
+ appId,
6510
+ profile.name,
6511
+ profile.website,
6512
+ profile.description,
6513
+ profile.xURL,
6514
+ profile.imagePath
6515
+ );
6516
+ }
6517
+ );
6518
+ },
6091
6519
  async logs(opts) {
6092
6520
  return logs(
6093
6521
  {
@@ -6267,9 +6695,11 @@ export {
6267
6695
  validateUpgradeParams,
6268
6696
  validateCreateAppParams,
6269
6697
  validateLogsParams,
6698
+ prepareDeployFromVerifiableBuild,
6270
6699
  prepareDeploy,
6271
6700
  executeDeploy,
6272
6701
  watchDeployment,
6702
+ prepareUpgradeFromVerifiableBuild,
6273
6703
  prepareUpgrade,
6274
6704
  executeUpgrade,
6275
6705
  watchUpgrade,
@@ -6286,4 +6716,4 @@ export {
6286
6716
  createAppModule,
6287
6717
  createComputeModule
6288
6718
  };
6289
- //# sourceMappingURL=chunk-4SKRNFKQ.js.map
6719
+ //# sourceMappingURL=chunk-R44OVMCY.js.map