@layr-labs/ecloud-sdk 0.1.2 → 0.2.0-dev.1
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-AOZRDBLK.js → chunk-FY7UU55U.js} +107 -31
- package/dist/chunk-FY7UU55U.js.map +1 -0
- package/dist/{chunk-4RG5IMZ7.js → chunk-GB4GM4C2.js} +2 -2
- package/dist/{chunk-MQ2NGP4C.js → chunk-O7EU5JL7.js} +312 -55
- package/dist/chunk-O7EU5JL7.js.map +1 -0
- package/dist/{compute-BlUpqWKo.d.cts → compute-CF2HOXed.d.ts} +9 -1
- package/dist/{compute-CottWiST.d.ts → compute-CbmjA8kJ.d.cts} +9 -1
- package/dist/compute.cjs +387 -47
- 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-Fb_S-Cqk.d.ts → index-D2QufVB9.d.cts} +33 -1
- package/dist/{index-Fb_S-Cqk.d.cts → index-D2QufVB9.d.ts} +33 -1
- package/dist/index.cjs +769 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +314 -98
- package/dist/index.d.ts +314 -98
- package/dist/index.js +376 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-AOZRDBLK.js.map +0 -1
- package/dist/chunk-MQ2NGP4C.js.map +0 -1
- /package/dist/{chunk-4RG5IMZ7.js.map → chunk-GB4GM4C2.js.map} +0 -0
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,
|
|
@@ -207,7 +221,7 @@ function getBillingEnvironmentConfig(build) {
|
|
|
207
221
|
return config;
|
|
208
222
|
}
|
|
209
223
|
function getBuildType() {
|
|
210
|
-
const buildTimeType = true ? "
|
|
224
|
+
const buildTimeType = true ? "dev"?.toLowerCase() : void 0;
|
|
211
225
|
const runtimeType = process.env.BUILD_TYPE?.toLowerCase();
|
|
212
226
|
const buildType = buildTimeType || runtimeType;
|
|
213
227
|
if (buildType === "dev") {
|
|
@@ -425,9 +439,9 @@ async function pushDockerImage(docker, imageRef, logger) {
|
|
|
425
439
|
if (!output.includes("digest:") && !output.includes("pushed") && !output.includes("Pushed")) {
|
|
426
440
|
logger?.debug?.("No clear success indicator in push output, verifying...");
|
|
427
441
|
}
|
|
428
|
-
logger?.info?.("Image push completed successfully");
|
|
429
442
|
try {
|
|
430
443
|
await verifyImageExists(imageRef, logger);
|
|
444
|
+
logger?.info?.("Image push completed successfully");
|
|
431
445
|
resolve2();
|
|
432
446
|
} catch (error) {
|
|
433
447
|
reject(error);
|
|
@@ -1266,6 +1280,67 @@ Please verify the image exists: docker manifest inspect ${finalImageRef}`
|
|
|
1266
1280
|
};
|
|
1267
1281
|
}
|
|
1268
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
|
+
|
|
1269
1344
|
// src/client/common/contract/caller.ts
|
|
1270
1345
|
var import_accounts2 = require("viem/accounts");
|
|
1271
1346
|
|
|
@@ -2302,27 +2377,55 @@ var ERC7702Delegator_default = [
|
|
|
2302
2377
|
];
|
|
2303
2378
|
|
|
2304
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
|
+
}
|
|
2305
2403
|
async function estimateBatchGas(options) {
|
|
2306
|
-
const { publicClient, executions } = options;
|
|
2307
|
-
const
|
|
2308
|
-
const
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
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;
|
|
2314
2418
|
const maxCostWei = gasLimit * maxFeePerGas;
|
|
2315
|
-
const maxCostEth = formatETH(maxCostWei);
|
|
2316
2419
|
return {
|
|
2317
2420
|
gasLimit,
|
|
2318
2421
|
maxFeePerGas,
|
|
2319
|
-
maxPriorityFeePerGas,
|
|
2422
|
+
maxPriorityFeePerGas: gasTipCap,
|
|
2320
2423
|
maxCostWei,
|
|
2321
|
-
maxCostEth
|
|
2424
|
+
maxCostEth: formatETH(maxCostWei)
|
|
2322
2425
|
};
|
|
2323
2426
|
}
|
|
2324
2427
|
async function checkERC7702Delegation(publicClient, account, delegatorAddress) {
|
|
2325
|
-
const code = await publicClient.
|
|
2428
|
+
const code = await publicClient.getCode({ address: account });
|
|
2326
2429
|
if (!code) {
|
|
2327
2430
|
return false;
|
|
2328
2431
|
}
|
|
@@ -2339,36 +2442,7 @@ async function executeBatch(options, logger) {
|
|
|
2339
2442
|
if (!chain) {
|
|
2340
2443
|
throw new Error("Wallet client must have a chain");
|
|
2341
2444
|
}
|
|
2342
|
-
const
|
|
2343
|
-
[
|
|
2344
|
-
{
|
|
2345
|
-
type: "tuple[]",
|
|
2346
|
-
components: [
|
|
2347
|
-
{ name: "target", type: "address" },
|
|
2348
|
-
{ name: "value", type: "uint256" },
|
|
2349
|
-
{ name: "callData", type: "bytes" }
|
|
2350
|
-
]
|
|
2351
|
-
}
|
|
2352
|
-
],
|
|
2353
|
-
[executions]
|
|
2354
|
-
);
|
|
2355
|
-
const executeBatchMode = "0x0100000000000000000000000000000000000000000000000000000000000000";
|
|
2356
|
-
let executeBatchData;
|
|
2357
|
-
try {
|
|
2358
|
-
executeBatchData = (0, import_viem.encodeFunctionData)({
|
|
2359
|
-
abi: ERC7702Delegator_default,
|
|
2360
|
-
functionName: "execute",
|
|
2361
|
-
args: [executeBatchMode, encodedExecutions]
|
|
2362
|
-
});
|
|
2363
|
-
} catch {
|
|
2364
|
-
const functionSignature = "execute(bytes32,bytes)";
|
|
2365
|
-
const selector = (0, import_viem.keccak256)((0, import_viem.toBytes)(functionSignature)).slice(0, 10);
|
|
2366
|
-
const encodedParams = (0, import_viem.encodeAbiParameters)(
|
|
2367
|
-
[{ type: "bytes32" }, { type: "bytes" }],
|
|
2368
|
-
[executeBatchMode, encodedExecutions]
|
|
2369
|
-
);
|
|
2370
|
-
executeBatchData = (0, import_viem.concat)([selector, encodedParams]);
|
|
2371
|
-
}
|
|
2445
|
+
const executeBatchData = encodeExecuteBatchData(executions);
|
|
2372
2446
|
const isDelegated2 = await checkERC7702Delegation(
|
|
2373
2447
|
publicClient,
|
|
2374
2448
|
account.address,
|
|
@@ -2522,12 +2596,23 @@ function stripHexPrefix(value) {
|
|
|
2522
2596
|
}
|
|
2523
2597
|
|
|
2524
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
|
+
}
|
|
2525
2610
|
var MAX_ADDRESS_COUNT = 5;
|
|
2526
2611
|
var CanViewAppLogsPermission = "0x2fd3f2fe";
|
|
2527
2612
|
var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
|
|
2528
2613
|
var CanUpdateAppProfilePermission = "0x036fef61";
|
|
2529
2614
|
function getDefaultClientId() {
|
|
2530
|
-
const version = true ? "0.1
|
|
2615
|
+
const version = true ? "0.2.0-dev.1" : "0.0.0";
|
|
2531
2616
|
return `ecloud-sdk/v${version}`;
|
|
2532
2617
|
}
|
|
2533
2618
|
var UserApiClient = class {
|
|
@@ -2561,6 +2646,31 @@ var UserApiClient = class {
|
|
|
2561
2646
|
};
|
|
2562
2647
|
});
|
|
2563
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
|
+
}
|
|
2564
2674
|
/**
|
|
2565
2675
|
* Get available SKUs (instance types) from UserAPI
|
|
2566
2676
|
*/
|
|
@@ -2733,6 +2843,48 @@ Please check:
|
|
|
2733
2843
|
};
|
|
2734
2844
|
}
|
|
2735
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
|
+
}
|
|
2736
2888
|
|
|
2737
2889
|
// src/client/common/utils/billing.ts
|
|
2738
2890
|
function isSubscriptionActive(status) {
|
|
@@ -5554,6 +5706,97 @@ async function withSDKTelemetry(options, action) {
|
|
|
5554
5706
|
}
|
|
5555
5707
|
|
|
5556
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
|
+
}
|
|
5557
5800
|
function validateDeployOptions(options) {
|
|
5558
5801
|
if (!options.privateKey) {
|
|
5559
5802
|
throw new Error("privateKey is required for deployment");
|
|
@@ -5774,7 +6017,7 @@ async function prepareDeploy(options, logger = defaultLogger) {
|
|
|
5774
6017
|
logger.debug("Estimating gas...");
|
|
5775
6018
|
const gasEstimate = await estimateBatchGas({
|
|
5776
6019
|
publicClient: batch.publicClient,
|
|
5777
|
-
|
|
6020
|
+
account: batch.walletClient.account.address,
|
|
5778
6021
|
executions: batch.executions
|
|
5779
6022
|
});
|
|
5780
6023
|
const data = {
|
|
@@ -5864,6 +6107,81 @@ async function checkAppLogPermission(preflightCtx, appAddress, logger) {
|
|
|
5864
6107
|
}
|
|
5865
6108
|
|
|
5866
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
|
+
}
|
|
5867
6185
|
function validateUpgradeOptions(options) {
|
|
5868
6186
|
if (!options.privateKey) {
|
|
5869
6187
|
throw new Error("privateKey is required for upgrade");
|
|
@@ -6026,7 +6344,7 @@ async function prepareUpgrade(options, logger = defaultLogger) {
|
|
|
6026
6344
|
logger.debug("Estimating gas...");
|
|
6027
6345
|
const gasEstimate = await estimateBatchGas({
|
|
6028
6346
|
publicClient: batch.publicClient,
|
|
6029
|
-
|
|
6347
|
+
account: batch.walletClient.account.address,
|
|
6030
6348
|
executions: batch.executions
|
|
6031
6349
|
});
|
|
6032
6350
|
const data = {
|
|
@@ -6846,6 +7164,24 @@ function createAppModule(ctx) {
|
|
|
6846
7164
|
logger
|
|
6847
7165
|
);
|
|
6848
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
|
+
},
|
|
6849
7185
|
async executeDeploy(prepared, gas) {
|
|
6850
7186
|
const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
|
|
6851
7187
|
const chain = getChainFromID(environment.chainID);
|
|
@@ -6906,6 +7242,24 @@ function createAppModule(ctx) {
|
|
|
6906
7242
|
logger
|
|
6907
7243
|
);
|
|
6908
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
|
+
},
|
|
6909
7263
|
async executeUpgrade(prepared, gas) {
|
|
6910
7264
|
const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
|
|
6911
7265
|
const chain = getChainFromID(environment.chainID);
|
|
@@ -7527,6 +7881,360 @@ function createBillingModule(config) {
|
|
|
7527
7881
|
};
|
|
7528
7882
|
}
|
|
7529
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
|
+
|
|
7530
8238
|
// src/client/common/utils/instance.ts
|
|
7531
8239
|
async function getCurrentInstanceType(preflightCtx, appID, logger, clientId) {
|
|
7532
8240
|
try {
|
|
@@ -7581,10 +8289,20 @@ function createECloudClient(cfg) {
|
|
|
7581
8289
|
}
|
|
7582
8290
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7583
8291
|
0 && (module.exports = {
|
|
8292
|
+
AuthRequiredError,
|
|
8293
|
+
BUILD_STATUS,
|
|
8294
|
+
BadRequestError,
|
|
8295
|
+
BuildError,
|
|
8296
|
+
BuildFailedError,
|
|
8297
|
+
ConflictError,
|
|
8298
|
+
ForbiddenError,
|
|
7584
8299
|
NoopClient,
|
|
8300
|
+
NotFoundError,
|
|
7585
8301
|
PRIMARY_LANGUAGES,
|
|
7586
8302
|
PostHogClient,
|
|
8303
|
+
TimeoutError,
|
|
7587
8304
|
UserApiClient,
|
|
8305
|
+
addHexPrefix,
|
|
7588
8306
|
addMetric,
|
|
7589
8307
|
addMetricWithDimensions,
|
|
7590
8308
|
assertValidFilePath,
|
|
@@ -7594,6 +8312,7 @@ function createECloudClient(cfg) {
|
|
|
7594
8312
|
createApp,
|
|
7595
8313
|
createAppEnvironment,
|
|
7596
8314
|
createBillingModule,
|
|
8315
|
+
createBuildModule,
|
|
7597
8316
|
createComputeModule,
|
|
7598
8317
|
createECloudClient,
|
|
7599
8318
|
createMetricsContext,
|
|
@@ -7637,12 +8356,15 @@ function createECloudClient(cfg) {
|
|
|
7637
8356
|
listStoredKeys,
|
|
7638
8357
|
logs,
|
|
7639
8358
|
prepareDeploy,
|
|
8359
|
+
prepareDeployFromVerifiableBuild,
|
|
7640
8360
|
prepareUpgrade,
|
|
8361
|
+
prepareUpgradeFromVerifiableBuild,
|
|
7641
8362
|
requirePrivateKey,
|
|
7642
8363
|
sanitizeString,
|
|
7643
8364
|
sanitizeURL,
|
|
7644
8365
|
sanitizeXURL,
|
|
7645
8366
|
storePrivateKey,
|
|
8367
|
+
stripHexPrefix,
|
|
7646
8368
|
validateAppID,
|
|
7647
8369
|
validateAppName,
|
|
7648
8370
|
validateCreateAppParams,
|