@enclave-run/sdk 0.0.0-dev → 0.0.0-dev.5
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/README.md +51 -18
- package/dist/index.d.mts +372 -17
- package/dist/index.d.ts +372 -17
- package/dist/index.js +526 -90
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +524 -90
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/index.mjs
CHANGED
|
@@ -60,7 +60,7 @@ import createClient from "openapi-fetch";
|
|
|
60
60
|
import platform2 from "platform";
|
|
61
61
|
|
|
62
62
|
// package.json
|
|
63
|
-
var version = "0.0.0-dev";
|
|
63
|
+
var version = "0.0.0-dev.5";
|
|
64
64
|
|
|
65
65
|
// src/utils.ts
|
|
66
66
|
import platform from "platform";
|
|
@@ -244,6 +244,21 @@ var TemplateError = class extends SandboxError {
|
|
|
244
244
|
this.name = "TemplateError";
|
|
245
245
|
}
|
|
246
246
|
};
|
|
247
|
+
var TemplateTagConflictError = class extends TemplateError {
|
|
248
|
+
constructor(options) {
|
|
249
|
+
var _a3;
|
|
250
|
+
super(
|
|
251
|
+
(_a3 = options.message) != null ? _a3 : `Template tag "${options.tag}" conflicted with another mutation. Fetch its current head with Template.getTagHead() before retrying.`
|
|
252
|
+
);
|
|
253
|
+
this.name = "TemplateTagConflictError";
|
|
254
|
+
this.templateId = options.templateId;
|
|
255
|
+
this.tag = options.tag;
|
|
256
|
+
this.candidateBuildId = options.candidateBuildId;
|
|
257
|
+
this.expectedBuildId = options.expectedBuildId;
|
|
258
|
+
this.expectedVersion = options.expectedVersion;
|
|
259
|
+
this.reason = options.reason;
|
|
260
|
+
}
|
|
261
|
+
};
|
|
247
262
|
var RateLimitError = class extends SandboxError {
|
|
248
263
|
constructor(message) {
|
|
249
264
|
super(message);
|
|
@@ -1653,9 +1668,9 @@ var ALL_TRAFFIC = "0.0.0.0/0";
|
|
|
1653
1668
|
function shellEscape(value) {
|
|
1654
1669
|
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
1655
1670
|
}
|
|
1656
|
-
function withCredentials(
|
|
1671
|
+
function withCredentials(url2, username, password) {
|
|
1657
1672
|
if (!username && !password) {
|
|
1658
|
-
return
|
|
1673
|
+
return url2;
|
|
1659
1674
|
}
|
|
1660
1675
|
if (!username || !password) {
|
|
1661
1676
|
throw new InvalidArgumentError(
|
|
@@ -1664,9 +1679,9 @@ function withCredentials(url, username, password) {
|
|
|
1664
1679
|
}
|
|
1665
1680
|
let parsed;
|
|
1666
1681
|
try {
|
|
1667
|
-
parsed = new URL(
|
|
1682
|
+
parsed = new URL(url2);
|
|
1668
1683
|
} catch (e) {
|
|
1669
|
-
throw new InvalidArgumentError(`Invalid Git URL: ${
|
|
1684
|
+
throw new InvalidArgumentError(`Invalid Git URL: ${url2}`);
|
|
1670
1685
|
}
|
|
1671
1686
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
1672
1687
|
throw new InvalidArgumentError(
|
|
@@ -1677,27 +1692,27 @@ function withCredentials(url, username, password) {
|
|
|
1677
1692
|
parsed.password = password;
|
|
1678
1693
|
return parsed.toString();
|
|
1679
1694
|
}
|
|
1680
|
-
function stripCredentials(
|
|
1695
|
+
function stripCredentials(url2) {
|
|
1681
1696
|
let parsed;
|
|
1682
1697
|
try {
|
|
1683
|
-
parsed = new URL(
|
|
1698
|
+
parsed = new URL(url2);
|
|
1684
1699
|
} catch (e) {
|
|
1685
|
-
return
|
|
1700
|
+
return url2;
|
|
1686
1701
|
}
|
|
1687
1702
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
1688
|
-
return
|
|
1703
|
+
return url2;
|
|
1689
1704
|
}
|
|
1690
1705
|
if (!parsed.username && !parsed.password) {
|
|
1691
|
-
return
|
|
1706
|
+
return url2;
|
|
1692
1707
|
}
|
|
1693
1708
|
parsed.username = "";
|
|
1694
1709
|
parsed.password = "";
|
|
1695
1710
|
return parsed.toString();
|
|
1696
1711
|
}
|
|
1697
|
-
function deriveRepoDirFromUrl(
|
|
1712
|
+
function deriveRepoDirFromUrl(url2) {
|
|
1698
1713
|
let parsed;
|
|
1699
1714
|
try {
|
|
1700
|
-
parsed = new URL(
|
|
1715
|
+
parsed = new URL(url2);
|
|
1701
1716
|
} catch (e) {
|
|
1702
1717
|
return void 0;
|
|
1703
1718
|
}
|
|
@@ -1984,7 +1999,7 @@ var Git = class {
|
|
|
1984
1999
|
* @param opts Clone options.
|
|
1985
2000
|
* @returns Command result from the command runner.
|
|
1986
2001
|
*/
|
|
1987
|
-
async clone(
|
|
2002
|
+
async clone(url2, opts) {
|
|
1988
2003
|
const _a3 = opts != null ? opts : {}, {
|
|
1989
2004
|
username,
|
|
1990
2005
|
password,
|
|
@@ -2006,10 +2021,10 @@ var Git = class {
|
|
|
2006
2021
|
);
|
|
2007
2022
|
}
|
|
2008
2023
|
const attemptClone = async (authUsername, authPassword) => {
|
|
2009
|
-
const urlWithCreds = authUsername && authPassword ? withCredentials(
|
|
2024
|
+
const urlWithCreds = authUsername && authPassword ? withCredentials(url2, authUsername, authPassword) : url2;
|
|
2010
2025
|
const sanitizedUrl = stripCredentials(urlWithCreds);
|
|
2011
2026
|
const stripInlineCreds = !dangerouslyStoreCredentials && sanitizedUrl !== urlWithCreds;
|
|
2012
|
-
const repoPath = stripInlineCreds ? path2 != null ? path2 : deriveRepoDirFromUrl(
|
|
2027
|
+
const repoPath = stripInlineCreds ? path2 != null ? path2 : deriveRepoDirFromUrl(url2) : path2;
|
|
2013
2028
|
if (stripInlineCreds && !repoPath) {
|
|
2014
2029
|
throw new InvalidArgumentError(
|
|
2015
2030
|
"A destination path is required when using credentials without storing them."
|
|
@@ -2068,8 +2083,8 @@ var Git = class {
|
|
|
2068
2083
|
* @param opts Remote add options.
|
|
2069
2084
|
* @returns Command result from the command runner.
|
|
2070
2085
|
*/
|
|
2071
|
-
async remoteAdd(path2, name,
|
|
2072
|
-
if (!name || !
|
|
2086
|
+
async remoteAdd(path2, name, url2, opts) {
|
|
2087
|
+
if (!name || !url2) {
|
|
2073
2088
|
throw new InvalidArgumentError(
|
|
2074
2089
|
"Both remote name and URL are required to add a git remote."
|
|
2075
2090
|
);
|
|
@@ -2079,12 +2094,12 @@ var Git = class {
|
|
|
2079
2094
|
if (fetch2) {
|
|
2080
2095
|
addArgs.push("-f");
|
|
2081
2096
|
}
|
|
2082
|
-
addArgs.push(name,
|
|
2097
|
+
addArgs.push(name, url2);
|
|
2083
2098
|
if (!overwrite) {
|
|
2084
2099
|
return this.runGit(addArgs, path2, rest);
|
|
2085
2100
|
}
|
|
2086
2101
|
const addCmd = buildGitCommand(addArgs, path2);
|
|
2087
|
-
const setUrlCmd = buildGitCommand(["remote", "set-url", name,
|
|
2102
|
+
const setUrlCmd = buildGitCommand(["remote", "set-url", name, url2], path2);
|
|
2088
2103
|
let cmd = `${addCmd} || ${setUrlCmd}`;
|
|
2089
2104
|
if (fetch2) {
|
|
2090
2105
|
const fetchCmd = buildGitCommand(["fetch", name], path2);
|
|
@@ -2529,13 +2544,13 @@ var Git = class {
|
|
|
2529
2544
|
}
|
|
2530
2545
|
async getRemoteUrl(path2, remote, opts) {
|
|
2531
2546
|
const result = await this.runGit(["remote", "get-url", remote], path2, opts);
|
|
2532
|
-
const
|
|
2533
|
-
if (!
|
|
2547
|
+
const url2 = result.stdout.trim();
|
|
2548
|
+
if (!url2) {
|
|
2534
2549
|
throw new InvalidArgumentError(
|
|
2535
2550
|
`Remote "${remote}" URL not found in repository.`
|
|
2536
2551
|
);
|
|
2537
2552
|
}
|
|
2538
|
-
return
|
|
2553
|
+
return url2;
|
|
2539
2554
|
}
|
|
2540
2555
|
async resolveRemoteName(path2, remote, opts) {
|
|
2541
2556
|
if (remote) {
|
|
@@ -3068,6 +3083,26 @@ function getLifecycle(opts) {
|
|
|
3068
3083
|
var _a3;
|
|
3069
3084
|
return (_a3 = opts == null ? void 0 : opts.lifecycle) != null ? _a3 : { onTimeout: "kill", autoResume: false };
|
|
3070
3085
|
}
|
|
3086
|
+
function resolveSandboxTarget(target, opts) {
|
|
3087
|
+
if (typeof target === "string") {
|
|
3088
|
+
return {
|
|
3089
|
+
sandboxId: target,
|
|
3090
|
+
config: ConnectionConfig.forSandbox(opts)
|
|
3091
|
+
};
|
|
3092
|
+
}
|
|
3093
|
+
const referenceRegion = ConnectionConfig.resolveRegion(target.region);
|
|
3094
|
+
if ((opts == null ? void 0 : opts.region) && ConnectionConfig.resolveRegion(opts.region) !== referenceRegion) {
|
|
3095
|
+
throw new Error(
|
|
3096
|
+
`Sandbox ${target.sandboxId} belongs to region "${referenceRegion}", not "${opts.region}"`
|
|
3097
|
+
);
|
|
3098
|
+
}
|
|
3099
|
+
return {
|
|
3100
|
+
sandboxId: target.sandboxId,
|
|
3101
|
+
config: ConnectionConfig.forSandbox(__spreadProps(__spreadValues({}, opts), {
|
|
3102
|
+
region: referenceRegion
|
|
3103
|
+
}))
|
|
3104
|
+
};
|
|
3105
|
+
}
|
|
3071
3106
|
var SandboxApi = class {
|
|
3072
3107
|
constructor() {
|
|
3073
3108
|
}
|
|
@@ -3079,9 +3114,9 @@ var SandboxApi = class {
|
|
|
3079
3114
|
*
|
|
3080
3115
|
* @returns `true` if the sandbox was found and killed, `false` otherwise.
|
|
3081
3116
|
*/
|
|
3082
|
-
static async kill(
|
|
3117
|
+
static async kill(target, opts) {
|
|
3083
3118
|
var _a3;
|
|
3084
|
-
const config =
|
|
3119
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3085
3120
|
const client = new ApiClient(config);
|
|
3086
3121
|
const res = await client.api.DELETE("/sandboxes/{sandboxID}", {
|
|
3087
3122
|
params: {
|
|
@@ -3108,8 +3143,8 @@ var SandboxApi = class {
|
|
|
3108
3143
|
*
|
|
3109
3144
|
* @returns sandbox information.
|
|
3110
3145
|
*/
|
|
3111
|
-
static async getInfo(
|
|
3112
|
-
const fullInfo = await this.getFullInfo(
|
|
3146
|
+
static async getInfo(target, opts) {
|
|
3147
|
+
const fullInfo = await this.getFullInfo(target, opts);
|
|
3113
3148
|
delete fullInfo.envdAccessToken;
|
|
3114
3149
|
delete fullInfo.sandboxDomain;
|
|
3115
3150
|
return fullInfo;
|
|
@@ -3122,9 +3157,9 @@ var SandboxApi = class {
|
|
|
3122
3157
|
*
|
|
3123
3158
|
* @returns List of sandbox metrics containing CPU, memory and disk usage information.
|
|
3124
3159
|
*/
|
|
3125
|
-
static async getMetrics(
|
|
3160
|
+
static async getMetrics(target, opts) {
|
|
3126
3161
|
var _a3, _b;
|
|
3127
|
-
const config =
|
|
3162
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3128
3163
|
const client = new ApiClient(config);
|
|
3129
3164
|
const start = (opts == null ? void 0 : opts.start) ? opts.start.getTime() : void 0;
|
|
3130
3165
|
const end = (opts == null ? void 0 : opts.end) ? opts.end.getTime() : void 0;
|
|
@@ -3167,9 +3202,9 @@ var SandboxApi = class {
|
|
|
3167
3202
|
* @param timeoutMs timeout in **milliseconds**.
|
|
3168
3203
|
* @param opts connection options.
|
|
3169
3204
|
*/
|
|
3170
|
-
static async setTimeout(
|
|
3205
|
+
static async setTimeout(target, timeoutMs, opts) {
|
|
3171
3206
|
var _a3;
|
|
3172
|
-
const config =
|
|
3207
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3173
3208
|
const client = new ApiClient(config);
|
|
3174
3209
|
const res = await client.api.POST("/sandboxes/{sandboxID}/timeout", {
|
|
3175
3210
|
params: {
|
|
@@ -3190,9 +3225,9 @@ var SandboxApi = class {
|
|
|
3190
3225
|
throw err;
|
|
3191
3226
|
}
|
|
3192
3227
|
}
|
|
3193
|
-
static async getFullInfo(
|
|
3228
|
+
static async getFullInfo(target, opts) {
|
|
3194
3229
|
var _a3, _b;
|
|
3195
|
-
const config =
|
|
3230
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3196
3231
|
const client = new ApiClient(config);
|
|
3197
3232
|
const res = await client.api.GET("/sandboxes/{sandboxID}", {
|
|
3198
3233
|
params: {
|
|
@@ -3214,6 +3249,7 @@ var SandboxApi = class {
|
|
|
3214
3249
|
}
|
|
3215
3250
|
return __spreadProps(__spreadValues({
|
|
3216
3251
|
sandboxId: res.data.sandboxID,
|
|
3252
|
+
buildId: res.data.buildID,
|
|
3217
3253
|
templateId: res.data.templateID
|
|
3218
3254
|
}, res.data.alias && { name: res.data.alias }), {
|
|
3219
3255
|
metadata: (_b = res.data.metadata) != null ? _b : {},
|
|
@@ -3236,9 +3272,9 @@ var SandboxApi = class {
|
|
|
3236
3272
|
*
|
|
3237
3273
|
* @returns `true` if the sandbox got paused, `false` if the sandbox was already paused.
|
|
3238
3274
|
*/
|
|
3239
|
-
static async pause(
|
|
3275
|
+
static async pause(target, opts) {
|
|
3240
3276
|
var _a3, _b;
|
|
3241
|
-
const config =
|
|
3277
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3242
3278
|
const client = new ApiClient(config);
|
|
3243
3279
|
const res = await client.api.POST("/sandboxes/{sandboxID}/pause", {
|
|
3244
3280
|
params: {
|
|
@@ -3272,9 +3308,9 @@ var SandboxApi = class {
|
|
|
3272
3308
|
*
|
|
3273
3309
|
* @returns snapshot information including the snapshot name that can be used with Sandbox.create().
|
|
3274
3310
|
*/
|
|
3275
|
-
static async createSnapshot(
|
|
3311
|
+
static async createSnapshot(target, opts) {
|
|
3276
3312
|
var _a3;
|
|
3277
|
-
const config =
|
|
3313
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3278
3314
|
const client = new ApiClient(config);
|
|
3279
3315
|
const res = await client.api.POST("/sandboxes/{sandboxID}/snapshots", {
|
|
3280
3316
|
params: {
|
|
@@ -3393,14 +3429,51 @@ var SandboxApi = class {
|
|
|
3393
3429
|
}
|
|
3394
3430
|
sandbox = res.data;
|
|
3395
3431
|
}
|
|
3432
|
+
return this.sandboxInfoFromCreate(sandbox, config, opts);
|
|
3433
|
+
}
|
|
3434
|
+
static async recoverSandboxCreate(recovery, opts) {
|
|
3435
|
+
if (!recovery.idempotencyKey.trim()) {
|
|
3436
|
+
throw new InvalidArgumentError(
|
|
3437
|
+
"Sandbox create recovery requires an idempotency key"
|
|
3438
|
+
);
|
|
3439
|
+
}
|
|
3440
|
+
const recoveryRegion = recovery.region ? ConnectionConfig.resolveRegion(recovery.region) : void 0;
|
|
3441
|
+
if (recoveryRegion && (opts == null ? void 0 : opts.region) && ConnectionConfig.resolveRegion(opts.region) !== recoveryRegion) {
|
|
3442
|
+
throw new InvalidArgumentError(
|
|
3443
|
+
`Sandbox create recovery belongs to region "${recoveryRegion}", not "${opts.region}"`
|
|
3444
|
+
);
|
|
3445
|
+
}
|
|
3446
|
+
const config = ConnectionConfig.forSandbox(__spreadProps(__spreadValues({}, opts), {
|
|
3447
|
+
region: recoveryRegion != null ? recoveryRegion : opts == null ? void 0 : opts.region
|
|
3448
|
+
}));
|
|
3449
|
+
const signal = config.getSignal(opts == null ? void 0 : opts.requestTimeoutMs);
|
|
3450
|
+
const sandbox = await this.waitForSandboxCreate(
|
|
3451
|
+
new ApiClient(config),
|
|
3452
|
+
__spreadProps(__spreadValues({}, recovery), {
|
|
3453
|
+
region: config.region
|
|
3454
|
+
}),
|
|
3455
|
+
signal
|
|
3456
|
+
);
|
|
3457
|
+
return this.sandboxInfoFromCreate(sandbox, config, opts);
|
|
3458
|
+
}
|
|
3459
|
+
static async sandboxInfoFromCreate(sandbox, config, opts) {
|
|
3396
3460
|
if (compareVersions4(sandbox.envdVersion, "0.1.0") < 0) {
|
|
3397
|
-
await this.kill(
|
|
3461
|
+
await this.kill(
|
|
3462
|
+
{
|
|
3463
|
+
sandboxId: sandbox.sandboxID,
|
|
3464
|
+
region: sandbox.region
|
|
3465
|
+
},
|
|
3466
|
+
__spreadProps(__spreadValues({}, opts), {
|
|
3467
|
+
region: sandbox.region
|
|
3468
|
+
})
|
|
3469
|
+
);
|
|
3398
3470
|
throw new TemplateError(
|
|
3399
3471
|
"You need to update the template to use the new SDK. You can do this by running `enclave template build` in the directory with the template."
|
|
3400
3472
|
);
|
|
3401
3473
|
}
|
|
3402
3474
|
return {
|
|
3403
3475
|
sandboxId: sandbox.sandboxID,
|
|
3476
|
+
buildId: sandbox.buildID,
|
|
3404
3477
|
sandboxDomain: sandbox.domain || void 0,
|
|
3405
3478
|
sandboxRegion: sandbox.region,
|
|
3406
3479
|
capacityTier: sandbox.capacityTier,
|
|
@@ -3414,7 +3487,13 @@ var SandboxApi = class {
|
|
|
3414
3487
|
};
|
|
3415
3488
|
}
|
|
3416
3489
|
static async waitForSandboxCreate(client, recovery, signal) {
|
|
3417
|
-
var _a3, _b;
|
|
3490
|
+
var _a3, _b, _c;
|
|
3491
|
+
let lastRecoveryError;
|
|
3492
|
+
let recoveryRetryDelayMs = 25;
|
|
3493
|
+
const waitToRetryRecovery = async () => {
|
|
3494
|
+
await new Promise((resolve) => setTimeout(resolve, recoveryRetryDelayMs));
|
|
3495
|
+
recoveryRetryDelayMs = Math.min(recoveryRetryDelayMs * 2, 1e3);
|
|
3496
|
+
};
|
|
3418
3497
|
while (!(signal == null ? void 0 : signal.aborted)) {
|
|
3419
3498
|
let res;
|
|
3420
3499
|
try {
|
|
@@ -3430,12 +3509,17 @@ var SandboxApi = class {
|
|
|
3430
3509
|
}
|
|
3431
3510
|
);
|
|
3432
3511
|
} catch (cause) {
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3512
|
+
lastRecoveryError = cause;
|
|
3513
|
+
await waitToRetryRecovery();
|
|
3514
|
+
continue;
|
|
3515
|
+
}
|
|
3516
|
+
const status = res.response.status;
|
|
3517
|
+
if (status === 404 || status === 408 || status === 425 || status >= 500) {
|
|
3518
|
+
lastRecoveryError = handleApiError(res);
|
|
3519
|
+
await waitToRetryRecovery();
|
|
3520
|
+
continue;
|
|
3438
3521
|
}
|
|
3522
|
+
recoveryRetryDelayMs = 25;
|
|
3439
3523
|
const err = handleApiError(res);
|
|
3440
3524
|
if (err) {
|
|
3441
3525
|
throw err;
|
|
@@ -3454,13 +3538,13 @@ var SandboxApi = class {
|
|
|
3454
3538
|
throw new OutcomeUnknownError(
|
|
3455
3539
|
"Sandbox admission committed, but waiting for its terminal result timed out.",
|
|
3456
3540
|
recovery,
|
|
3457
|
-
signal == null ? void 0 : signal.reason
|
|
3541
|
+
(_c = signal == null ? void 0 : signal.reason) != null ? _c : lastRecoveryError
|
|
3458
3542
|
);
|
|
3459
3543
|
}
|
|
3460
|
-
static async connectSandbox(
|
|
3544
|
+
static async connectSandbox(target, opts) {
|
|
3461
3545
|
var _a3, _b;
|
|
3462
3546
|
const timeoutMs = (_a3 = opts == null ? void 0 : opts.timeoutMs) != null ? _a3 : DEFAULT_SANDBOX_TIMEOUT_MS;
|
|
3463
|
-
const config =
|
|
3547
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3464
3548
|
const client = new ApiClient(config);
|
|
3465
3549
|
const res = await client.api.POST("/sandboxes/{sandboxID}/connect", {
|
|
3466
3550
|
params: {
|
|
@@ -3482,6 +3566,7 @@ var SandboxApi = class {
|
|
|
3482
3566
|
}
|
|
3483
3567
|
return {
|
|
3484
3568
|
sandboxId: res.data.sandboxID,
|
|
3569
|
+
buildId: res.data.buildID,
|
|
3485
3570
|
sandboxDomain: res.data.domain || void 0,
|
|
3486
3571
|
sandboxRegion: res.data.region,
|
|
3487
3572
|
capacityTier: res.data.capacityTier,
|
|
@@ -3562,6 +3647,7 @@ var SandboxPaginator = class extends BasePaginator {
|
|
|
3562
3647
|
var _a4;
|
|
3563
3648
|
return __spreadProps(__spreadValues({
|
|
3564
3649
|
sandboxId: sandbox.sandboxID,
|
|
3650
|
+
buildId: sandbox.buildID,
|
|
3565
3651
|
templateId: sandbox.templateID
|
|
3566
3652
|
}, sandbox.alias && { name: sandbox.alias }), {
|
|
3567
3653
|
metadata: (_a4 = sandbox.metadata) != null ? _a4 : {},
|
|
@@ -3628,8 +3714,14 @@ var Sandbox = class extends SandboxApi {
|
|
|
3628
3714
|
this.mcpPort = 50005;
|
|
3629
3715
|
this.connectionConfig = ConnectionConfig.forSandbox(opts);
|
|
3630
3716
|
this.sandboxId = opts.sandboxId;
|
|
3717
|
+
this.buildId = opts.buildId;
|
|
3631
3718
|
this.sandboxDomain = (_a3 = opts.sandboxDomain) != null ? _a3 : this.connectionConfig.domain;
|
|
3632
|
-
this.sandboxRegion = opts.sandboxRegion;
|
|
3719
|
+
this.sandboxRegion = this.connectionConfig.debug ? opts.sandboxRegion : ConnectionConfig.resolveRegion(opts.sandboxRegion);
|
|
3720
|
+
if (!this.connectionConfig.debug && this.connectionConfig.region !== this.sandboxRegion) {
|
|
3721
|
+
throw new Error(
|
|
3722
|
+
`Sandbox ${opts.sandboxId} belongs to region "${this.sandboxRegion}", not "${this.connectionConfig.region}"`
|
|
3723
|
+
);
|
|
3724
|
+
}
|
|
3633
3725
|
this.capacityTier = opts.capacityTier;
|
|
3634
3726
|
this.envdAccessToken = opts.envdAccessToken;
|
|
3635
3727
|
this.trafficAccessToken = opts.trafficAccessToken;
|
|
@@ -3646,7 +3738,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3646
3738
|
baseUrl: this.envdApiUrl,
|
|
3647
3739
|
useBinaryFormat: false,
|
|
3648
3740
|
interceptors: (opts == null ? void 0 : opts.logger) ? [createRpcLogger(opts.logger)] : void 0,
|
|
3649
|
-
fetch: (
|
|
3741
|
+
fetch: (url2, options) => {
|
|
3650
3742
|
const headers = new Headers(this.connectionConfig.headers);
|
|
3651
3743
|
new Headers(options == null ? void 0 : options.headers).forEach(
|
|
3652
3744
|
(value, key) => headers.append(key, value)
|
|
@@ -3661,7 +3753,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3661
3753
|
headers,
|
|
3662
3754
|
redirect: "follow"
|
|
3663
3755
|
});
|
|
3664
|
-
return fetch(
|
|
3756
|
+
return fetch(url2, options);
|
|
3665
3757
|
}
|
|
3666
3758
|
});
|
|
3667
3759
|
this.envdApi = new EnvdApiClient(
|
|
@@ -3690,6 +3782,33 @@ var Sandbox = class extends SandboxApi {
|
|
|
3690
3782
|
});
|
|
3691
3783
|
this.git = new Git(this.commands);
|
|
3692
3784
|
}
|
|
3785
|
+
/**
|
|
3786
|
+
* Serializable regional reference for reconnecting to this sandbox.
|
|
3787
|
+
*/
|
|
3788
|
+
get ref() {
|
|
3789
|
+
if (this.connectionConfig.debug) {
|
|
3790
|
+
throw new Error("Sandbox references are unavailable in debug mode");
|
|
3791
|
+
}
|
|
3792
|
+
return {
|
|
3793
|
+
sandboxId: this.sandboxId,
|
|
3794
|
+
region: this.sandboxRegion
|
|
3795
|
+
};
|
|
3796
|
+
}
|
|
3797
|
+
connectionOptions(opts) {
|
|
3798
|
+
const ownerRegion = this.connectionConfig.debug ? this.connectionConfig.region : this.sandboxRegion;
|
|
3799
|
+
if (!this.connectionConfig.debug && (opts == null ? void 0 : opts.region) && ConnectionConfig.resolveRegion(opts.region) !== ownerRegion) {
|
|
3800
|
+
throw new Error(
|
|
3801
|
+
`Sandbox ${this.sandboxId} belongs to region "${ownerRegion}", not "${opts.region}"`
|
|
3802
|
+
);
|
|
3803
|
+
}
|
|
3804
|
+
return __spreadProps(__spreadValues(__spreadValues({}, this.connectionConfig), opts), {
|
|
3805
|
+
apiUrl: this.connectionConfig.apiUrl,
|
|
3806
|
+
sandboxUrl: this.connectionConfig.sandboxUrl,
|
|
3807
|
+
domain: this.connectionConfig.domain,
|
|
3808
|
+
debug: this.connectionConfig.debug,
|
|
3809
|
+
region: ownerRegion
|
|
3810
|
+
});
|
|
3811
|
+
}
|
|
3693
3812
|
/**
|
|
3694
3813
|
* List all sandboxes.
|
|
3695
3814
|
*
|
|
@@ -3700,6 +3819,20 @@ var Sandbox = class extends SandboxApi {
|
|
|
3700
3819
|
static list(opts) {
|
|
3701
3820
|
return new SandboxPaginator(opts);
|
|
3702
3821
|
}
|
|
3822
|
+
/**
|
|
3823
|
+
* Create an immutable regional scope so repeated sandbox operations do not
|
|
3824
|
+
* need to repeat the same region option.
|
|
3825
|
+
*
|
|
3826
|
+
* @example
|
|
3827
|
+
* ```ts
|
|
3828
|
+
* const yyz = Sandbox.inRegion("yyz")
|
|
3829
|
+
* const sandbox = await yyz.create()
|
|
3830
|
+
* const sameSandbox = await yyz.connect(sandbox.sandboxId)
|
|
3831
|
+
* ```
|
|
3832
|
+
*/
|
|
3833
|
+
static inRegion(region) {
|
|
3834
|
+
return new SandboxRegionScope(this, region);
|
|
3835
|
+
}
|
|
3703
3836
|
static async create(templateOrOpts, opts) {
|
|
3704
3837
|
var _a3, _b;
|
|
3705
3838
|
const { template, sandboxOpts } = typeof templateOrOpts === "string" ? {
|
|
@@ -3713,6 +3846,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3713
3846
|
if (config.debug) {
|
|
3714
3847
|
return new this(__spreadValues({
|
|
3715
3848
|
sandboxId: "debug_sandbox_id",
|
|
3849
|
+
buildId: "debug_build_id",
|
|
3716
3850
|
sandboxRegion: "debug",
|
|
3717
3851
|
capacityTier: "shared",
|
|
3718
3852
|
envdVersion: ENVD_DEBUG_FALLBACK
|
|
@@ -3723,7 +3857,9 @@ var Sandbox = class extends SandboxApi {
|
|
|
3723
3857
|
(_a3 = sandboxOpts == null ? void 0 : sandboxOpts.timeoutMs) != null ? _a3 : this.defaultSandboxTimeoutMs,
|
|
3724
3858
|
sandboxOpts
|
|
3725
3859
|
);
|
|
3726
|
-
const sandbox = new this(__spreadValues(__spreadValues({}, config), sandboxInfo)
|
|
3860
|
+
const sandbox = new this(__spreadProps(__spreadValues(__spreadValues({}, config), sandboxInfo), {
|
|
3861
|
+
region: sandboxInfo.sandboxRegion
|
|
3862
|
+
}));
|
|
3727
3863
|
if (sandboxOpts == null ? void 0 : sandboxOpts.mcp) {
|
|
3728
3864
|
sandbox.mcpToken = crypto.randomUUID();
|
|
3729
3865
|
const res = await sandbox.commands.run(
|
|
@@ -3741,6 +3877,51 @@ var Sandbox = class extends SandboxApi {
|
|
|
3741
3877
|
}
|
|
3742
3878
|
return sandbox;
|
|
3743
3879
|
}
|
|
3880
|
+
/**
|
|
3881
|
+
* Recover a create whose authoritative response was lost without resending
|
|
3882
|
+
* the original create payload.
|
|
3883
|
+
*
|
|
3884
|
+
* Pass `OutcomeUnknownError.recovery`. Recovery is pinned to the operation's
|
|
3885
|
+
* owning region and cannot create a second sandbox with different options.
|
|
3886
|
+
*
|
|
3887
|
+
* @example
|
|
3888
|
+
* ```ts
|
|
3889
|
+
* try {
|
|
3890
|
+
* return await Sandbox.create("base", { idempotencyKey: "job-123" })
|
|
3891
|
+
* } catch (error) {
|
|
3892
|
+
* if (error instanceof OutcomeUnknownError) {
|
|
3893
|
+
* return Sandbox.recoverCreate(error.recovery)
|
|
3894
|
+
* }
|
|
3895
|
+
* throw error
|
|
3896
|
+
* }
|
|
3897
|
+
* ```
|
|
3898
|
+
*/
|
|
3899
|
+
static async recoverCreate(recovery, opts) {
|
|
3900
|
+
var _a3;
|
|
3901
|
+
const config = ConnectionConfig.forSandbox(__spreadProps(__spreadValues({}, opts), {
|
|
3902
|
+
region: (_a3 = recovery.region) != null ? _a3 : opts == null ? void 0 : opts.region
|
|
3903
|
+
}));
|
|
3904
|
+
const sandboxInfo = await SandboxApi.recoverSandboxCreate(recovery, opts);
|
|
3905
|
+
const sandbox = new this(__spreadProps(__spreadValues(__spreadValues({}, config), sandboxInfo), {
|
|
3906
|
+
region: sandboxInfo.sandboxRegion
|
|
3907
|
+
}));
|
|
3908
|
+
if (opts == null ? void 0 : opts.mcp) {
|
|
3909
|
+
sandbox.mcpToken = crypto.randomUUID();
|
|
3910
|
+
const res = await sandbox.commands.run(
|
|
3911
|
+
`mcp-gateway --config '${JSON.stringify(opts.mcp)}'`,
|
|
3912
|
+
{
|
|
3913
|
+
user: "root",
|
|
3914
|
+
envs: {
|
|
3915
|
+
GATEWAY_ACCESS_TOKEN: sandbox.mcpToken
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3918
|
+
);
|
|
3919
|
+
if (res.exitCode !== 0) {
|
|
3920
|
+
throw new Error(`Failed to start MCP gateway: ${res.stderr}`);
|
|
3921
|
+
}
|
|
3922
|
+
}
|
|
3923
|
+
return sandbox;
|
|
3924
|
+
}
|
|
3744
3925
|
static async betaCreate(templateOrOpts, opts) {
|
|
3745
3926
|
var _a3, _b;
|
|
3746
3927
|
const { template, sandboxOpts } = typeof templateOrOpts === "string" ? {
|
|
@@ -3754,6 +3935,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3754
3935
|
if (config.debug) {
|
|
3755
3936
|
return new this(__spreadValues({
|
|
3756
3937
|
sandboxId: "debug_sandbox_id",
|
|
3938
|
+
buildId: "debug_build_id",
|
|
3757
3939
|
sandboxRegion: "debug",
|
|
3758
3940
|
capacityTier: "shared",
|
|
3759
3941
|
envdVersion: ENVD_DEBUG_FALLBACK
|
|
@@ -3764,7 +3946,9 @@ var Sandbox = class extends SandboxApi {
|
|
|
3764
3946
|
(_a3 = sandboxOpts == null ? void 0 : sandboxOpts.timeoutMs) != null ? _a3 : this.defaultSandboxTimeoutMs,
|
|
3765
3947
|
sandboxOpts
|
|
3766
3948
|
);
|
|
3767
|
-
const sandbox = new this(__spreadValues(__spreadValues({}, config), sandboxInfo)
|
|
3949
|
+
const sandbox = new this(__spreadProps(__spreadValues(__spreadValues({}, config), sandboxInfo), {
|
|
3950
|
+
region: sandboxInfo.sandboxRegion
|
|
3951
|
+
}));
|
|
3768
3952
|
if (sandboxOpts == null ? void 0 : sandboxOpts.mcp) {
|
|
3769
3953
|
sandbox.mcpToken = crypto.randomUUID();
|
|
3770
3954
|
const res = await sandbox.commands.run(
|
|
@@ -3786,9 +3970,11 @@ var Sandbox = class extends SandboxApi {
|
|
|
3786
3970
|
* Connect to a sandbox. If the sandbox is paused, it will be automatically resumed.
|
|
3787
3971
|
* Sandbox must be either running or be paused.
|
|
3788
3972
|
*
|
|
3789
|
-
*
|
|
3973
|
+
* Persist {@link Sandbox.ref} to reconnect through the sandbox's owning
|
|
3974
|
+
* regional API from another process or environment.
|
|
3790
3975
|
*
|
|
3791
|
-
* @param
|
|
3976
|
+
* @param target sandbox ID, or a serializable reference containing its ID
|
|
3977
|
+
* and owning region.
|
|
3792
3978
|
* @param opts connection options.
|
|
3793
3979
|
*
|
|
3794
3980
|
* @returns A running sandbox instance
|
|
@@ -3802,13 +3988,15 @@ var Sandbox = class extends SandboxApi {
|
|
|
3802
3988
|
* const sameSandbox = await Sandbox.connect(sandboxId)
|
|
3803
3989
|
* ```
|
|
3804
3990
|
*/
|
|
3805
|
-
static async connect(
|
|
3806
|
-
const sandbox = await SandboxApi.connectSandbox(
|
|
3807
|
-
const config = ConnectionConfig.forSandbox(opts);
|
|
3991
|
+
static async connect(target, opts) {
|
|
3992
|
+
const sandbox = await SandboxApi.connectSandbox(target, opts);
|
|
3993
|
+
const config = ConnectionConfig.forSandbox(__spreadValues(__spreadValues({}, opts), typeof target === "string" ? {} : { region: target.region }));
|
|
3808
3994
|
return new this(__spreadProps(__spreadValues({}, config), {
|
|
3809
|
-
sandboxId,
|
|
3995
|
+
sandboxId: sandbox.sandboxId,
|
|
3996
|
+
buildId: sandbox.buildId,
|
|
3810
3997
|
sandboxDomain: sandbox.sandboxDomain,
|
|
3811
3998
|
sandboxRegion: sandbox.sandboxRegion,
|
|
3999
|
+
region: sandbox.sandboxRegion,
|
|
3812
4000
|
capacityTier: sandbox.capacityTier,
|
|
3813
4001
|
apiUrl: sandbox.apiUrl,
|
|
3814
4002
|
envdAccessToken: sandbox.envdAccessToken,
|
|
@@ -3836,7 +4024,10 @@ var Sandbox = class extends SandboxApi {
|
|
|
3836
4024
|
* ```
|
|
3837
4025
|
*/
|
|
3838
4026
|
async connect(opts) {
|
|
3839
|
-
await SandboxApi.connectSandbox(
|
|
4027
|
+
await SandboxApi.connectSandbox(
|
|
4028
|
+
this.sandboxId,
|
|
4029
|
+
this.connectionOptions(opts)
|
|
4030
|
+
);
|
|
3840
4031
|
return this;
|
|
3841
4032
|
}
|
|
3842
4033
|
/**
|
|
@@ -3905,7 +4096,11 @@ var Sandbox = class extends SandboxApi {
|
|
|
3905
4096
|
if (this.connectionConfig.debug) {
|
|
3906
4097
|
return;
|
|
3907
4098
|
}
|
|
3908
|
-
await SandboxApi.setTimeout(
|
|
4099
|
+
await SandboxApi.setTimeout(
|
|
4100
|
+
this.sandboxId,
|
|
4101
|
+
timeoutMs,
|
|
4102
|
+
this.connectionOptions(opts)
|
|
4103
|
+
);
|
|
3909
4104
|
}
|
|
3910
4105
|
/**
|
|
3911
4106
|
* Kill the sandbox.
|
|
@@ -3916,7 +4111,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3916
4111
|
if (this.connectionConfig.debug) {
|
|
3917
4112
|
return;
|
|
3918
4113
|
}
|
|
3919
|
-
await SandboxApi.kill(this.sandboxId,
|
|
4114
|
+
await SandboxApi.kill(this.sandboxId, this.connectionOptions(opts));
|
|
3920
4115
|
}
|
|
3921
4116
|
/**
|
|
3922
4117
|
* Pause a sandbox by its ID.
|
|
@@ -3932,7 +4127,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3932
4127
|
* ```
|
|
3933
4128
|
*/
|
|
3934
4129
|
async pause(opts) {
|
|
3935
|
-
return await SandboxApi.pause(this.sandboxId,
|
|
4130
|
+
return await SandboxApi.pause(this.sandboxId, this.connectionOptions(opts));
|
|
3936
4131
|
}
|
|
3937
4132
|
/**
|
|
3938
4133
|
* Create a snapshot of the sandbox's current state.
|
|
@@ -3960,7 +4155,10 @@ var Sandbox = class extends SandboxApi {
|
|
|
3960
4155
|
* ```
|
|
3961
4156
|
*/
|
|
3962
4157
|
async createSnapshot(opts) {
|
|
3963
|
-
return await SandboxApi.createSnapshot(
|
|
4158
|
+
return await SandboxApi.createSnapshot(
|
|
4159
|
+
this.sandboxId,
|
|
4160
|
+
this.connectionOptions(opts)
|
|
4161
|
+
);
|
|
3964
4162
|
}
|
|
3965
4163
|
/**
|
|
3966
4164
|
* List all snapshots created from this sandbox.
|
|
@@ -3970,7 +4168,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3970
4168
|
* @returns paginator for listing snapshots from this sandbox.
|
|
3971
4169
|
*/
|
|
3972
4170
|
listSnapshots(opts) {
|
|
3973
|
-
return SandboxApi.listSnapshots(__spreadProps(__spreadValues(
|
|
4171
|
+
return SandboxApi.listSnapshots(__spreadProps(__spreadValues({}, this.connectionOptions(opts)), {
|
|
3974
4172
|
sandboxId: this.sandboxId
|
|
3975
4173
|
}));
|
|
3976
4174
|
}
|
|
@@ -4022,7 +4220,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
4022
4220
|
const filePath = path2 != null ? path2 : "";
|
|
4023
4221
|
const fileUrl = this.fileUrl(filePath, username);
|
|
4024
4222
|
if (useSignature) {
|
|
4025
|
-
const
|
|
4223
|
+
const url2 = new URL(fileUrl);
|
|
4026
4224
|
const sig = await getSignature({
|
|
4027
4225
|
path: filePath,
|
|
4028
4226
|
operation: "write",
|
|
@@ -4030,11 +4228,11 @@ var Sandbox = class extends SandboxApi {
|
|
|
4030
4228
|
expirationInSeconds: opts.useSignatureExpiration,
|
|
4031
4229
|
envdAccessToken: this.envdAccessToken
|
|
4032
4230
|
});
|
|
4033
|
-
|
|
4231
|
+
url2.searchParams.set("signature", sig.signature);
|
|
4034
4232
|
if (sig.expiration) {
|
|
4035
|
-
|
|
4233
|
+
url2.searchParams.set("signature_expiration", sig.expiration.toString());
|
|
4036
4234
|
}
|
|
4037
|
-
return
|
|
4235
|
+
return url2.toString();
|
|
4038
4236
|
}
|
|
4039
4237
|
return fileUrl;
|
|
4040
4238
|
}
|
|
@@ -4061,7 +4259,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
4061
4259
|
}
|
|
4062
4260
|
const fileUrl = this.fileUrl(path2, username);
|
|
4063
4261
|
if (useSignature) {
|
|
4064
|
-
const
|
|
4262
|
+
const url2 = new URL(fileUrl);
|
|
4065
4263
|
const sig = await getSignature({
|
|
4066
4264
|
path: path2,
|
|
4067
4265
|
operation: "read",
|
|
@@ -4069,11 +4267,11 @@ var Sandbox = class extends SandboxApi {
|
|
|
4069
4267
|
expirationInSeconds: opts.useSignatureExpiration,
|
|
4070
4268
|
envdAccessToken: this.envdAccessToken
|
|
4071
4269
|
});
|
|
4072
|
-
|
|
4270
|
+
url2.searchParams.set("signature", sig.signature);
|
|
4073
4271
|
if (sig.expiration) {
|
|
4074
|
-
|
|
4272
|
+
url2.searchParams.set("signature_expiration", sig.expiration.toString());
|
|
4075
4273
|
}
|
|
4076
|
-
return
|
|
4274
|
+
return url2.toString();
|
|
4077
4275
|
}
|
|
4078
4276
|
return fileUrl;
|
|
4079
4277
|
}
|
|
@@ -4085,7 +4283,10 @@ var Sandbox = class extends SandboxApi {
|
|
|
4085
4283
|
* @returns information about the sandbox
|
|
4086
4284
|
*/
|
|
4087
4285
|
async getInfo(opts) {
|
|
4088
|
-
return await SandboxApi.getInfo(
|
|
4286
|
+
return await SandboxApi.getInfo(
|
|
4287
|
+
this.sandboxId,
|
|
4288
|
+
this.connectionOptions(opts)
|
|
4289
|
+
);
|
|
4089
4290
|
}
|
|
4090
4291
|
/**
|
|
4091
4292
|
* Get the metrics of the sandbox.
|
|
@@ -4109,7 +4310,10 @@ var Sandbox = class extends SandboxApi {
|
|
|
4109
4310
|
);
|
|
4110
4311
|
}
|
|
4111
4312
|
}
|
|
4112
|
-
return await SandboxApi.getMetrics(
|
|
4313
|
+
return await SandboxApi.getMetrics(
|
|
4314
|
+
this.sandboxId,
|
|
4315
|
+
this.connectionOptions(opts)
|
|
4316
|
+
);
|
|
4113
4317
|
}
|
|
4114
4318
|
fileUrl(path2, username) {
|
|
4115
4319
|
const externalUrl = this.connectionConfig.getSandboxExternalUrl(
|
|
@@ -4120,19 +4324,105 @@ var Sandbox = class extends SandboxApi {
|
|
|
4120
4324
|
port: this.envdPort
|
|
4121
4325
|
}
|
|
4122
4326
|
);
|
|
4123
|
-
const
|
|
4327
|
+
const url2 = new URL("/files", externalUrl);
|
|
4124
4328
|
if (username) {
|
|
4125
|
-
|
|
4329
|
+
url2.searchParams.set("username", username);
|
|
4126
4330
|
}
|
|
4127
4331
|
if (path2) {
|
|
4128
|
-
|
|
4332
|
+
url2.searchParams.set("path", path2);
|
|
4129
4333
|
}
|
|
4130
|
-
return
|
|
4334
|
+
return url2.toString();
|
|
4131
4335
|
}
|
|
4132
4336
|
};
|
|
4133
4337
|
Sandbox.defaultTemplate = "base";
|
|
4134
4338
|
Sandbox.defaultMcpTemplate = "mcp-gateway";
|
|
4135
4339
|
Sandbox.defaultSandboxTimeoutMs = DEFAULT_SANDBOX_TIMEOUT_MS;
|
|
4340
|
+
var SandboxRegionScope = class {
|
|
4341
|
+
constructor(sandboxClass, region) {
|
|
4342
|
+
this.sandboxClass = sandboxClass;
|
|
4343
|
+
this.selectedRegion = ConnectionConfig.resolveRegion(region);
|
|
4344
|
+
}
|
|
4345
|
+
get region() {
|
|
4346
|
+
return this.selectedRegion;
|
|
4347
|
+
}
|
|
4348
|
+
options(opts) {
|
|
4349
|
+
const requestedRegion = opts == null ? void 0 : opts.region;
|
|
4350
|
+
if (requestedRegion && ConnectionConfig.resolveRegion(requestedRegion) !== this.region) {
|
|
4351
|
+
throw new Error(
|
|
4352
|
+
`Regional sandbox scope is pinned to "${this.region}", not "${requestedRegion}"`
|
|
4353
|
+
);
|
|
4354
|
+
}
|
|
4355
|
+
return __spreadProps(__spreadValues({}, opts), {
|
|
4356
|
+
region: this.region
|
|
4357
|
+
});
|
|
4358
|
+
}
|
|
4359
|
+
list(opts) {
|
|
4360
|
+
return this.sandboxClass.list(this.options(opts));
|
|
4361
|
+
}
|
|
4362
|
+
async create(templateOrOpts, opts) {
|
|
4363
|
+
if (typeof templateOrOpts === "string") {
|
|
4364
|
+
return this.sandboxClass.create(
|
|
4365
|
+
templateOrOpts,
|
|
4366
|
+
this.options(opts)
|
|
4367
|
+
);
|
|
4368
|
+
}
|
|
4369
|
+
return this.sandboxClass.create(this.options(templateOrOpts));
|
|
4370
|
+
}
|
|
4371
|
+
recoverCreate(recovery, opts) {
|
|
4372
|
+
if (recovery.region && ConnectionConfig.resolveRegion(recovery.region) !== this.region) {
|
|
4373
|
+
throw new Error(
|
|
4374
|
+
`Sandbox create recovery belongs to region "${recovery.region}", not "${this.region}"`
|
|
4375
|
+
);
|
|
4376
|
+
}
|
|
4377
|
+
return this.sandboxClass.recoverCreate(
|
|
4378
|
+
__spreadProps(__spreadValues({}, recovery), {
|
|
4379
|
+
region: this.region
|
|
4380
|
+
}),
|
|
4381
|
+
this.options(opts)
|
|
4382
|
+
);
|
|
4383
|
+
}
|
|
4384
|
+
async betaCreate(templateOrOpts, opts) {
|
|
4385
|
+
if (typeof templateOrOpts === "string") {
|
|
4386
|
+
return this.sandboxClass.betaCreate(
|
|
4387
|
+
templateOrOpts,
|
|
4388
|
+
this.options(opts)
|
|
4389
|
+
);
|
|
4390
|
+
}
|
|
4391
|
+
return this.sandboxClass.betaCreate(
|
|
4392
|
+
this.options(templateOrOpts)
|
|
4393
|
+
);
|
|
4394
|
+
}
|
|
4395
|
+
connect(target, opts) {
|
|
4396
|
+
return this.sandboxClass.connect(target, this.options(opts));
|
|
4397
|
+
}
|
|
4398
|
+
kill(target, opts) {
|
|
4399
|
+
return this.sandboxClass.kill(target, this.options(opts));
|
|
4400
|
+
}
|
|
4401
|
+
getInfo(target, opts) {
|
|
4402
|
+
return this.sandboxClass.getInfo(target, this.options(opts));
|
|
4403
|
+
}
|
|
4404
|
+
getFullInfo(target, opts) {
|
|
4405
|
+
return this.sandboxClass.getFullInfo(target, this.options(opts));
|
|
4406
|
+
}
|
|
4407
|
+
getMetrics(target, opts) {
|
|
4408
|
+
return this.sandboxClass.getMetrics(target, this.options(opts));
|
|
4409
|
+
}
|
|
4410
|
+
setTimeout(target, timeoutMs, opts) {
|
|
4411
|
+
return this.sandboxClass.setTimeout(target, timeoutMs, this.options(opts));
|
|
4412
|
+
}
|
|
4413
|
+
pause(target, opts) {
|
|
4414
|
+
return this.sandboxClass.pause(target, this.options(opts));
|
|
4415
|
+
}
|
|
4416
|
+
createSnapshot(target, opts) {
|
|
4417
|
+
return this.sandboxClass.createSnapshot(target, this.options(opts));
|
|
4418
|
+
}
|
|
4419
|
+
listSnapshots(opts) {
|
|
4420
|
+
return this.sandboxClass.listSnapshots(this.options(opts));
|
|
4421
|
+
}
|
|
4422
|
+
deleteSnapshot(snapshotId, opts) {
|
|
4423
|
+
return this.sandboxClass.deleteSnapshot(snapshotId, this.options(opts));
|
|
4424
|
+
}
|
|
4425
|
+
};
|
|
4136
4426
|
|
|
4137
4427
|
// src/template/logger.ts
|
|
4138
4428
|
import chalk from "chalk";
|
|
@@ -4256,7 +4546,7 @@ function defaultBuildLogger(options) {
|
|
|
4256
4546
|
import crypto2 from "crypto";
|
|
4257
4547
|
import fs from "fs";
|
|
4258
4548
|
import path from "path";
|
|
4259
|
-
import
|
|
4549
|
+
import url from "url";
|
|
4260
4550
|
|
|
4261
4551
|
// src/template/consts.ts
|
|
4262
4552
|
var FINALIZE_STEP_NAME = "finalize";
|
|
@@ -4404,7 +4694,7 @@ function getCallerDirectory(depth) {
|
|
|
4404
4694
|
return void 0;
|
|
4405
4695
|
}
|
|
4406
4696
|
if (fileName.startsWith("file:")) {
|
|
4407
|
-
fileName = fileURLToPath(fileName);
|
|
4697
|
+
fileName = url.fileURLToPath(fileName);
|
|
4408
4698
|
}
|
|
4409
4699
|
return path.dirname(fileName);
|
|
4410
4700
|
}
|
|
@@ -4495,7 +4785,7 @@ async function getFileUploadLink(client, { templateID, filesHash }, stackTrace)
|
|
|
4495
4785
|
return fileUploadLinkRes.data;
|
|
4496
4786
|
}
|
|
4497
4787
|
async function uploadFile(options, stackTrace) {
|
|
4498
|
-
const { fileName, url, fileContextPath, ignorePatterns, resolveSymlinks } = options;
|
|
4788
|
+
const { fileName, url: url2, fileContextPath, ignorePatterns, resolveSymlinks } = options;
|
|
4499
4789
|
try {
|
|
4500
4790
|
const uploadStream = await tarFileStreamUpload(
|
|
4501
4791
|
fileName,
|
|
@@ -4503,7 +4793,7 @@ async function uploadFile(options, stackTrace) {
|
|
|
4503
4793
|
ignorePatterns,
|
|
4504
4794
|
resolveSymlinks
|
|
4505
4795
|
);
|
|
4506
|
-
const res = await fetch(
|
|
4796
|
+
const res = await fetch(url2, {
|
|
4507
4797
|
method: "PUT",
|
|
4508
4798
|
// @ts-expect-error
|
|
4509
4799
|
body: uploadStream,
|
|
@@ -4723,8 +5013,8 @@ function waitForPort(port) {
|
|
|
4723
5013
|
const cmd = `ss -tuln | grep :${port}`;
|
|
4724
5014
|
return new ReadyCmd(cmd);
|
|
4725
5015
|
}
|
|
4726
|
-
function waitForURL(
|
|
4727
|
-
const cmd = `curl -s -o /dev/null -w "%{http_code}" ${
|
|
5016
|
+
function waitForURL(url2, statusCode = 200) {
|
|
5017
|
+
const cmd = `curl -s -o /dev/null -w "%{http_code}" ${url2} | grep -q "${statusCode}"`;
|
|
4728
5018
|
return new ReadyCmd(cmd);
|
|
4729
5019
|
}
|
|
4730
5020
|
function waitForProcess(processName) {
|
|
@@ -4929,6 +5219,7 @@ function handleCmdEntrypointInstruction(instruction, templateBuilder) {
|
|
|
4929
5219
|
// src/template/activationApi.ts
|
|
4930
5220
|
async function activateTemplate(build, options = {}) {
|
|
4931
5221
|
assertBuildIdentity(build);
|
|
5222
|
+
assertExpectedVersion(options.expectedVersion);
|
|
4932
5223
|
const region = resolveRegion(options.region);
|
|
4933
5224
|
const config = ConnectionConfig.forGlobal(options);
|
|
4934
5225
|
const client = new ApiClient(config);
|
|
@@ -4945,7 +5236,8 @@ async function activateTemplate(build, options = {}) {
|
|
|
4945
5236
|
buildID: build.buildId,
|
|
4946
5237
|
active: true,
|
|
4947
5238
|
requiredReadyNodes: options.requiredReadyNodes,
|
|
4948
|
-
allowRemoteFallback: options.allowRemoteFallback
|
|
5239
|
+
allowRemoteFallback: options.allowRemoteFallback,
|
|
5240
|
+
expectedVersion: options.expectedVersion
|
|
4949
5241
|
},
|
|
4950
5242
|
signal: config.getSignal(options.requestTimeoutMs)
|
|
4951
5243
|
}
|
|
@@ -4954,6 +5246,7 @@ async function activateTemplate(build, options = {}) {
|
|
|
4954
5246
|
}
|
|
4955
5247
|
async function deactivateTemplate(build, options = {}) {
|
|
4956
5248
|
assertBuildIdentity(build);
|
|
5249
|
+
assertExpectedVersion(options.expectedVersion);
|
|
4957
5250
|
const region = resolveRegion(options.region);
|
|
4958
5251
|
const config = ConnectionConfig.forGlobal(options);
|
|
4959
5252
|
const client = new ApiClient(config);
|
|
@@ -4968,7 +5261,8 @@ async function deactivateTemplate(build, options = {}) {
|
|
|
4968
5261
|
},
|
|
4969
5262
|
body: {
|
|
4970
5263
|
buildID: build.buildId,
|
|
4971
|
-
active: false
|
|
5264
|
+
active: false,
|
|
5265
|
+
expectedVersion: options.expectedVersion
|
|
4972
5266
|
},
|
|
4973
5267
|
signal: config.getSignal(options.requestTimeoutMs)
|
|
4974
5268
|
}
|
|
@@ -4979,6 +5273,9 @@ async function getTemplateActivation(templateId, options = {}) {
|
|
|
4979
5273
|
if (!templateId.trim()) {
|
|
4980
5274
|
throw new InvalidArgumentError("templateId is required");
|
|
4981
5275
|
}
|
|
5276
|
+
if (options.buildId !== void 0 && !options.buildId.trim()) {
|
|
5277
|
+
throw new InvalidArgumentError("buildId must not be empty");
|
|
5278
|
+
}
|
|
4982
5279
|
const region = resolveRegion(options.region);
|
|
4983
5280
|
const config = ConnectionConfig.forSandbox(__spreadProps(__spreadValues({}, options), { region }));
|
|
4984
5281
|
const client = new ApiClient(config);
|
|
@@ -4989,6 +5286,9 @@ async function getTemplateActivation(templateId, options = {}) {
|
|
|
4989
5286
|
path: {
|
|
4990
5287
|
templateID: templateId,
|
|
4991
5288
|
region
|
|
5289
|
+
},
|
|
5290
|
+
query: {
|
|
5291
|
+
buildID: options.buildId
|
|
4992
5292
|
}
|
|
4993
5293
|
},
|
|
4994
5294
|
signal: config.getSignal(options.requestTimeoutMs)
|
|
@@ -5004,6 +5304,100 @@ function assertBuildIdentity(build) {
|
|
|
5004
5304
|
function resolveRegion(region) {
|
|
5005
5305
|
return ConnectionConfig.resolveRegion(region);
|
|
5006
5306
|
}
|
|
5307
|
+
function assertExpectedVersion(expectedVersion) {
|
|
5308
|
+
if (expectedVersion !== void 0 && (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)) {
|
|
5309
|
+
throw new InvalidArgumentError(
|
|
5310
|
+
"expectedVersion must be a non-negative safe integer"
|
|
5311
|
+
);
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
|
|
5315
|
+
// src/template/tagHeadApi.ts
|
|
5316
|
+
async function getTemplateTagHead(client, templateId, tag, signal) {
|
|
5317
|
+
assertTemplateAndTag(templateId, tag);
|
|
5318
|
+
const response = await client.api.GET("/templates/{templateID}/tags/{tag}", {
|
|
5319
|
+
params: {
|
|
5320
|
+
path: {
|
|
5321
|
+
templateID: templateId,
|
|
5322
|
+
tag
|
|
5323
|
+
}
|
|
5324
|
+
},
|
|
5325
|
+
signal
|
|
5326
|
+
});
|
|
5327
|
+
const error = handleApiError(response, TemplateError);
|
|
5328
|
+
if (error) {
|
|
5329
|
+
throw error;
|
|
5330
|
+
}
|
|
5331
|
+
if (!response.data) {
|
|
5332
|
+
throw new TemplateError("Enclave API returned no template tag head");
|
|
5333
|
+
}
|
|
5334
|
+
return mapTagHead(response.data);
|
|
5335
|
+
}
|
|
5336
|
+
async function promoteTemplateTag(client, candidate, tag, expected, signal) {
|
|
5337
|
+
var _a3, _b, _c, _d, _e, _f;
|
|
5338
|
+
assertBuildIdentity2(candidate);
|
|
5339
|
+
assertTemplateAndTag(candidate.templateId, tag);
|
|
5340
|
+
assertExpectation(expected);
|
|
5341
|
+
const response = await client.api.PUT("/templates/{templateID}/tags/{tag}", {
|
|
5342
|
+
params: {
|
|
5343
|
+
path: {
|
|
5344
|
+
templateID: candidate.templateId,
|
|
5345
|
+
tag
|
|
5346
|
+
}
|
|
5347
|
+
},
|
|
5348
|
+
body: {
|
|
5349
|
+
buildID: candidate.buildId,
|
|
5350
|
+
expectedBuildID: expected == null ? void 0 : expected.buildId,
|
|
5351
|
+
expectedVersion: (_a3 = expected == null ? void 0 : expected.version) != null ? _a3 : 0
|
|
5352
|
+
},
|
|
5353
|
+
signal
|
|
5354
|
+
});
|
|
5355
|
+
if (response.response.status === 409 && (((_b = response.error) == null ? void 0 : _b.code) === "tag_changed" || ((_c = response.error) == null ? void 0 : _c.code) === "concurrent_mutation")) {
|
|
5356
|
+
const message = (_e = (_d = response.error) == null ? void 0 : _d.message) != null ? _e : "The template tag changed after it was read";
|
|
5357
|
+
throw new TemplateTagConflictError({
|
|
5358
|
+
templateId: candidate.templateId,
|
|
5359
|
+
tag,
|
|
5360
|
+
candidateBuildId: candidate.buildId,
|
|
5361
|
+
expectedBuildId: expected == null ? void 0 : expected.buildId,
|
|
5362
|
+
expectedVersion: (_f = expected == null ? void 0 : expected.version) != null ? _f : 0,
|
|
5363
|
+
reason: response.error.code,
|
|
5364
|
+
message: `409: ${message}. Fetch its current head with Template.getTagHead() before retrying.`
|
|
5365
|
+
});
|
|
5366
|
+
}
|
|
5367
|
+
const error = handleApiError(response, TemplateError);
|
|
5368
|
+
if (error) {
|
|
5369
|
+
throw error;
|
|
5370
|
+
}
|
|
5371
|
+
if (!response.data) {
|
|
5372
|
+
throw new TemplateError("Enclave API returned no promoted template tag");
|
|
5373
|
+
}
|
|
5374
|
+
return mapTagHead(response.data);
|
|
5375
|
+
}
|
|
5376
|
+
function mapTagHead(head) {
|
|
5377
|
+
return {
|
|
5378
|
+
tag: head.tag,
|
|
5379
|
+
buildId: head.buildID,
|
|
5380
|
+
version: head.version,
|
|
5381
|
+
createdAt: new Date(head.createdAt)
|
|
5382
|
+
};
|
|
5383
|
+
}
|
|
5384
|
+
function assertTemplateAndTag(templateId, tag) {
|
|
5385
|
+
if (!templateId.trim() || !tag.trim()) {
|
|
5386
|
+
throw new InvalidArgumentError("templateId and tag are required");
|
|
5387
|
+
}
|
|
5388
|
+
}
|
|
5389
|
+
function assertBuildIdentity2(candidate) {
|
|
5390
|
+
if (!candidate.templateId.trim() || !candidate.buildId.trim()) {
|
|
5391
|
+
throw new InvalidArgumentError("templateId and buildId are required");
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
function assertExpectation(expected) {
|
|
5395
|
+
if (expected !== null && (!expected.buildId.trim() || !Number.isSafeInteger(expected.version) || expected.version < 1)) {
|
|
5396
|
+
throw new InvalidArgumentError(
|
|
5397
|
+
"expected tag head must include a buildId and a positive safe-integer version"
|
|
5398
|
+
);
|
|
5399
|
+
}
|
|
5400
|
+
}
|
|
5007
5401
|
|
|
5008
5402
|
// src/template/index.ts
|
|
5009
5403
|
var _a2;
|
|
@@ -5255,6 +5649,42 @@ var TemplateBase = class {
|
|
|
5255
5649
|
const client = new ApiClient(config);
|
|
5256
5650
|
return getTemplateTags(client, { templateID: templateId });
|
|
5257
5651
|
}
|
|
5652
|
+
/**
|
|
5653
|
+
* Get the authoritative traffic-selection token for one template tag.
|
|
5654
|
+
*
|
|
5655
|
+
* Pass the returned head directly to {@link promoteTag}; its monotonic
|
|
5656
|
+
* version prevents concurrent releasers from silently overwriting each
|
|
5657
|
+
* other.
|
|
5658
|
+
*/
|
|
5659
|
+
static async getTagHead(templateId, tag, options) {
|
|
5660
|
+
const config = ConnectionConfig.forGlobal(options);
|
|
5661
|
+
const client = new ApiClient(config);
|
|
5662
|
+
return getTemplateTagHead(
|
|
5663
|
+
client,
|
|
5664
|
+
templateId,
|
|
5665
|
+
tag,
|
|
5666
|
+
config.getSignal(options == null ? void 0 : options.requestTimeoutMs)
|
|
5667
|
+
);
|
|
5668
|
+
}
|
|
5669
|
+
/**
|
|
5670
|
+
* Atomically move one template tag to an exact ready, durable build.
|
|
5671
|
+
*
|
|
5672
|
+
* Use a head returned by {@link getTagHead} as `expected`. Pass `null` only
|
|
5673
|
+
* when creating a tag that must not already exist. A concurrent change throws
|
|
5674
|
+
* `TemplateTagConflictError`; fetch the head again before deciding whether to
|
|
5675
|
+
* retry.
|
|
5676
|
+
*/
|
|
5677
|
+
static async promoteTag(candidate, tag, expected, options) {
|
|
5678
|
+
const config = ConnectionConfig.forGlobal(options);
|
|
5679
|
+
const client = new ApiClient(config);
|
|
5680
|
+
return promoteTemplateTag(
|
|
5681
|
+
client,
|
|
5682
|
+
candidate,
|
|
5683
|
+
tag,
|
|
5684
|
+
expected,
|
|
5685
|
+
config.getSignal(options == null ? void 0 : options.requestTimeoutMs)
|
|
5686
|
+
);
|
|
5687
|
+
}
|
|
5258
5688
|
fromDebianImage(variant = "stable") {
|
|
5259
5689
|
return this.fromImage(`debian:${variant}`);
|
|
5260
5690
|
}
|
|
@@ -5552,8 +5982,8 @@ var TemplateBase = class {
|
|
|
5552
5982
|
})
|
|
5553
5983
|
);
|
|
5554
5984
|
}
|
|
5555
|
-
gitClone(
|
|
5556
|
-
const args = ["git", "clone",
|
|
5985
|
+
gitClone(url2, path2, options) {
|
|
5986
|
+
const args = ["git", "clone", url2];
|
|
5557
5987
|
if (options == null ? void 0 : options.branch) {
|
|
5558
5988
|
args.push(`--branch ${options.branch}`);
|
|
5559
5989
|
args.push("--single-branch");
|
|
@@ -5805,7 +6235,7 @@ var TemplateBase = class {
|
|
|
5805
6235
|
if (index + 1 >= 0 && index + 1 < this.stackTraces.length) {
|
|
5806
6236
|
stackTrace = this.stackTraces[index + 1];
|
|
5807
6237
|
}
|
|
5808
|
-
const { present, url } = await getFileUploadLink(
|
|
6238
|
+
const { present, url: url2 } = await getFileUploadLink(
|
|
5809
6239
|
client,
|
|
5810
6240
|
{
|
|
5811
6241
|
templateID,
|
|
@@ -5813,12 +6243,12 @@ var TemplateBase = class {
|
|
|
5813
6243
|
},
|
|
5814
6244
|
stackTrace
|
|
5815
6245
|
);
|
|
5816
|
-
if (forceUpload &&
|
|
6246
|
+
if (forceUpload && url2 != null || present === false && url2 != null) {
|
|
5817
6247
|
await uploadFile(
|
|
5818
6248
|
{
|
|
5819
6249
|
fileName: src,
|
|
5820
6250
|
fileContextPath: this.fileContextPath.toString(),
|
|
5821
|
-
url,
|
|
6251
|
+
url: url2,
|
|
5822
6252
|
ignorePatterns: [
|
|
5823
6253
|
...this.fileIgnorePatterns,
|
|
5824
6254
|
...readDockerignore(this.fileContextPath.toString())
|
|
@@ -5939,6 +6369,8 @@ Template.exists = TemplateBase.exists;
|
|
|
5939
6369
|
Template.assignTags = TemplateBase.assignTags;
|
|
5940
6370
|
Template.removeTags = TemplateBase.removeTags;
|
|
5941
6371
|
Template.getTags = TemplateBase.getTags;
|
|
6372
|
+
Template.getTagHead = TemplateBase.getTagHead;
|
|
6373
|
+
Template.promoteTag = TemplateBase.promoteTag;
|
|
5942
6374
|
Template.toJSON = TemplateBase.toJSON;
|
|
5943
6375
|
Template.toDockerfile = TemplateBase.toDockerfile;
|
|
5944
6376
|
|
|
@@ -5972,9 +6404,11 @@ export {
|
|
|
5972
6404
|
Sandbox,
|
|
5973
6405
|
SandboxCreateRejectedError,
|
|
5974
6406
|
SandboxError,
|
|
6407
|
+
SandboxRegionScope,
|
|
5975
6408
|
Template,
|
|
5976
6409
|
TemplateBase,
|
|
5977
6410
|
TemplateError,
|
|
6411
|
+
TemplateTagConflictError,
|
|
5978
6412
|
TimeoutError,
|
|
5979
6413
|
src_default as default,
|
|
5980
6414
|
defaultBuildLogger,
|