@enclave-run/sdk 0.0.0-dev.4 → 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.js
CHANGED
|
@@ -103,9 +103,11 @@ __export(src_exports, {
|
|
|
103
103
|
Sandbox: () => Sandbox,
|
|
104
104
|
SandboxCreateRejectedError: () => SandboxCreateRejectedError,
|
|
105
105
|
SandboxError: () => SandboxError,
|
|
106
|
+
SandboxRegionScope: () => SandboxRegionScope,
|
|
106
107
|
Template: () => Template,
|
|
107
108
|
TemplateBase: () => TemplateBase,
|
|
108
109
|
TemplateError: () => TemplateError,
|
|
110
|
+
TemplateTagConflictError: () => TemplateTagConflictError,
|
|
109
111
|
TimeoutError: () => TimeoutError,
|
|
110
112
|
default: () => src_default,
|
|
111
113
|
defaultBuildLogger: () => defaultBuildLogger,
|
|
@@ -125,7 +127,7 @@ var import_openapi_fetch = __toESM(require("openapi-fetch"));
|
|
|
125
127
|
var import_platform2 = __toESM(require("platform"));
|
|
126
128
|
|
|
127
129
|
// package.json
|
|
128
|
-
var version = "0.0.0-dev.
|
|
130
|
+
var version = "0.0.0-dev.5";
|
|
129
131
|
|
|
130
132
|
// src/utils.ts
|
|
131
133
|
var import_platform = __toESM(require("platform"));
|
|
@@ -309,6 +311,21 @@ var TemplateError = class extends SandboxError {
|
|
|
309
311
|
this.name = "TemplateError";
|
|
310
312
|
}
|
|
311
313
|
};
|
|
314
|
+
var TemplateTagConflictError = class extends TemplateError {
|
|
315
|
+
constructor(options) {
|
|
316
|
+
var _a3;
|
|
317
|
+
super(
|
|
318
|
+
(_a3 = options.message) != null ? _a3 : `Template tag "${options.tag}" conflicted with another mutation. Fetch its current head with Template.getTagHead() before retrying.`
|
|
319
|
+
);
|
|
320
|
+
this.name = "TemplateTagConflictError";
|
|
321
|
+
this.templateId = options.templateId;
|
|
322
|
+
this.tag = options.tag;
|
|
323
|
+
this.candidateBuildId = options.candidateBuildId;
|
|
324
|
+
this.expectedBuildId = options.expectedBuildId;
|
|
325
|
+
this.expectedVersion = options.expectedVersion;
|
|
326
|
+
this.reason = options.reason;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
312
329
|
var RateLimitError = class extends SandboxError {
|
|
313
330
|
constructor(message) {
|
|
314
331
|
super(message);
|
|
@@ -1714,9 +1731,9 @@ var ALL_TRAFFIC = "0.0.0.0/0";
|
|
|
1714
1731
|
function shellEscape(value) {
|
|
1715
1732
|
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
1716
1733
|
}
|
|
1717
|
-
function withCredentials(
|
|
1734
|
+
function withCredentials(url2, username, password) {
|
|
1718
1735
|
if (!username && !password) {
|
|
1719
|
-
return
|
|
1736
|
+
return url2;
|
|
1720
1737
|
}
|
|
1721
1738
|
if (!username || !password) {
|
|
1722
1739
|
throw new InvalidArgumentError(
|
|
@@ -1725,9 +1742,9 @@ function withCredentials(url, username, password) {
|
|
|
1725
1742
|
}
|
|
1726
1743
|
let parsed;
|
|
1727
1744
|
try {
|
|
1728
|
-
parsed = new URL(
|
|
1745
|
+
parsed = new URL(url2);
|
|
1729
1746
|
} catch (e) {
|
|
1730
|
-
throw new InvalidArgumentError(`Invalid Git URL: ${
|
|
1747
|
+
throw new InvalidArgumentError(`Invalid Git URL: ${url2}`);
|
|
1731
1748
|
}
|
|
1732
1749
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
1733
1750
|
throw new InvalidArgumentError(
|
|
@@ -1738,27 +1755,27 @@ function withCredentials(url, username, password) {
|
|
|
1738
1755
|
parsed.password = password;
|
|
1739
1756
|
return parsed.toString();
|
|
1740
1757
|
}
|
|
1741
|
-
function stripCredentials(
|
|
1758
|
+
function stripCredentials(url2) {
|
|
1742
1759
|
let parsed;
|
|
1743
1760
|
try {
|
|
1744
|
-
parsed = new URL(
|
|
1761
|
+
parsed = new URL(url2);
|
|
1745
1762
|
} catch (e) {
|
|
1746
|
-
return
|
|
1763
|
+
return url2;
|
|
1747
1764
|
}
|
|
1748
1765
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
1749
|
-
return
|
|
1766
|
+
return url2;
|
|
1750
1767
|
}
|
|
1751
1768
|
if (!parsed.username && !parsed.password) {
|
|
1752
|
-
return
|
|
1769
|
+
return url2;
|
|
1753
1770
|
}
|
|
1754
1771
|
parsed.username = "";
|
|
1755
1772
|
parsed.password = "";
|
|
1756
1773
|
return parsed.toString();
|
|
1757
1774
|
}
|
|
1758
|
-
function deriveRepoDirFromUrl(
|
|
1775
|
+
function deriveRepoDirFromUrl(url2) {
|
|
1759
1776
|
let parsed;
|
|
1760
1777
|
try {
|
|
1761
|
-
parsed = new URL(
|
|
1778
|
+
parsed = new URL(url2);
|
|
1762
1779
|
} catch (e) {
|
|
1763
1780
|
return void 0;
|
|
1764
1781
|
}
|
|
@@ -2045,7 +2062,7 @@ var Git = class {
|
|
|
2045
2062
|
* @param opts Clone options.
|
|
2046
2063
|
* @returns Command result from the command runner.
|
|
2047
2064
|
*/
|
|
2048
|
-
async clone(
|
|
2065
|
+
async clone(url2, opts) {
|
|
2049
2066
|
const _a3 = opts != null ? opts : {}, {
|
|
2050
2067
|
username,
|
|
2051
2068
|
password,
|
|
@@ -2067,10 +2084,10 @@ var Git = class {
|
|
|
2067
2084
|
);
|
|
2068
2085
|
}
|
|
2069
2086
|
const attemptClone = async (authUsername, authPassword) => {
|
|
2070
|
-
const urlWithCreds = authUsername && authPassword ? withCredentials(
|
|
2087
|
+
const urlWithCreds = authUsername && authPassword ? withCredentials(url2, authUsername, authPassword) : url2;
|
|
2071
2088
|
const sanitizedUrl = stripCredentials(urlWithCreds);
|
|
2072
2089
|
const stripInlineCreds = !dangerouslyStoreCredentials && sanitizedUrl !== urlWithCreds;
|
|
2073
|
-
const repoPath = stripInlineCreds ? path2 != null ? path2 : deriveRepoDirFromUrl(
|
|
2090
|
+
const repoPath = stripInlineCreds ? path2 != null ? path2 : deriveRepoDirFromUrl(url2) : path2;
|
|
2074
2091
|
if (stripInlineCreds && !repoPath) {
|
|
2075
2092
|
throw new InvalidArgumentError(
|
|
2076
2093
|
"A destination path is required when using credentials without storing them."
|
|
@@ -2129,8 +2146,8 @@ var Git = class {
|
|
|
2129
2146
|
* @param opts Remote add options.
|
|
2130
2147
|
* @returns Command result from the command runner.
|
|
2131
2148
|
*/
|
|
2132
|
-
async remoteAdd(path2, name,
|
|
2133
|
-
if (!name || !
|
|
2149
|
+
async remoteAdd(path2, name, url2, opts) {
|
|
2150
|
+
if (!name || !url2) {
|
|
2134
2151
|
throw new InvalidArgumentError(
|
|
2135
2152
|
"Both remote name and URL are required to add a git remote."
|
|
2136
2153
|
);
|
|
@@ -2140,12 +2157,12 @@ var Git = class {
|
|
|
2140
2157
|
if (fetch2) {
|
|
2141
2158
|
addArgs.push("-f");
|
|
2142
2159
|
}
|
|
2143
|
-
addArgs.push(name,
|
|
2160
|
+
addArgs.push(name, url2);
|
|
2144
2161
|
if (!overwrite) {
|
|
2145
2162
|
return this.runGit(addArgs, path2, rest);
|
|
2146
2163
|
}
|
|
2147
2164
|
const addCmd = buildGitCommand(addArgs, path2);
|
|
2148
|
-
const setUrlCmd = buildGitCommand(["remote", "set-url", name,
|
|
2165
|
+
const setUrlCmd = buildGitCommand(["remote", "set-url", name, url2], path2);
|
|
2149
2166
|
let cmd = `${addCmd} || ${setUrlCmd}`;
|
|
2150
2167
|
if (fetch2) {
|
|
2151
2168
|
const fetchCmd = buildGitCommand(["fetch", name], path2);
|
|
@@ -2590,13 +2607,13 @@ var Git = class {
|
|
|
2590
2607
|
}
|
|
2591
2608
|
async getRemoteUrl(path2, remote, opts) {
|
|
2592
2609
|
const result = await this.runGit(["remote", "get-url", remote], path2, opts);
|
|
2593
|
-
const
|
|
2594
|
-
if (!
|
|
2610
|
+
const url2 = result.stdout.trim();
|
|
2611
|
+
if (!url2) {
|
|
2595
2612
|
throw new InvalidArgumentError(
|
|
2596
2613
|
`Remote "${remote}" URL not found in repository.`
|
|
2597
2614
|
);
|
|
2598
2615
|
}
|
|
2599
|
-
return
|
|
2616
|
+
return url2;
|
|
2600
2617
|
}
|
|
2601
2618
|
async resolveRemoteName(path2, remote, opts) {
|
|
2602
2619
|
if (remote) {
|
|
@@ -3121,6 +3138,26 @@ function getLifecycle(opts) {
|
|
|
3121
3138
|
var _a3;
|
|
3122
3139
|
return (_a3 = opts == null ? void 0 : opts.lifecycle) != null ? _a3 : { onTimeout: "kill", autoResume: false };
|
|
3123
3140
|
}
|
|
3141
|
+
function resolveSandboxTarget(target, opts) {
|
|
3142
|
+
if (typeof target === "string") {
|
|
3143
|
+
return {
|
|
3144
|
+
sandboxId: target,
|
|
3145
|
+
config: ConnectionConfig.forSandbox(opts)
|
|
3146
|
+
};
|
|
3147
|
+
}
|
|
3148
|
+
const referenceRegion = ConnectionConfig.resolveRegion(target.region);
|
|
3149
|
+
if ((opts == null ? void 0 : opts.region) && ConnectionConfig.resolveRegion(opts.region) !== referenceRegion) {
|
|
3150
|
+
throw new Error(
|
|
3151
|
+
`Sandbox ${target.sandboxId} belongs to region "${referenceRegion}", not "${opts.region}"`
|
|
3152
|
+
);
|
|
3153
|
+
}
|
|
3154
|
+
return {
|
|
3155
|
+
sandboxId: target.sandboxId,
|
|
3156
|
+
config: ConnectionConfig.forSandbox(__spreadProps(__spreadValues({}, opts), {
|
|
3157
|
+
region: referenceRegion
|
|
3158
|
+
}))
|
|
3159
|
+
};
|
|
3160
|
+
}
|
|
3124
3161
|
var SandboxApi = class {
|
|
3125
3162
|
constructor() {
|
|
3126
3163
|
}
|
|
@@ -3132,9 +3169,9 @@ var SandboxApi = class {
|
|
|
3132
3169
|
*
|
|
3133
3170
|
* @returns `true` if the sandbox was found and killed, `false` otherwise.
|
|
3134
3171
|
*/
|
|
3135
|
-
static async kill(
|
|
3172
|
+
static async kill(target, opts) {
|
|
3136
3173
|
var _a3;
|
|
3137
|
-
const config =
|
|
3174
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3138
3175
|
const client = new ApiClient(config);
|
|
3139
3176
|
const res = await client.api.DELETE("/sandboxes/{sandboxID}", {
|
|
3140
3177
|
params: {
|
|
@@ -3161,8 +3198,8 @@ var SandboxApi = class {
|
|
|
3161
3198
|
*
|
|
3162
3199
|
* @returns sandbox information.
|
|
3163
3200
|
*/
|
|
3164
|
-
static async getInfo(
|
|
3165
|
-
const fullInfo = await this.getFullInfo(
|
|
3201
|
+
static async getInfo(target, opts) {
|
|
3202
|
+
const fullInfo = await this.getFullInfo(target, opts);
|
|
3166
3203
|
delete fullInfo.envdAccessToken;
|
|
3167
3204
|
delete fullInfo.sandboxDomain;
|
|
3168
3205
|
return fullInfo;
|
|
@@ -3175,9 +3212,9 @@ var SandboxApi = class {
|
|
|
3175
3212
|
*
|
|
3176
3213
|
* @returns List of sandbox metrics containing CPU, memory and disk usage information.
|
|
3177
3214
|
*/
|
|
3178
|
-
static async getMetrics(
|
|
3215
|
+
static async getMetrics(target, opts) {
|
|
3179
3216
|
var _a3, _b;
|
|
3180
|
-
const config =
|
|
3217
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3181
3218
|
const client = new ApiClient(config);
|
|
3182
3219
|
const start = (opts == null ? void 0 : opts.start) ? opts.start.getTime() : void 0;
|
|
3183
3220
|
const end = (opts == null ? void 0 : opts.end) ? opts.end.getTime() : void 0;
|
|
@@ -3220,9 +3257,9 @@ var SandboxApi = class {
|
|
|
3220
3257
|
* @param timeoutMs timeout in **milliseconds**.
|
|
3221
3258
|
* @param opts connection options.
|
|
3222
3259
|
*/
|
|
3223
|
-
static async setTimeout(
|
|
3260
|
+
static async setTimeout(target, timeoutMs, opts) {
|
|
3224
3261
|
var _a3;
|
|
3225
|
-
const config =
|
|
3262
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3226
3263
|
const client = new ApiClient(config);
|
|
3227
3264
|
const res = await client.api.POST("/sandboxes/{sandboxID}/timeout", {
|
|
3228
3265
|
params: {
|
|
@@ -3243,9 +3280,9 @@ var SandboxApi = class {
|
|
|
3243
3280
|
throw err;
|
|
3244
3281
|
}
|
|
3245
3282
|
}
|
|
3246
|
-
static async getFullInfo(
|
|
3283
|
+
static async getFullInfo(target, opts) {
|
|
3247
3284
|
var _a3, _b;
|
|
3248
|
-
const config =
|
|
3285
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3249
3286
|
const client = new ApiClient(config);
|
|
3250
3287
|
const res = await client.api.GET("/sandboxes/{sandboxID}", {
|
|
3251
3288
|
params: {
|
|
@@ -3267,6 +3304,7 @@ var SandboxApi = class {
|
|
|
3267
3304
|
}
|
|
3268
3305
|
return __spreadProps(__spreadValues({
|
|
3269
3306
|
sandboxId: res.data.sandboxID,
|
|
3307
|
+
buildId: res.data.buildID,
|
|
3270
3308
|
templateId: res.data.templateID
|
|
3271
3309
|
}, res.data.alias && { name: res.data.alias }), {
|
|
3272
3310
|
metadata: (_b = res.data.metadata) != null ? _b : {},
|
|
@@ -3289,9 +3327,9 @@ var SandboxApi = class {
|
|
|
3289
3327
|
*
|
|
3290
3328
|
* @returns `true` if the sandbox got paused, `false` if the sandbox was already paused.
|
|
3291
3329
|
*/
|
|
3292
|
-
static async pause(
|
|
3330
|
+
static async pause(target, opts) {
|
|
3293
3331
|
var _a3, _b;
|
|
3294
|
-
const config =
|
|
3332
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3295
3333
|
const client = new ApiClient(config);
|
|
3296
3334
|
const res = await client.api.POST("/sandboxes/{sandboxID}/pause", {
|
|
3297
3335
|
params: {
|
|
@@ -3325,9 +3363,9 @@ var SandboxApi = class {
|
|
|
3325
3363
|
*
|
|
3326
3364
|
* @returns snapshot information including the snapshot name that can be used with Sandbox.create().
|
|
3327
3365
|
*/
|
|
3328
|
-
static async createSnapshot(
|
|
3366
|
+
static async createSnapshot(target, opts) {
|
|
3329
3367
|
var _a3;
|
|
3330
|
-
const config =
|
|
3368
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3331
3369
|
const client = new ApiClient(config);
|
|
3332
3370
|
const res = await client.api.POST("/sandboxes/{sandboxID}/snapshots", {
|
|
3333
3371
|
params: {
|
|
@@ -3446,14 +3484,51 @@ var SandboxApi = class {
|
|
|
3446
3484
|
}
|
|
3447
3485
|
sandbox = res.data;
|
|
3448
3486
|
}
|
|
3487
|
+
return this.sandboxInfoFromCreate(sandbox, config, opts);
|
|
3488
|
+
}
|
|
3489
|
+
static async recoverSandboxCreate(recovery, opts) {
|
|
3490
|
+
if (!recovery.idempotencyKey.trim()) {
|
|
3491
|
+
throw new InvalidArgumentError(
|
|
3492
|
+
"Sandbox create recovery requires an idempotency key"
|
|
3493
|
+
);
|
|
3494
|
+
}
|
|
3495
|
+
const recoveryRegion = recovery.region ? ConnectionConfig.resolveRegion(recovery.region) : void 0;
|
|
3496
|
+
if (recoveryRegion && (opts == null ? void 0 : opts.region) && ConnectionConfig.resolveRegion(opts.region) !== recoveryRegion) {
|
|
3497
|
+
throw new InvalidArgumentError(
|
|
3498
|
+
`Sandbox create recovery belongs to region "${recoveryRegion}", not "${opts.region}"`
|
|
3499
|
+
);
|
|
3500
|
+
}
|
|
3501
|
+
const config = ConnectionConfig.forSandbox(__spreadProps(__spreadValues({}, opts), {
|
|
3502
|
+
region: recoveryRegion != null ? recoveryRegion : opts == null ? void 0 : opts.region
|
|
3503
|
+
}));
|
|
3504
|
+
const signal = config.getSignal(opts == null ? void 0 : opts.requestTimeoutMs);
|
|
3505
|
+
const sandbox = await this.waitForSandboxCreate(
|
|
3506
|
+
new ApiClient(config),
|
|
3507
|
+
__spreadProps(__spreadValues({}, recovery), {
|
|
3508
|
+
region: config.region
|
|
3509
|
+
}),
|
|
3510
|
+
signal
|
|
3511
|
+
);
|
|
3512
|
+
return this.sandboxInfoFromCreate(sandbox, config, opts);
|
|
3513
|
+
}
|
|
3514
|
+
static async sandboxInfoFromCreate(sandbox, config, opts) {
|
|
3449
3515
|
if ((0, import_compare_versions4.compareVersions)(sandbox.envdVersion, "0.1.0") < 0) {
|
|
3450
|
-
await this.kill(
|
|
3516
|
+
await this.kill(
|
|
3517
|
+
{
|
|
3518
|
+
sandboxId: sandbox.sandboxID,
|
|
3519
|
+
region: sandbox.region
|
|
3520
|
+
},
|
|
3521
|
+
__spreadProps(__spreadValues({}, opts), {
|
|
3522
|
+
region: sandbox.region
|
|
3523
|
+
})
|
|
3524
|
+
);
|
|
3451
3525
|
throw new TemplateError(
|
|
3452
3526
|
"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."
|
|
3453
3527
|
);
|
|
3454
3528
|
}
|
|
3455
3529
|
return {
|
|
3456
3530
|
sandboxId: sandbox.sandboxID,
|
|
3531
|
+
buildId: sandbox.buildID,
|
|
3457
3532
|
sandboxDomain: sandbox.domain || void 0,
|
|
3458
3533
|
sandboxRegion: sandbox.region,
|
|
3459
3534
|
capacityTier: sandbox.capacityTier,
|
|
@@ -3467,7 +3542,13 @@ var SandboxApi = class {
|
|
|
3467
3542
|
};
|
|
3468
3543
|
}
|
|
3469
3544
|
static async waitForSandboxCreate(client, recovery, signal) {
|
|
3470
|
-
var _a3, _b;
|
|
3545
|
+
var _a3, _b, _c;
|
|
3546
|
+
let lastRecoveryError;
|
|
3547
|
+
let recoveryRetryDelayMs = 25;
|
|
3548
|
+
const waitToRetryRecovery = async () => {
|
|
3549
|
+
await new Promise((resolve) => setTimeout(resolve, recoveryRetryDelayMs));
|
|
3550
|
+
recoveryRetryDelayMs = Math.min(recoveryRetryDelayMs * 2, 1e3);
|
|
3551
|
+
};
|
|
3471
3552
|
while (!(signal == null ? void 0 : signal.aborted)) {
|
|
3472
3553
|
let res;
|
|
3473
3554
|
try {
|
|
@@ -3483,12 +3564,17 @@ var SandboxApi = class {
|
|
|
3483
3564
|
}
|
|
3484
3565
|
);
|
|
3485
3566
|
} catch (cause) {
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3567
|
+
lastRecoveryError = cause;
|
|
3568
|
+
await waitToRetryRecovery();
|
|
3569
|
+
continue;
|
|
3570
|
+
}
|
|
3571
|
+
const status = res.response.status;
|
|
3572
|
+
if (status === 404 || status === 408 || status === 425 || status >= 500) {
|
|
3573
|
+
lastRecoveryError = handleApiError(res);
|
|
3574
|
+
await waitToRetryRecovery();
|
|
3575
|
+
continue;
|
|
3491
3576
|
}
|
|
3577
|
+
recoveryRetryDelayMs = 25;
|
|
3492
3578
|
const err = handleApiError(res);
|
|
3493
3579
|
if (err) {
|
|
3494
3580
|
throw err;
|
|
@@ -3507,13 +3593,13 @@ var SandboxApi = class {
|
|
|
3507
3593
|
throw new OutcomeUnknownError(
|
|
3508
3594
|
"Sandbox admission committed, but waiting for its terminal result timed out.",
|
|
3509
3595
|
recovery,
|
|
3510
|
-
signal == null ? void 0 : signal.reason
|
|
3596
|
+
(_c = signal == null ? void 0 : signal.reason) != null ? _c : lastRecoveryError
|
|
3511
3597
|
);
|
|
3512
3598
|
}
|
|
3513
|
-
static async connectSandbox(
|
|
3599
|
+
static async connectSandbox(target, opts) {
|
|
3514
3600
|
var _a3, _b;
|
|
3515
3601
|
const timeoutMs = (_a3 = opts == null ? void 0 : opts.timeoutMs) != null ? _a3 : DEFAULT_SANDBOX_TIMEOUT_MS;
|
|
3516
|
-
const config =
|
|
3602
|
+
const { sandboxId, config } = resolveSandboxTarget(target, opts);
|
|
3517
3603
|
const client = new ApiClient(config);
|
|
3518
3604
|
const res = await client.api.POST("/sandboxes/{sandboxID}/connect", {
|
|
3519
3605
|
params: {
|
|
@@ -3535,6 +3621,7 @@ var SandboxApi = class {
|
|
|
3535
3621
|
}
|
|
3536
3622
|
return {
|
|
3537
3623
|
sandboxId: res.data.sandboxID,
|
|
3624
|
+
buildId: res.data.buildID,
|
|
3538
3625
|
sandboxDomain: res.data.domain || void 0,
|
|
3539
3626
|
sandboxRegion: res.data.region,
|
|
3540
3627
|
capacityTier: res.data.capacityTier,
|
|
@@ -3615,6 +3702,7 @@ var SandboxPaginator = class extends BasePaginator {
|
|
|
3615
3702
|
var _a4;
|
|
3616
3703
|
return __spreadProps(__spreadValues({
|
|
3617
3704
|
sandboxId: sandbox.sandboxID,
|
|
3705
|
+
buildId: sandbox.buildID,
|
|
3618
3706
|
templateId: sandbox.templateID
|
|
3619
3707
|
}, sandbox.alias && { name: sandbox.alias }), {
|
|
3620
3708
|
metadata: (_a4 = sandbox.metadata) != null ? _a4 : {},
|
|
@@ -3681,8 +3769,14 @@ var Sandbox = class extends SandboxApi {
|
|
|
3681
3769
|
this.mcpPort = 50005;
|
|
3682
3770
|
this.connectionConfig = ConnectionConfig.forSandbox(opts);
|
|
3683
3771
|
this.sandboxId = opts.sandboxId;
|
|
3772
|
+
this.buildId = opts.buildId;
|
|
3684
3773
|
this.sandboxDomain = (_a3 = opts.sandboxDomain) != null ? _a3 : this.connectionConfig.domain;
|
|
3685
|
-
this.sandboxRegion = opts.sandboxRegion;
|
|
3774
|
+
this.sandboxRegion = this.connectionConfig.debug ? opts.sandboxRegion : ConnectionConfig.resolveRegion(opts.sandboxRegion);
|
|
3775
|
+
if (!this.connectionConfig.debug && this.connectionConfig.region !== this.sandboxRegion) {
|
|
3776
|
+
throw new Error(
|
|
3777
|
+
`Sandbox ${opts.sandboxId} belongs to region "${this.sandboxRegion}", not "${this.connectionConfig.region}"`
|
|
3778
|
+
);
|
|
3779
|
+
}
|
|
3686
3780
|
this.capacityTier = opts.capacityTier;
|
|
3687
3781
|
this.envdAccessToken = opts.envdAccessToken;
|
|
3688
3782
|
this.trafficAccessToken = opts.trafficAccessToken;
|
|
@@ -3699,7 +3793,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3699
3793
|
baseUrl: this.envdApiUrl,
|
|
3700
3794
|
useBinaryFormat: false,
|
|
3701
3795
|
interceptors: (opts == null ? void 0 : opts.logger) ? [createRpcLogger(opts.logger)] : void 0,
|
|
3702
|
-
fetch: (
|
|
3796
|
+
fetch: (url2, options) => {
|
|
3703
3797
|
const headers = new Headers(this.connectionConfig.headers);
|
|
3704
3798
|
new Headers(options == null ? void 0 : options.headers).forEach(
|
|
3705
3799
|
(value, key) => headers.append(key, value)
|
|
@@ -3714,7 +3808,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3714
3808
|
headers,
|
|
3715
3809
|
redirect: "follow"
|
|
3716
3810
|
});
|
|
3717
|
-
return fetch(
|
|
3811
|
+
return fetch(url2, options);
|
|
3718
3812
|
}
|
|
3719
3813
|
});
|
|
3720
3814
|
this.envdApi = new EnvdApiClient(
|
|
@@ -3743,6 +3837,33 @@ var Sandbox = class extends SandboxApi {
|
|
|
3743
3837
|
});
|
|
3744
3838
|
this.git = new Git(this.commands);
|
|
3745
3839
|
}
|
|
3840
|
+
/**
|
|
3841
|
+
* Serializable regional reference for reconnecting to this sandbox.
|
|
3842
|
+
*/
|
|
3843
|
+
get ref() {
|
|
3844
|
+
if (this.connectionConfig.debug) {
|
|
3845
|
+
throw new Error("Sandbox references are unavailable in debug mode");
|
|
3846
|
+
}
|
|
3847
|
+
return {
|
|
3848
|
+
sandboxId: this.sandboxId,
|
|
3849
|
+
region: this.sandboxRegion
|
|
3850
|
+
};
|
|
3851
|
+
}
|
|
3852
|
+
connectionOptions(opts) {
|
|
3853
|
+
const ownerRegion = this.connectionConfig.debug ? this.connectionConfig.region : this.sandboxRegion;
|
|
3854
|
+
if (!this.connectionConfig.debug && (opts == null ? void 0 : opts.region) && ConnectionConfig.resolveRegion(opts.region) !== ownerRegion) {
|
|
3855
|
+
throw new Error(
|
|
3856
|
+
`Sandbox ${this.sandboxId} belongs to region "${ownerRegion}", not "${opts.region}"`
|
|
3857
|
+
);
|
|
3858
|
+
}
|
|
3859
|
+
return __spreadProps(__spreadValues(__spreadValues({}, this.connectionConfig), opts), {
|
|
3860
|
+
apiUrl: this.connectionConfig.apiUrl,
|
|
3861
|
+
sandboxUrl: this.connectionConfig.sandboxUrl,
|
|
3862
|
+
domain: this.connectionConfig.domain,
|
|
3863
|
+
debug: this.connectionConfig.debug,
|
|
3864
|
+
region: ownerRegion
|
|
3865
|
+
});
|
|
3866
|
+
}
|
|
3746
3867
|
/**
|
|
3747
3868
|
* List all sandboxes.
|
|
3748
3869
|
*
|
|
@@ -3753,6 +3874,20 @@ var Sandbox = class extends SandboxApi {
|
|
|
3753
3874
|
static list(opts) {
|
|
3754
3875
|
return new SandboxPaginator(opts);
|
|
3755
3876
|
}
|
|
3877
|
+
/**
|
|
3878
|
+
* Create an immutable regional scope so repeated sandbox operations do not
|
|
3879
|
+
* need to repeat the same region option.
|
|
3880
|
+
*
|
|
3881
|
+
* @example
|
|
3882
|
+
* ```ts
|
|
3883
|
+
* const yyz = Sandbox.inRegion("yyz")
|
|
3884
|
+
* const sandbox = await yyz.create()
|
|
3885
|
+
* const sameSandbox = await yyz.connect(sandbox.sandboxId)
|
|
3886
|
+
* ```
|
|
3887
|
+
*/
|
|
3888
|
+
static inRegion(region) {
|
|
3889
|
+
return new SandboxRegionScope(this, region);
|
|
3890
|
+
}
|
|
3756
3891
|
static async create(templateOrOpts, opts) {
|
|
3757
3892
|
var _a3, _b;
|
|
3758
3893
|
const { template, sandboxOpts } = typeof templateOrOpts === "string" ? {
|
|
@@ -3766,6 +3901,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3766
3901
|
if (config.debug) {
|
|
3767
3902
|
return new this(__spreadValues({
|
|
3768
3903
|
sandboxId: "debug_sandbox_id",
|
|
3904
|
+
buildId: "debug_build_id",
|
|
3769
3905
|
sandboxRegion: "debug",
|
|
3770
3906
|
capacityTier: "shared",
|
|
3771
3907
|
envdVersion: ENVD_DEBUG_FALLBACK
|
|
@@ -3776,7 +3912,9 @@ var Sandbox = class extends SandboxApi {
|
|
|
3776
3912
|
(_a3 = sandboxOpts == null ? void 0 : sandboxOpts.timeoutMs) != null ? _a3 : this.defaultSandboxTimeoutMs,
|
|
3777
3913
|
sandboxOpts
|
|
3778
3914
|
);
|
|
3779
|
-
const sandbox = new this(__spreadValues(__spreadValues({}, config), sandboxInfo)
|
|
3915
|
+
const sandbox = new this(__spreadProps(__spreadValues(__spreadValues({}, config), sandboxInfo), {
|
|
3916
|
+
region: sandboxInfo.sandboxRegion
|
|
3917
|
+
}));
|
|
3780
3918
|
if (sandboxOpts == null ? void 0 : sandboxOpts.mcp) {
|
|
3781
3919
|
sandbox.mcpToken = crypto.randomUUID();
|
|
3782
3920
|
const res = await sandbox.commands.run(
|
|
@@ -3794,6 +3932,51 @@ var Sandbox = class extends SandboxApi {
|
|
|
3794
3932
|
}
|
|
3795
3933
|
return sandbox;
|
|
3796
3934
|
}
|
|
3935
|
+
/**
|
|
3936
|
+
* Recover a create whose authoritative response was lost without resending
|
|
3937
|
+
* the original create payload.
|
|
3938
|
+
*
|
|
3939
|
+
* Pass `OutcomeUnknownError.recovery`. Recovery is pinned to the operation's
|
|
3940
|
+
* owning region and cannot create a second sandbox with different options.
|
|
3941
|
+
*
|
|
3942
|
+
* @example
|
|
3943
|
+
* ```ts
|
|
3944
|
+
* try {
|
|
3945
|
+
* return await Sandbox.create("base", { idempotencyKey: "job-123" })
|
|
3946
|
+
* } catch (error) {
|
|
3947
|
+
* if (error instanceof OutcomeUnknownError) {
|
|
3948
|
+
* return Sandbox.recoverCreate(error.recovery)
|
|
3949
|
+
* }
|
|
3950
|
+
* throw error
|
|
3951
|
+
* }
|
|
3952
|
+
* ```
|
|
3953
|
+
*/
|
|
3954
|
+
static async recoverCreate(recovery, opts) {
|
|
3955
|
+
var _a3;
|
|
3956
|
+
const config = ConnectionConfig.forSandbox(__spreadProps(__spreadValues({}, opts), {
|
|
3957
|
+
region: (_a3 = recovery.region) != null ? _a3 : opts == null ? void 0 : opts.region
|
|
3958
|
+
}));
|
|
3959
|
+
const sandboxInfo = await SandboxApi.recoverSandboxCreate(recovery, opts);
|
|
3960
|
+
const sandbox = new this(__spreadProps(__spreadValues(__spreadValues({}, config), sandboxInfo), {
|
|
3961
|
+
region: sandboxInfo.sandboxRegion
|
|
3962
|
+
}));
|
|
3963
|
+
if (opts == null ? void 0 : opts.mcp) {
|
|
3964
|
+
sandbox.mcpToken = crypto.randomUUID();
|
|
3965
|
+
const res = await sandbox.commands.run(
|
|
3966
|
+
`mcp-gateway --config '${JSON.stringify(opts.mcp)}'`,
|
|
3967
|
+
{
|
|
3968
|
+
user: "root",
|
|
3969
|
+
envs: {
|
|
3970
|
+
GATEWAY_ACCESS_TOKEN: sandbox.mcpToken
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
);
|
|
3974
|
+
if (res.exitCode !== 0) {
|
|
3975
|
+
throw new Error(`Failed to start MCP gateway: ${res.stderr}`);
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
return sandbox;
|
|
3979
|
+
}
|
|
3797
3980
|
static async betaCreate(templateOrOpts, opts) {
|
|
3798
3981
|
var _a3, _b;
|
|
3799
3982
|
const { template, sandboxOpts } = typeof templateOrOpts === "string" ? {
|
|
@@ -3807,6 +3990,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3807
3990
|
if (config.debug) {
|
|
3808
3991
|
return new this(__spreadValues({
|
|
3809
3992
|
sandboxId: "debug_sandbox_id",
|
|
3993
|
+
buildId: "debug_build_id",
|
|
3810
3994
|
sandboxRegion: "debug",
|
|
3811
3995
|
capacityTier: "shared",
|
|
3812
3996
|
envdVersion: ENVD_DEBUG_FALLBACK
|
|
@@ -3817,7 +4001,9 @@ var Sandbox = class extends SandboxApi {
|
|
|
3817
4001
|
(_a3 = sandboxOpts == null ? void 0 : sandboxOpts.timeoutMs) != null ? _a3 : this.defaultSandboxTimeoutMs,
|
|
3818
4002
|
sandboxOpts
|
|
3819
4003
|
);
|
|
3820
|
-
const sandbox = new this(__spreadValues(__spreadValues({}, config), sandboxInfo)
|
|
4004
|
+
const sandbox = new this(__spreadProps(__spreadValues(__spreadValues({}, config), sandboxInfo), {
|
|
4005
|
+
region: sandboxInfo.sandboxRegion
|
|
4006
|
+
}));
|
|
3821
4007
|
if (sandboxOpts == null ? void 0 : sandboxOpts.mcp) {
|
|
3822
4008
|
sandbox.mcpToken = crypto.randomUUID();
|
|
3823
4009
|
const res = await sandbox.commands.run(
|
|
@@ -3839,9 +4025,11 @@ var Sandbox = class extends SandboxApi {
|
|
|
3839
4025
|
* Connect to a sandbox. If the sandbox is paused, it will be automatically resumed.
|
|
3840
4026
|
* Sandbox must be either running or be paused.
|
|
3841
4027
|
*
|
|
3842
|
-
*
|
|
4028
|
+
* Persist {@link Sandbox.ref} to reconnect through the sandbox's owning
|
|
4029
|
+
* regional API from another process or environment.
|
|
3843
4030
|
*
|
|
3844
|
-
* @param
|
|
4031
|
+
* @param target sandbox ID, or a serializable reference containing its ID
|
|
4032
|
+
* and owning region.
|
|
3845
4033
|
* @param opts connection options.
|
|
3846
4034
|
*
|
|
3847
4035
|
* @returns A running sandbox instance
|
|
@@ -3855,13 +4043,15 @@ var Sandbox = class extends SandboxApi {
|
|
|
3855
4043
|
* const sameSandbox = await Sandbox.connect(sandboxId)
|
|
3856
4044
|
* ```
|
|
3857
4045
|
*/
|
|
3858
|
-
static async connect(
|
|
3859
|
-
const sandbox = await SandboxApi.connectSandbox(
|
|
3860
|
-
const config = ConnectionConfig.forSandbox(opts);
|
|
4046
|
+
static async connect(target, opts) {
|
|
4047
|
+
const sandbox = await SandboxApi.connectSandbox(target, opts);
|
|
4048
|
+
const config = ConnectionConfig.forSandbox(__spreadValues(__spreadValues({}, opts), typeof target === "string" ? {} : { region: target.region }));
|
|
3861
4049
|
return new this(__spreadProps(__spreadValues({}, config), {
|
|
3862
|
-
sandboxId,
|
|
4050
|
+
sandboxId: sandbox.sandboxId,
|
|
4051
|
+
buildId: sandbox.buildId,
|
|
3863
4052
|
sandboxDomain: sandbox.sandboxDomain,
|
|
3864
4053
|
sandboxRegion: sandbox.sandboxRegion,
|
|
4054
|
+
region: sandbox.sandboxRegion,
|
|
3865
4055
|
capacityTier: sandbox.capacityTier,
|
|
3866
4056
|
apiUrl: sandbox.apiUrl,
|
|
3867
4057
|
envdAccessToken: sandbox.envdAccessToken,
|
|
@@ -3889,7 +4079,10 @@ var Sandbox = class extends SandboxApi {
|
|
|
3889
4079
|
* ```
|
|
3890
4080
|
*/
|
|
3891
4081
|
async connect(opts) {
|
|
3892
|
-
await SandboxApi.connectSandbox(
|
|
4082
|
+
await SandboxApi.connectSandbox(
|
|
4083
|
+
this.sandboxId,
|
|
4084
|
+
this.connectionOptions(opts)
|
|
4085
|
+
);
|
|
3893
4086
|
return this;
|
|
3894
4087
|
}
|
|
3895
4088
|
/**
|
|
@@ -3958,7 +4151,11 @@ var Sandbox = class extends SandboxApi {
|
|
|
3958
4151
|
if (this.connectionConfig.debug) {
|
|
3959
4152
|
return;
|
|
3960
4153
|
}
|
|
3961
|
-
await SandboxApi.setTimeout(
|
|
4154
|
+
await SandboxApi.setTimeout(
|
|
4155
|
+
this.sandboxId,
|
|
4156
|
+
timeoutMs,
|
|
4157
|
+
this.connectionOptions(opts)
|
|
4158
|
+
);
|
|
3962
4159
|
}
|
|
3963
4160
|
/**
|
|
3964
4161
|
* Kill the sandbox.
|
|
@@ -3969,7 +4166,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3969
4166
|
if (this.connectionConfig.debug) {
|
|
3970
4167
|
return;
|
|
3971
4168
|
}
|
|
3972
|
-
await SandboxApi.kill(this.sandboxId,
|
|
4169
|
+
await SandboxApi.kill(this.sandboxId, this.connectionOptions(opts));
|
|
3973
4170
|
}
|
|
3974
4171
|
/**
|
|
3975
4172
|
* Pause a sandbox by its ID.
|
|
@@ -3985,7 +4182,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
3985
4182
|
* ```
|
|
3986
4183
|
*/
|
|
3987
4184
|
async pause(opts) {
|
|
3988
|
-
return await SandboxApi.pause(this.sandboxId,
|
|
4185
|
+
return await SandboxApi.pause(this.sandboxId, this.connectionOptions(opts));
|
|
3989
4186
|
}
|
|
3990
4187
|
/**
|
|
3991
4188
|
* Create a snapshot of the sandbox's current state.
|
|
@@ -4013,7 +4210,10 @@ var Sandbox = class extends SandboxApi {
|
|
|
4013
4210
|
* ```
|
|
4014
4211
|
*/
|
|
4015
4212
|
async createSnapshot(opts) {
|
|
4016
|
-
return await SandboxApi.createSnapshot(
|
|
4213
|
+
return await SandboxApi.createSnapshot(
|
|
4214
|
+
this.sandboxId,
|
|
4215
|
+
this.connectionOptions(opts)
|
|
4216
|
+
);
|
|
4017
4217
|
}
|
|
4018
4218
|
/**
|
|
4019
4219
|
* List all snapshots created from this sandbox.
|
|
@@ -4023,7 +4223,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
4023
4223
|
* @returns paginator for listing snapshots from this sandbox.
|
|
4024
4224
|
*/
|
|
4025
4225
|
listSnapshots(opts) {
|
|
4026
|
-
return SandboxApi.listSnapshots(__spreadProps(__spreadValues(
|
|
4226
|
+
return SandboxApi.listSnapshots(__spreadProps(__spreadValues({}, this.connectionOptions(opts)), {
|
|
4027
4227
|
sandboxId: this.sandboxId
|
|
4028
4228
|
}));
|
|
4029
4229
|
}
|
|
@@ -4075,7 +4275,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
4075
4275
|
const filePath = path2 != null ? path2 : "";
|
|
4076
4276
|
const fileUrl = this.fileUrl(filePath, username);
|
|
4077
4277
|
if (useSignature) {
|
|
4078
|
-
const
|
|
4278
|
+
const url2 = new URL(fileUrl);
|
|
4079
4279
|
const sig = await getSignature({
|
|
4080
4280
|
path: filePath,
|
|
4081
4281
|
operation: "write",
|
|
@@ -4083,11 +4283,11 @@ var Sandbox = class extends SandboxApi {
|
|
|
4083
4283
|
expirationInSeconds: opts.useSignatureExpiration,
|
|
4084
4284
|
envdAccessToken: this.envdAccessToken
|
|
4085
4285
|
});
|
|
4086
|
-
|
|
4286
|
+
url2.searchParams.set("signature", sig.signature);
|
|
4087
4287
|
if (sig.expiration) {
|
|
4088
|
-
|
|
4288
|
+
url2.searchParams.set("signature_expiration", sig.expiration.toString());
|
|
4089
4289
|
}
|
|
4090
|
-
return
|
|
4290
|
+
return url2.toString();
|
|
4091
4291
|
}
|
|
4092
4292
|
return fileUrl;
|
|
4093
4293
|
}
|
|
@@ -4114,7 +4314,7 @@ var Sandbox = class extends SandboxApi {
|
|
|
4114
4314
|
}
|
|
4115
4315
|
const fileUrl = this.fileUrl(path2, username);
|
|
4116
4316
|
if (useSignature) {
|
|
4117
|
-
const
|
|
4317
|
+
const url2 = new URL(fileUrl);
|
|
4118
4318
|
const sig = await getSignature({
|
|
4119
4319
|
path: path2,
|
|
4120
4320
|
operation: "read",
|
|
@@ -4122,11 +4322,11 @@ var Sandbox = class extends SandboxApi {
|
|
|
4122
4322
|
expirationInSeconds: opts.useSignatureExpiration,
|
|
4123
4323
|
envdAccessToken: this.envdAccessToken
|
|
4124
4324
|
});
|
|
4125
|
-
|
|
4325
|
+
url2.searchParams.set("signature", sig.signature);
|
|
4126
4326
|
if (sig.expiration) {
|
|
4127
|
-
|
|
4327
|
+
url2.searchParams.set("signature_expiration", sig.expiration.toString());
|
|
4128
4328
|
}
|
|
4129
|
-
return
|
|
4329
|
+
return url2.toString();
|
|
4130
4330
|
}
|
|
4131
4331
|
return fileUrl;
|
|
4132
4332
|
}
|
|
@@ -4138,7 +4338,10 @@ var Sandbox = class extends SandboxApi {
|
|
|
4138
4338
|
* @returns information about the sandbox
|
|
4139
4339
|
*/
|
|
4140
4340
|
async getInfo(opts) {
|
|
4141
|
-
return await SandboxApi.getInfo(
|
|
4341
|
+
return await SandboxApi.getInfo(
|
|
4342
|
+
this.sandboxId,
|
|
4343
|
+
this.connectionOptions(opts)
|
|
4344
|
+
);
|
|
4142
4345
|
}
|
|
4143
4346
|
/**
|
|
4144
4347
|
* Get the metrics of the sandbox.
|
|
@@ -4162,7 +4365,10 @@ var Sandbox = class extends SandboxApi {
|
|
|
4162
4365
|
);
|
|
4163
4366
|
}
|
|
4164
4367
|
}
|
|
4165
|
-
return await SandboxApi.getMetrics(
|
|
4368
|
+
return await SandboxApi.getMetrics(
|
|
4369
|
+
this.sandboxId,
|
|
4370
|
+
this.connectionOptions(opts)
|
|
4371
|
+
);
|
|
4166
4372
|
}
|
|
4167
4373
|
fileUrl(path2, username) {
|
|
4168
4374
|
const externalUrl = this.connectionConfig.getSandboxExternalUrl(
|
|
@@ -4173,19 +4379,105 @@ var Sandbox = class extends SandboxApi {
|
|
|
4173
4379
|
port: this.envdPort
|
|
4174
4380
|
}
|
|
4175
4381
|
);
|
|
4176
|
-
const
|
|
4382
|
+
const url2 = new URL("/files", externalUrl);
|
|
4177
4383
|
if (username) {
|
|
4178
|
-
|
|
4384
|
+
url2.searchParams.set("username", username);
|
|
4179
4385
|
}
|
|
4180
4386
|
if (path2) {
|
|
4181
|
-
|
|
4387
|
+
url2.searchParams.set("path", path2);
|
|
4182
4388
|
}
|
|
4183
|
-
return
|
|
4389
|
+
return url2.toString();
|
|
4184
4390
|
}
|
|
4185
4391
|
};
|
|
4186
4392
|
Sandbox.defaultTemplate = "base";
|
|
4187
4393
|
Sandbox.defaultMcpTemplate = "mcp-gateway";
|
|
4188
4394
|
Sandbox.defaultSandboxTimeoutMs = DEFAULT_SANDBOX_TIMEOUT_MS;
|
|
4395
|
+
var SandboxRegionScope = class {
|
|
4396
|
+
constructor(sandboxClass, region) {
|
|
4397
|
+
this.sandboxClass = sandboxClass;
|
|
4398
|
+
this.selectedRegion = ConnectionConfig.resolveRegion(region);
|
|
4399
|
+
}
|
|
4400
|
+
get region() {
|
|
4401
|
+
return this.selectedRegion;
|
|
4402
|
+
}
|
|
4403
|
+
options(opts) {
|
|
4404
|
+
const requestedRegion = opts == null ? void 0 : opts.region;
|
|
4405
|
+
if (requestedRegion && ConnectionConfig.resolveRegion(requestedRegion) !== this.region) {
|
|
4406
|
+
throw new Error(
|
|
4407
|
+
`Regional sandbox scope is pinned to "${this.region}", not "${requestedRegion}"`
|
|
4408
|
+
);
|
|
4409
|
+
}
|
|
4410
|
+
return __spreadProps(__spreadValues({}, opts), {
|
|
4411
|
+
region: this.region
|
|
4412
|
+
});
|
|
4413
|
+
}
|
|
4414
|
+
list(opts) {
|
|
4415
|
+
return this.sandboxClass.list(this.options(opts));
|
|
4416
|
+
}
|
|
4417
|
+
async create(templateOrOpts, opts) {
|
|
4418
|
+
if (typeof templateOrOpts === "string") {
|
|
4419
|
+
return this.sandboxClass.create(
|
|
4420
|
+
templateOrOpts,
|
|
4421
|
+
this.options(opts)
|
|
4422
|
+
);
|
|
4423
|
+
}
|
|
4424
|
+
return this.sandboxClass.create(this.options(templateOrOpts));
|
|
4425
|
+
}
|
|
4426
|
+
recoverCreate(recovery, opts) {
|
|
4427
|
+
if (recovery.region && ConnectionConfig.resolveRegion(recovery.region) !== this.region) {
|
|
4428
|
+
throw new Error(
|
|
4429
|
+
`Sandbox create recovery belongs to region "${recovery.region}", not "${this.region}"`
|
|
4430
|
+
);
|
|
4431
|
+
}
|
|
4432
|
+
return this.sandboxClass.recoverCreate(
|
|
4433
|
+
__spreadProps(__spreadValues({}, recovery), {
|
|
4434
|
+
region: this.region
|
|
4435
|
+
}),
|
|
4436
|
+
this.options(opts)
|
|
4437
|
+
);
|
|
4438
|
+
}
|
|
4439
|
+
async betaCreate(templateOrOpts, opts) {
|
|
4440
|
+
if (typeof templateOrOpts === "string") {
|
|
4441
|
+
return this.sandboxClass.betaCreate(
|
|
4442
|
+
templateOrOpts,
|
|
4443
|
+
this.options(opts)
|
|
4444
|
+
);
|
|
4445
|
+
}
|
|
4446
|
+
return this.sandboxClass.betaCreate(
|
|
4447
|
+
this.options(templateOrOpts)
|
|
4448
|
+
);
|
|
4449
|
+
}
|
|
4450
|
+
connect(target, opts) {
|
|
4451
|
+
return this.sandboxClass.connect(target, this.options(opts));
|
|
4452
|
+
}
|
|
4453
|
+
kill(target, opts) {
|
|
4454
|
+
return this.sandboxClass.kill(target, this.options(opts));
|
|
4455
|
+
}
|
|
4456
|
+
getInfo(target, opts) {
|
|
4457
|
+
return this.sandboxClass.getInfo(target, this.options(opts));
|
|
4458
|
+
}
|
|
4459
|
+
getFullInfo(target, opts) {
|
|
4460
|
+
return this.sandboxClass.getFullInfo(target, this.options(opts));
|
|
4461
|
+
}
|
|
4462
|
+
getMetrics(target, opts) {
|
|
4463
|
+
return this.sandboxClass.getMetrics(target, this.options(opts));
|
|
4464
|
+
}
|
|
4465
|
+
setTimeout(target, timeoutMs, opts) {
|
|
4466
|
+
return this.sandboxClass.setTimeout(target, timeoutMs, this.options(opts));
|
|
4467
|
+
}
|
|
4468
|
+
pause(target, opts) {
|
|
4469
|
+
return this.sandboxClass.pause(target, this.options(opts));
|
|
4470
|
+
}
|
|
4471
|
+
createSnapshot(target, opts) {
|
|
4472
|
+
return this.sandboxClass.createSnapshot(target, this.options(opts));
|
|
4473
|
+
}
|
|
4474
|
+
listSnapshots(opts) {
|
|
4475
|
+
return this.sandboxClass.listSnapshots(this.options(opts));
|
|
4476
|
+
}
|
|
4477
|
+
deleteSnapshot(snapshotId, opts) {
|
|
4478
|
+
return this.sandboxClass.deleteSnapshot(snapshotId, this.options(opts));
|
|
4479
|
+
}
|
|
4480
|
+
};
|
|
4189
4481
|
|
|
4190
4482
|
// src/template/logger.ts
|
|
4191
4483
|
var import_chalk = __toESM(require("chalk"));
|
|
@@ -4309,7 +4601,7 @@ function defaultBuildLogger(options) {
|
|
|
4309
4601
|
var import_node_crypto = __toESM(require("crypto"));
|
|
4310
4602
|
var import_node_fs = __toESM(require("fs"));
|
|
4311
4603
|
var import_node_path = __toESM(require("path"));
|
|
4312
|
-
var import_node_url = require("url");
|
|
4604
|
+
var import_node_url = __toESM(require("url"));
|
|
4313
4605
|
|
|
4314
4606
|
// src/template/consts.ts
|
|
4315
4607
|
var FINALIZE_STEP_NAME = "finalize";
|
|
@@ -4457,7 +4749,7 @@ function getCallerDirectory(depth) {
|
|
|
4457
4749
|
return void 0;
|
|
4458
4750
|
}
|
|
4459
4751
|
if (fileName.startsWith("file:")) {
|
|
4460
|
-
fileName =
|
|
4752
|
+
fileName = import_node_url.default.fileURLToPath(fileName);
|
|
4461
4753
|
}
|
|
4462
4754
|
return import_node_path.default.dirname(fileName);
|
|
4463
4755
|
}
|
|
@@ -4548,7 +4840,7 @@ async function getFileUploadLink(client, { templateID, filesHash }, stackTrace)
|
|
|
4548
4840
|
return fileUploadLinkRes.data;
|
|
4549
4841
|
}
|
|
4550
4842
|
async function uploadFile(options, stackTrace) {
|
|
4551
|
-
const { fileName, url, fileContextPath, ignorePatterns, resolveSymlinks } = options;
|
|
4843
|
+
const { fileName, url: url2, fileContextPath, ignorePatterns, resolveSymlinks } = options;
|
|
4552
4844
|
try {
|
|
4553
4845
|
const uploadStream = await tarFileStreamUpload(
|
|
4554
4846
|
fileName,
|
|
@@ -4556,7 +4848,7 @@ async function uploadFile(options, stackTrace) {
|
|
|
4556
4848
|
ignorePatterns,
|
|
4557
4849
|
resolveSymlinks
|
|
4558
4850
|
);
|
|
4559
|
-
const res = await fetch(
|
|
4851
|
+
const res = await fetch(url2, {
|
|
4560
4852
|
method: "PUT",
|
|
4561
4853
|
// @ts-expect-error
|
|
4562
4854
|
body: uploadStream,
|
|
@@ -4774,8 +5066,8 @@ function waitForPort(port) {
|
|
|
4774
5066
|
const cmd = `ss -tuln | grep :${port}`;
|
|
4775
5067
|
return new ReadyCmd(cmd);
|
|
4776
5068
|
}
|
|
4777
|
-
function waitForURL(
|
|
4778
|
-
const cmd = `curl -s -o /dev/null -w "%{http_code}" ${
|
|
5069
|
+
function waitForURL(url2, statusCode = 200) {
|
|
5070
|
+
const cmd = `curl -s -o /dev/null -w "%{http_code}" ${url2} | grep -q "${statusCode}"`;
|
|
4779
5071
|
return new ReadyCmd(cmd);
|
|
4780
5072
|
}
|
|
4781
5073
|
function waitForProcess(processName) {
|
|
@@ -4980,6 +5272,7 @@ function handleCmdEntrypointInstruction(instruction, templateBuilder) {
|
|
|
4980
5272
|
// src/template/activationApi.ts
|
|
4981
5273
|
async function activateTemplate(build, options = {}) {
|
|
4982
5274
|
assertBuildIdentity(build);
|
|
5275
|
+
assertExpectedVersion(options.expectedVersion);
|
|
4983
5276
|
const region = resolveRegion(options.region);
|
|
4984
5277
|
const config = ConnectionConfig.forGlobal(options);
|
|
4985
5278
|
const client = new ApiClient(config);
|
|
@@ -4996,7 +5289,8 @@ async function activateTemplate(build, options = {}) {
|
|
|
4996
5289
|
buildID: build.buildId,
|
|
4997
5290
|
active: true,
|
|
4998
5291
|
requiredReadyNodes: options.requiredReadyNodes,
|
|
4999
|
-
allowRemoteFallback: options.allowRemoteFallback
|
|
5292
|
+
allowRemoteFallback: options.allowRemoteFallback,
|
|
5293
|
+
expectedVersion: options.expectedVersion
|
|
5000
5294
|
},
|
|
5001
5295
|
signal: config.getSignal(options.requestTimeoutMs)
|
|
5002
5296
|
}
|
|
@@ -5005,6 +5299,7 @@ async function activateTemplate(build, options = {}) {
|
|
|
5005
5299
|
}
|
|
5006
5300
|
async function deactivateTemplate(build, options = {}) {
|
|
5007
5301
|
assertBuildIdentity(build);
|
|
5302
|
+
assertExpectedVersion(options.expectedVersion);
|
|
5008
5303
|
const region = resolveRegion(options.region);
|
|
5009
5304
|
const config = ConnectionConfig.forGlobal(options);
|
|
5010
5305
|
const client = new ApiClient(config);
|
|
@@ -5019,7 +5314,8 @@ async function deactivateTemplate(build, options = {}) {
|
|
|
5019
5314
|
},
|
|
5020
5315
|
body: {
|
|
5021
5316
|
buildID: build.buildId,
|
|
5022
|
-
active: false
|
|
5317
|
+
active: false,
|
|
5318
|
+
expectedVersion: options.expectedVersion
|
|
5023
5319
|
},
|
|
5024
5320
|
signal: config.getSignal(options.requestTimeoutMs)
|
|
5025
5321
|
}
|
|
@@ -5030,6 +5326,9 @@ async function getTemplateActivation(templateId, options = {}) {
|
|
|
5030
5326
|
if (!templateId.trim()) {
|
|
5031
5327
|
throw new InvalidArgumentError("templateId is required");
|
|
5032
5328
|
}
|
|
5329
|
+
if (options.buildId !== void 0 && !options.buildId.trim()) {
|
|
5330
|
+
throw new InvalidArgumentError("buildId must not be empty");
|
|
5331
|
+
}
|
|
5033
5332
|
const region = resolveRegion(options.region);
|
|
5034
5333
|
const config = ConnectionConfig.forSandbox(__spreadProps(__spreadValues({}, options), { region }));
|
|
5035
5334
|
const client = new ApiClient(config);
|
|
@@ -5040,6 +5339,9 @@ async function getTemplateActivation(templateId, options = {}) {
|
|
|
5040
5339
|
path: {
|
|
5041
5340
|
templateID: templateId,
|
|
5042
5341
|
region
|
|
5342
|
+
},
|
|
5343
|
+
query: {
|
|
5344
|
+
buildID: options.buildId
|
|
5043
5345
|
}
|
|
5044
5346
|
},
|
|
5045
5347
|
signal: config.getSignal(options.requestTimeoutMs)
|
|
@@ -5055,6 +5357,100 @@ function assertBuildIdentity(build) {
|
|
|
5055
5357
|
function resolveRegion(region) {
|
|
5056
5358
|
return ConnectionConfig.resolveRegion(region);
|
|
5057
5359
|
}
|
|
5360
|
+
function assertExpectedVersion(expectedVersion) {
|
|
5361
|
+
if (expectedVersion !== void 0 && (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)) {
|
|
5362
|
+
throw new InvalidArgumentError(
|
|
5363
|
+
"expectedVersion must be a non-negative safe integer"
|
|
5364
|
+
);
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
|
|
5368
|
+
// src/template/tagHeadApi.ts
|
|
5369
|
+
async function getTemplateTagHead(client, templateId, tag, signal) {
|
|
5370
|
+
assertTemplateAndTag(templateId, tag);
|
|
5371
|
+
const response = await client.api.GET("/templates/{templateID}/tags/{tag}", {
|
|
5372
|
+
params: {
|
|
5373
|
+
path: {
|
|
5374
|
+
templateID: templateId,
|
|
5375
|
+
tag
|
|
5376
|
+
}
|
|
5377
|
+
},
|
|
5378
|
+
signal
|
|
5379
|
+
});
|
|
5380
|
+
const error = handleApiError(response, TemplateError);
|
|
5381
|
+
if (error) {
|
|
5382
|
+
throw error;
|
|
5383
|
+
}
|
|
5384
|
+
if (!response.data) {
|
|
5385
|
+
throw new TemplateError("Enclave API returned no template tag head");
|
|
5386
|
+
}
|
|
5387
|
+
return mapTagHead(response.data);
|
|
5388
|
+
}
|
|
5389
|
+
async function promoteTemplateTag(client, candidate, tag, expected, signal) {
|
|
5390
|
+
var _a3, _b, _c, _d, _e, _f;
|
|
5391
|
+
assertBuildIdentity2(candidate);
|
|
5392
|
+
assertTemplateAndTag(candidate.templateId, tag);
|
|
5393
|
+
assertExpectation(expected);
|
|
5394
|
+
const response = await client.api.PUT("/templates/{templateID}/tags/{tag}", {
|
|
5395
|
+
params: {
|
|
5396
|
+
path: {
|
|
5397
|
+
templateID: candidate.templateId,
|
|
5398
|
+
tag
|
|
5399
|
+
}
|
|
5400
|
+
},
|
|
5401
|
+
body: {
|
|
5402
|
+
buildID: candidate.buildId,
|
|
5403
|
+
expectedBuildID: expected == null ? void 0 : expected.buildId,
|
|
5404
|
+
expectedVersion: (_a3 = expected == null ? void 0 : expected.version) != null ? _a3 : 0
|
|
5405
|
+
},
|
|
5406
|
+
signal
|
|
5407
|
+
});
|
|
5408
|
+
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")) {
|
|
5409
|
+
const message = (_e = (_d = response.error) == null ? void 0 : _d.message) != null ? _e : "The template tag changed after it was read";
|
|
5410
|
+
throw new TemplateTagConflictError({
|
|
5411
|
+
templateId: candidate.templateId,
|
|
5412
|
+
tag,
|
|
5413
|
+
candidateBuildId: candidate.buildId,
|
|
5414
|
+
expectedBuildId: expected == null ? void 0 : expected.buildId,
|
|
5415
|
+
expectedVersion: (_f = expected == null ? void 0 : expected.version) != null ? _f : 0,
|
|
5416
|
+
reason: response.error.code,
|
|
5417
|
+
message: `409: ${message}. Fetch its current head with Template.getTagHead() before retrying.`
|
|
5418
|
+
});
|
|
5419
|
+
}
|
|
5420
|
+
const error = handleApiError(response, TemplateError);
|
|
5421
|
+
if (error) {
|
|
5422
|
+
throw error;
|
|
5423
|
+
}
|
|
5424
|
+
if (!response.data) {
|
|
5425
|
+
throw new TemplateError("Enclave API returned no promoted template tag");
|
|
5426
|
+
}
|
|
5427
|
+
return mapTagHead(response.data);
|
|
5428
|
+
}
|
|
5429
|
+
function mapTagHead(head) {
|
|
5430
|
+
return {
|
|
5431
|
+
tag: head.tag,
|
|
5432
|
+
buildId: head.buildID,
|
|
5433
|
+
version: head.version,
|
|
5434
|
+
createdAt: new Date(head.createdAt)
|
|
5435
|
+
};
|
|
5436
|
+
}
|
|
5437
|
+
function assertTemplateAndTag(templateId, tag) {
|
|
5438
|
+
if (!templateId.trim() || !tag.trim()) {
|
|
5439
|
+
throw new InvalidArgumentError("templateId and tag are required");
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
5442
|
+
function assertBuildIdentity2(candidate) {
|
|
5443
|
+
if (!candidate.templateId.trim() || !candidate.buildId.trim()) {
|
|
5444
|
+
throw new InvalidArgumentError("templateId and buildId are required");
|
|
5445
|
+
}
|
|
5446
|
+
}
|
|
5447
|
+
function assertExpectation(expected) {
|
|
5448
|
+
if (expected !== null && (!expected.buildId.trim() || !Number.isSafeInteger(expected.version) || expected.version < 1)) {
|
|
5449
|
+
throw new InvalidArgumentError(
|
|
5450
|
+
"expected tag head must include a buildId and a positive safe-integer version"
|
|
5451
|
+
);
|
|
5452
|
+
}
|
|
5453
|
+
}
|
|
5058
5454
|
|
|
5059
5455
|
// src/template/index.ts
|
|
5060
5456
|
var _a2;
|
|
@@ -5306,6 +5702,42 @@ var TemplateBase = class {
|
|
|
5306
5702
|
const client = new ApiClient(config);
|
|
5307
5703
|
return getTemplateTags(client, { templateID: templateId });
|
|
5308
5704
|
}
|
|
5705
|
+
/**
|
|
5706
|
+
* Get the authoritative traffic-selection token for one template tag.
|
|
5707
|
+
*
|
|
5708
|
+
* Pass the returned head directly to {@link promoteTag}; its monotonic
|
|
5709
|
+
* version prevents concurrent releasers from silently overwriting each
|
|
5710
|
+
* other.
|
|
5711
|
+
*/
|
|
5712
|
+
static async getTagHead(templateId, tag, options) {
|
|
5713
|
+
const config = ConnectionConfig.forGlobal(options);
|
|
5714
|
+
const client = new ApiClient(config);
|
|
5715
|
+
return getTemplateTagHead(
|
|
5716
|
+
client,
|
|
5717
|
+
templateId,
|
|
5718
|
+
tag,
|
|
5719
|
+
config.getSignal(options == null ? void 0 : options.requestTimeoutMs)
|
|
5720
|
+
);
|
|
5721
|
+
}
|
|
5722
|
+
/**
|
|
5723
|
+
* Atomically move one template tag to an exact ready, durable build.
|
|
5724
|
+
*
|
|
5725
|
+
* Use a head returned by {@link getTagHead} as `expected`. Pass `null` only
|
|
5726
|
+
* when creating a tag that must not already exist. A concurrent change throws
|
|
5727
|
+
* `TemplateTagConflictError`; fetch the head again before deciding whether to
|
|
5728
|
+
* retry.
|
|
5729
|
+
*/
|
|
5730
|
+
static async promoteTag(candidate, tag, expected, options) {
|
|
5731
|
+
const config = ConnectionConfig.forGlobal(options);
|
|
5732
|
+
const client = new ApiClient(config);
|
|
5733
|
+
return promoteTemplateTag(
|
|
5734
|
+
client,
|
|
5735
|
+
candidate,
|
|
5736
|
+
tag,
|
|
5737
|
+
expected,
|
|
5738
|
+
config.getSignal(options == null ? void 0 : options.requestTimeoutMs)
|
|
5739
|
+
);
|
|
5740
|
+
}
|
|
5309
5741
|
fromDebianImage(variant = "stable") {
|
|
5310
5742
|
return this.fromImage(`debian:${variant}`);
|
|
5311
5743
|
}
|
|
@@ -5603,8 +6035,8 @@ var TemplateBase = class {
|
|
|
5603
6035
|
})
|
|
5604
6036
|
);
|
|
5605
6037
|
}
|
|
5606
|
-
gitClone(
|
|
5607
|
-
const args = ["git", "clone",
|
|
6038
|
+
gitClone(url2, path2, options) {
|
|
6039
|
+
const args = ["git", "clone", url2];
|
|
5608
6040
|
if (options == null ? void 0 : options.branch) {
|
|
5609
6041
|
args.push(`--branch ${options.branch}`);
|
|
5610
6042
|
args.push("--single-branch");
|
|
@@ -5856,7 +6288,7 @@ var TemplateBase = class {
|
|
|
5856
6288
|
if (index + 1 >= 0 && index + 1 < this.stackTraces.length) {
|
|
5857
6289
|
stackTrace = this.stackTraces[index + 1];
|
|
5858
6290
|
}
|
|
5859
|
-
const { present, url } = await getFileUploadLink(
|
|
6291
|
+
const { present, url: url2 } = await getFileUploadLink(
|
|
5860
6292
|
client,
|
|
5861
6293
|
{
|
|
5862
6294
|
templateID,
|
|
@@ -5864,12 +6296,12 @@ var TemplateBase = class {
|
|
|
5864
6296
|
},
|
|
5865
6297
|
stackTrace
|
|
5866
6298
|
);
|
|
5867
|
-
if (forceUpload &&
|
|
6299
|
+
if (forceUpload && url2 != null || present === false && url2 != null) {
|
|
5868
6300
|
await uploadFile(
|
|
5869
6301
|
{
|
|
5870
6302
|
fileName: src,
|
|
5871
6303
|
fileContextPath: this.fileContextPath.toString(),
|
|
5872
|
-
url,
|
|
6304
|
+
url: url2,
|
|
5873
6305
|
ignorePatterns: [
|
|
5874
6306
|
...this.fileIgnorePatterns,
|
|
5875
6307
|
...readDockerignore(this.fileContextPath.toString())
|
|
@@ -5990,6 +6422,8 @@ Template.exists = TemplateBase.exists;
|
|
|
5990
6422
|
Template.assignTags = TemplateBase.assignTags;
|
|
5991
6423
|
Template.removeTags = TemplateBase.removeTags;
|
|
5992
6424
|
Template.getTags = TemplateBase.getTags;
|
|
6425
|
+
Template.getTagHead = TemplateBase.getTagHead;
|
|
6426
|
+
Template.promoteTag = TemplateBase.promoteTag;
|
|
5993
6427
|
Template.toJSON = TemplateBase.toJSON;
|
|
5994
6428
|
Template.toDockerfile = TemplateBase.toDockerfile;
|
|
5995
6429
|
|
|
@@ -6024,9 +6458,11 @@ var src_default = Sandbox;
|
|
|
6024
6458
|
Sandbox,
|
|
6025
6459
|
SandboxCreateRejectedError,
|
|
6026
6460
|
SandboxError,
|
|
6461
|
+
SandboxRegionScope,
|
|
6027
6462
|
Template,
|
|
6028
6463
|
TemplateBase,
|
|
6029
6464
|
TemplateError,
|
|
6465
|
+
TemplateTagConflictError,
|
|
6030
6466
|
TimeoutError,
|
|
6031
6467
|
defaultBuildLogger,
|
|
6032
6468
|
getSignature,
|