sandbox 3.0.0-beta.21 → 3.0.0-beta.23
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.
|
@@ -15,10 +15,11 @@ import childProcess, { execFile } from "node:child_process";
|
|
|
15
15
|
import fs, { constants, writeFile } from "node:fs/promises";
|
|
16
16
|
import fs$1, { createWriteStream } from "node:fs";
|
|
17
17
|
import * as Auth from "@vercel/sandbox/dist/auth/index.js";
|
|
18
|
-
import { OAuth, getAuth, inferScope, pollForToken, updateAuthConfig } from "@vercel/sandbox/dist/auth/index.js";
|
|
18
|
+
import { NotOk, OAuth, getAuth, inferScope, pollForToken, updateAuthConfig } from "@vercel/sandbox/dist/auth/index.js";
|
|
19
19
|
import { EOL } from "os";
|
|
20
20
|
import { z } from "zod/v4";
|
|
21
21
|
import { z as z$1 } from "zod";
|
|
22
|
+
import retry from "async-retry";
|
|
22
23
|
import { APIError, Sandbox, Snapshot } from "@vercel/sandbox";
|
|
23
24
|
import readline from "node:readline";
|
|
24
25
|
import { randomUUID } from "crypto";
|
|
@@ -1997,7 +1998,7 @@ var require_parser$1 = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/
|
|
|
1997
1998
|
};
|
|
1998
1999
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1999
2000
|
exports.parse = parse$5;
|
|
2000
|
-
const debug$
|
|
2001
|
+
const debug$7 = (0, __importDefault$1(__require$1("debug")).default)("cmd-ts:parser");
|
|
2001
2002
|
/**
|
|
2002
2003
|
* Create an AST from a token list
|
|
2003
2004
|
*
|
|
@@ -2005,14 +2006,14 @@ var require_parser$1 = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/
|
|
|
2005
2006
|
* @param forceFlag Keys to force as flag. {@see ForceFlag} to read more about it.
|
|
2006
2007
|
*/
|
|
2007
2008
|
function parse$5(tokens, forceFlag) {
|
|
2008
|
-
if (debug$
|
|
2009
|
+
if (debug$7.enabled) {
|
|
2009
2010
|
const registered = {
|
|
2010
2011
|
shortFlags: [...forceFlag.forceFlagShortNames],
|
|
2011
2012
|
longFlags: [...forceFlag.forceFlagLongNames],
|
|
2012
2013
|
shortOptions: [...forceFlag.forceOptionShortNames],
|
|
2013
2014
|
longOptions: [...forceFlag.forceOptionLongNames]
|
|
2014
2015
|
};
|
|
2015
|
-
debug$
|
|
2016
|
+
debug$7("Registered:", JSON.stringify(registered));
|
|
2016
2017
|
}
|
|
2017
2018
|
const nodes = [];
|
|
2018
2019
|
let index = 0;
|
|
@@ -2143,9 +2144,9 @@ var require_parser$1 = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/
|
|
|
2143
2144
|
}
|
|
2144
2145
|
index++;
|
|
2145
2146
|
}
|
|
2146
|
-
if (debug$
|
|
2147
|
+
if (debug$7.enabled) {
|
|
2147
2148
|
const objectNodes = nodes.map((node) => ({ [node.type]: node.raw }));
|
|
2148
|
-
debug$
|
|
2149
|
+
debug$7("Parsed items:", JSON.stringify(objectNodes));
|
|
2149
2150
|
}
|
|
2150
2151
|
return nodes;
|
|
2151
2152
|
}
|
|
@@ -6755,7 +6756,7 @@ function _usingCtx() {
|
|
|
6755
6756
|
//#region src/commands/login.ts
|
|
6756
6757
|
var import_cjs$23 = /* @__PURE__ */ __toESM(require_cjs());
|
|
6757
6758
|
init_source();
|
|
6758
|
-
const debug$
|
|
6759
|
+
const debug$6 = createDebugger("sandbox:login");
|
|
6759
6760
|
const login = import_cjs$23.command({
|
|
6760
6761
|
name: "login",
|
|
6761
6762
|
description: "Log in to the Sandbox CLI",
|
|
@@ -6797,13 +6798,13 @@ const login = import_cjs$23.command({
|
|
|
6797
6798
|
oauth
|
|
6798
6799
|
})) switch (event._tag) {
|
|
6799
6800
|
case "Timeout":
|
|
6800
|
-
debug$
|
|
6801
|
+
debug$6(`Connection timeout. Slowing down, polling every ${event.newInterval / 1e3}s...`);
|
|
6801
6802
|
break;
|
|
6802
6803
|
case "SlowDown":
|
|
6803
|
-
debug$
|
|
6804
|
+
debug$6(`Authorization server requests to slow down. Polling every ${event.newInterval / 1e3}s...`);
|
|
6804
6805
|
break;
|
|
6805
6806
|
case "Response":
|
|
6806
|
-
debug$
|
|
6807
|
+
debug$6("Device Access Token response:", await event.response.text());
|
|
6807
6808
|
break;
|
|
6808
6809
|
case "Error":
|
|
6809
6810
|
error = event.error;
|
|
@@ -6977,7 +6978,20 @@ var require_dist = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/@ver
|
|
|
6977
6978
|
var import_cjs$22 = /* @__PURE__ */ __toESM(require_cjs());
|
|
6978
6979
|
init_source();
|
|
6979
6980
|
var import_dist = require_dist();
|
|
6980
|
-
const debug$
|
|
6981
|
+
const debug$5 = createDebugger("sandbox:args:auth");
|
|
6982
|
+
/**
|
|
6983
|
+
* Timestamp (ms epoch) of the most recent auto-login. Used to identify
|
|
6984
|
+
* tokens so that the first 401/403 against a freshly-issued token can be
|
|
6985
|
+
* retried instead of surfaced to the user.
|
|
6986
|
+
*/
|
|
6987
|
+
let freshTokenAcquiredAt;
|
|
6988
|
+
const FRESH_TOKEN_WINDOW_MS = 1e4;
|
|
6989
|
+
function isTokenFresh() {
|
|
6990
|
+
return freshTokenAcquiredAt !== void 0 && Date.now() - freshTokenAcquiredAt < FRESH_TOKEN_WINDOW_MS;
|
|
6991
|
+
}
|
|
6992
|
+
function markTokenAsFresh() {
|
|
6993
|
+
freshTokenAcquiredAt = Date.now();
|
|
6994
|
+
}
|
|
6981
6995
|
const token = import_cjs$22.option({
|
|
6982
6996
|
long: "token",
|
|
6983
6997
|
description: "A Vercel authentication token. If not provided, will use the token stored in your system from `VERCEL_AUTH_TOKEN` or will start a log in process.",
|
|
@@ -6990,18 +7004,20 @@ const token = import_cjs$22.option({
|
|
|
6990
7004
|
if (process.env.VERCEL_OIDC_TOKEN) try {
|
|
6991
7005
|
return await (0, import_dist.getVercelOidcToken)();
|
|
6992
7006
|
} catch (cause) {
|
|
6993
|
-
debug$
|
|
7007
|
+
debug$5(`Failed to get or refresh OIDC token: ${getMessage(cause)}`);
|
|
6994
7008
|
console.warn(source_default.yellow(`${source_default.bold("warn:")} failed to get or refresh OIDC token, using personal token authentication.`));
|
|
6995
7009
|
}
|
|
6996
7010
|
try {
|
|
6997
7011
|
return await (0, import_dist.getVercelToken)();
|
|
6998
7012
|
} catch (error) {
|
|
6999
7013
|
if (error instanceof import_dist.AccessTokenMissingError || error instanceof import_dist.RefreshAccessTokenFailedError) {
|
|
7000
|
-
debug$
|
|
7014
|
+
debug$5(`CLI token unavailable (${error.name}), prompting for login...`);
|
|
7001
7015
|
console.warn(source_default.yellow(`${source_default.bold("notice:")} Your session has expired. Please log in again.`));
|
|
7002
7016
|
await login.handler({});
|
|
7003
7017
|
try {
|
|
7004
|
-
|
|
7018
|
+
const refreshed = await (0, import_dist.getVercelToken)();
|
|
7019
|
+
markTokenAsFresh();
|
|
7020
|
+
return refreshed;
|
|
7005
7021
|
} catch (retryError) {
|
|
7006
7022
|
throw new Error([
|
|
7007
7023
|
`Failed to retrieve authentication token.`,
|
|
@@ -7062,18 +7078,18 @@ function readProjectConfiguration(cwd) {
|
|
|
7062
7078
|
|
|
7063
7079
|
//#endregion
|
|
7064
7080
|
//#region src/util/infer-scope.ts
|
|
7065
|
-
const debug$
|
|
7081
|
+
const debug$4 = createDebugger("sandbox:scope");
|
|
7066
7082
|
async function inferScope$1({ token: token$1, team: team$1 }) {
|
|
7067
7083
|
const jwt = z.jwt().safeParse(token$1);
|
|
7068
7084
|
if (jwt.success) {
|
|
7069
|
-
debug$
|
|
7085
|
+
debug$4("trying to infer scope from OIDC JWT");
|
|
7070
7086
|
const data = await inferFromJwt(jwt.data);
|
|
7071
|
-
debug$
|
|
7087
|
+
debug$4("Using scope from OIDC JWT", data);
|
|
7072
7088
|
return data;
|
|
7073
7089
|
}
|
|
7074
7090
|
const projectJson = readProjectConfiguration(process.cwd());
|
|
7075
7091
|
if (projectJson) {
|
|
7076
|
-
debug$
|
|
7092
|
+
debug$4("Using scope from project configuration", {
|
|
7077
7093
|
owner: projectJson.orgId,
|
|
7078
7094
|
project: projectJson.projectId
|
|
7079
7095
|
});
|
|
@@ -7082,12 +7098,12 @@ async function inferScope$1({ token: token$1, team: team$1 }) {
|
|
|
7082
7098
|
project: projectJson.projectId
|
|
7083
7099
|
};
|
|
7084
7100
|
}
|
|
7085
|
-
debug$
|
|
7101
|
+
debug$4("trying to infer scope from API token", {
|
|
7086
7102
|
token: token$1,
|
|
7087
7103
|
team: team$1
|
|
7088
7104
|
});
|
|
7089
7105
|
const fromToken = await inferFromToken(token$1, team$1);
|
|
7090
|
-
debug$
|
|
7106
|
+
debug$4("Using scope from API token", fromToken);
|
|
7091
7107
|
return fromToken;
|
|
7092
7108
|
}
|
|
7093
7109
|
const JwtSchema = z.object({
|
|
@@ -7123,6 +7139,44 @@ async function inferFromToken(token$1, requestedTeam) {
|
|
|
7123
7139
|
};
|
|
7124
7140
|
}
|
|
7125
7141
|
|
|
7142
|
+
//#endregion
|
|
7143
|
+
//#region src/util/fresh-auth-retry.ts
|
|
7144
|
+
const debug$3 = createDebugger("sandbox:fresh-auth-retry");
|
|
7145
|
+
/**
|
|
7146
|
+
* Run an async operation, transparently retrying on 401/403 when the auth
|
|
7147
|
+
* token was just acquired via auto-login.
|
|
7148
|
+
*/
|
|
7149
|
+
async function withFreshAuthRetry(factory) {
|
|
7150
|
+
return retry(async (bail, attempt) => {
|
|
7151
|
+
try {
|
|
7152
|
+
return await factory();
|
|
7153
|
+
} catch (error) {
|
|
7154
|
+
const status = getAuthFailureStatus(error);
|
|
7155
|
+
if (status !== void 0 && isTokenFresh()) {
|
|
7156
|
+
debug$3(`fresh-auth retry attempt ${attempt} (status ${status})`);
|
|
7157
|
+
throw error;
|
|
7158
|
+
}
|
|
7159
|
+
bail(error);
|
|
7160
|
+
return;
|
|
7161
|
+
}
|
|
7162
|
+
}, {
|
|
7163
|
+
retries: 3,
|
|
7164
|
+
minTimeout: 250,
|
|
7165
|
+
factor: 2,
|
|
7166
|
+
maxRetryTime: 3e3
|
|
7167
|
+
});
|
|
7168
|
+
}
|
|
7169
|
+
/**
|
|
7170
|
+
* Returns the HTTP status if the error represents a 401 or 403.
|
|
7171
|
+
* Returns undefined for any other error.
|
|
7172
|
+
*/
|
|
7173
|
+
function getAuthFailureStatus(error) {
|
|
7174
|
+
let status;
|
|
7175
|
+
if (error instanceof APIError) status = error.response.status;
|
|
7176
|
+
else if (error instanceof NotOk) status = error.response.statusCode;
|
|
7177
|
+
return status === 401 || status === 403 ? status : void 0;
|
|
7178
|
+
}
|
|
7179
|
+
|
|
7126
7180
|
//#endregion
|
|
7127
7181
|
//#region src/args/scope.ts
|
|
7128
7182
|
var import_cjs$21 = /* @__PURE__ */ __toESM(require_cjs());
|
|
@@ -7190,10 +7244,10 @@ const scope = {
|
|
|
7190
7244
|
let projectSlug;
|
|
7191
7245
|
let teamSlug;
|
|
7192
7246
|
if (typeof projectId.value === "undefined" || typeof teamId.value === "undefined") try {
|
|
7193
|
-
const scope$1 = await inferScope$1({
|
|
7247
|
+
const scope$1 = await withFreshAuthRetry(() => inferScope$1({
|
|
7194
7248
|
token: t.value,
|
|
7195
7249
|
team: teamId.value
|
|
7196
|
-
});
|
|
7250
|
+
}));
|
|
7197
7251
|
projectId.value ?? (projectId.value = scope$1.project);
|
|
7198
7252
|
teamId.value ?? (teamId.value = scope$1.owner);
|
|
7199
7253
|
projectSlug = scope$1.projectSlug;
|
|
@@ -7236,7 +7290,7 @@ const scope = {
|
|
|
7236
7290
|
|
|
7237
7291
|
//#endregion
|
|
7238
7292
|
//#region package.json
|
|
7239
|
-
var version = "3.0.0-beta.
|
|
7293
|
+
var version = "3.0.0-beta.23";
|
|
7240
7294
|
|
|
7241
7295
|
//#endregion
|
|
7242
7296
|
//#region src/error.ts
|
|
@@ -7255,26 +7309,30 @@ init_source();
|
|
|
7255
7309
|
* A {@link Sandbox} wrapper that adds user-agent headers and error handling.
|
|
7256
7310
|
*/
|
|
7257
7311
|
const sandboxClient = {
|
|
7258
|
-
get: (params) => withErrorHandling(Sandbox.get({
|
|
7312
|
+
get: (params) => withErrorHandling(() => Sandbox.get({
|
|
7259
7313
|
fetch: fetchWithUserAgent,
|
|
7260
7314
|
resume: false,
|
|
7261
7315
|
...params
|
|
7262
7316
|
})),
|
|
7263
|
-
create: (params) => withErrorHandling(Sandbox.create({
|
|
7317
|
+
create: (params) => withErrorHandling(() => Sandbox.create({
|
|
7264
7318
|
fetch: fetchWithUserAgent,
|
|
7265
7319
|
...params
|
|
7266
7320
|
})),
|
|
7267
|
-
list: (params) => withErrorHandling(Sandbox.list({
|
|
7321
|
+
list: (params) => withErrorHandling(() => Sandbox.list({
|
|
7268
7322
|
fetch: fetchWithUserAgent,
|
|
7269
7323
|
...params
|
|
7270
7324
|
}))
|
|
7271
7325
|
};
|
|
7272
7326
|
const snapshotClient = {
|
|
7273
|
-
list: (params) => withErrorHandling(Snapshot.list({
|
|
7327
|
+
list: (params) => withErrorHandling(() => Snapshot.list({
|
|
7274
7328
|
fetch: fetchWithUserAgent,
|
|
7275
7329
|
...params
|
|
7276
7330
|
})),
|
|
7277
|
-
get: (params) => withErrorHandling(Snapshot.get({ ...params }))
|
|
7331
|
+
get: (params) => withErrorHandling(() => Snapshot.get({ ...params })),
|
|
7332
|
+
fromSandbox: (name, opts) => withErrorHandling(() => Snapshot.fromSandbox(name, {
|
|
7333
|
+
fetch: fetchWithUserAgent,
|
|
7334
|
+
...opts
|
|
7335
|
+
}))
|
|
7278
7336
|
};
|
|
7279
7337
|
const fetchWithUserAgent = (input, init$1) => {
|
|
7280
7338
|
const headers = new Headers(init$1?.headers ?? (input && typeof input === "object" && "headers" in input ? input?.headers : {}));
|
|
@@ -7287,9 +7345,9 @@ const fetchWithUserAgent = (input, init$1) => {
|
|
|
7287
7345
|
headers
|
|
7288
7346
|
});
|
|
7289
7347
|
};
|
|
7290
|
-
async function withErrorHandling(
|
|
7348
|
+
async function withErrorHandling(factory) {
|
|
7291
7349
|
try {
|
|
7292
|
-
return await
|
|
7350
|
+
return await withFreshAuthRetry(factory);
|
|
7293
7351
|
} catch (error) {
|
|
7294
7352
|
if (error instanceof APIError) return await handleApiError(error);
|
|
7295
7353
|
throw error;
|
|
@@ -11591,6 +11649,11 @@ const args$2 = {
|
|
|
11591
11649
|
description: "Start the sandbox from a snapshot ID",
|
|
11592
11650
|
type: import_cjs$14.optional(snapshotId)
|
|
11593
11651
|
}),
|
|
11652
|
+
sandboxSnapshot: import_cjs$14.option({
|
|
11653
|
+
long: "sandbox-snapshot",
|
|
11654
|
+
description: "Start the sandbox from another sandbox's current snapshot",
|
|
11655
|
+
type: import_cjs$14.optional(sandboxName)
|
|
11656
|
+
}),
|
|
11594
11657
|
connect: import_cjs$14.flag({
|
|
11595
11658
|
long: "connect",
|
|
11596
11659
|
description: "Start an interactive shell session after creating the sandbox"
|
|
@@ -11612,6 +11675,30 @@ const args$2 = {
|
|
|
11612
11675
|
type: import_cjs$14.optional(SnapshotExpiration),
|
|
11613
11676
|
description: "Default snapshot expiration. Use \"none\" or 0 for no expiration. Example: 7d, 30d"
|
|
11614
11677
|
}),
|
|
11678
|
+
keepLastSnapshots: import_cjs$14.option({
|
|
11679
|
+
long: "keep-last-snapshots",
|
|
11680
|
+
type: import_cjs$14.optional(import_cjs$14.extendType(import_cjs$14.number, {
|
|
11681
|
+
displayName: "COUNT",
|
|
11682
|
+
async from(n) {
|
|
11683
|
+
if (!Number.isInteger(n) || n < 1 || n > 10) throw new Error(`Invalid --keep-last-snapshots value: ${n}. Must be an integer between 1 and 10.`);
|
|
11684
|
+
return n;
|
|
11685
|
+
}
|
|
11686
|
+
})),
|
|
11687
|
+
description: "Keep only the N most recent snapshots of this sandbox (1-10)."
|
|
11688
|
+
}),
|
|
11689
|
+
keepLastSnapshotsFor: import_cjs$14.option({
|
|
11690
|
+
long: "keep-last-snapshots-for",
|
|
11691
|
+
type: import_cjs$14.optional(SnapshotExpiration),
|
|
11692
|
+
description: "Expiration applied to kept snapshots. Use \"none\" or 0 for no expiration. Example: 7d, 30d"
|
|
11693
|
+
}),
|
|
11694
|
+
deleteEvictedSnapshots: import_cjs$14.option({
|
|
11695
|
+
long: "delete-evicted-snapshots",
|
|
11696
|
+
type: import_cjs$14.optional({
|
|
11697
|
+
...import_cjs$14.oneOf(["true", "false"]),
|
|
11698
|
+
displayName: "true|false"
|
|
11699
|
+
}),
|
|
11700
|
+
description: "When \"true\" (the default), evicted snapshots are deleted immediately; when \"false\", they keep the default expiration."
|
|
11701
|
+
}),
|
|
11615
11702
|
...networkPolicyArgs,
|
|
11616
11703
|
scope
|
|
11617
11704
|
};
|
|
@@ -11623,22 +11710,34 @@ const create = import_cjs$14.command({
|
|
|
11623
11710
|
description: "Create and connect to a sandbox without a network access",
|
|
11624
11711
|
command: `sandbox run --network-policy=none --connect`
|
|
11625
11712
|
}],
|
|
11626
|
-
async handler({ name, nonPersistent, ports, scope: scope$1, runtime: runtime$1, timeout: timeout$1, vcpus: vcpus$1, silent, snapshot: snapshot$1, connect: connect$2, envVars, tags, snapshotExpiration, networkPolicy: networkPolicyMode$1, allowedDomains: allowedDomains$1, allowedCIDRs: allowedCIDRs$1, deniedCIDRs: deniedCIDRs$1 }) {
|
|
11713
|
+
async handler({ name, nonPersistent, ports, scope: scope$1, runtime: runtime$1, timeout: timeout$1, vcpus: vcpus$1, silent, snapshot: snapshot$1, sandboxSnapshot, connect: connect$2, envVars, tags, snapshotExpiration, keepLastSnapshots, keepLastSnapshotsFor, deleteEvictedSnapshots, networkPolicy: networkPolicyMode$1, allowedDomains: allowedDomains$1, allowedCIDRs: allowedCIDRs$1, deniedCIDRs: deniedCIDRs$1 }) {
|
|
11714
|
+
if (snapshot$1 && sandboxSnapshot) throw new Error([`Cannot use --snapshot and --sandbox-snapshot together.`, `${source_default.bold("hint:")} Pick one source for the new sandbox.`].join("\n"));
|
|
11627
11715
|
const networkPolicy$1 = buildNetworkPolicy({
|
|
11628
11716
|
networkPolicy: networkPolicyMode$1,
|
|
11629
11717
|
allowedDomains: allowedDomains$1,
|
|
11630
11718
|
allowedCIDRs: allowedCIDRs$1,
|
|
11631
11719
|
deniedCIDRs: deniedCIDRs$1
|
|
11632
11720
|
});
|
|
11721
|
+
if (keepLastSnapshots === void 0 && (keepLastSnapshotsFor !== void 0 || deleteEvictedSnapshots !== void 0)) throw new Error(["--keep-last-snapshots-for and --delete-evicted-snapshots require --keep-last-snapshots.", `${source_default.bold("hint:")} Pass --keep-last-snapshots <count> to enable the retention policy.`].join("\n"));
|
|
11722
|
+
const keepLastSnapshotsPayload = keepLastSnapshots !== void 0 ? {
|
|
11723
|
+
count: keepLastSnapshots,
|
|
11724
|
+
expiration: keepLastSnapshotsFor !== void 0 ? (0, import_ms$2.default)(keepLastSnapshotsFor) : void 0,
|
|
11725
|
+
deleteEvicted: deleteEvictedSnapshots !== void 0 ? deleteEvictedSnapshots === "true" : void 0
|
|
11726
|
+
} : void 0;
|
|
11633
11727
|
const persistent = !nonPersistent;
|
|
11634
11728
|
const resources = vcpus$1 ? { vcpus: vcpus$1 } : void 0;
|
|
11635
11729
|
const tagsObj = Object.keys(tags).length > 0 ? tags : void 0;
|
|
11730
|
+
const resolvedSnapshot = snapshot$1 ?? (sandboxSnapshot ? await snapshotClient.fromSandbox(sandboxSnapshot, {
|
|
11731
|
+
teamId: scope$1.team,
|
|
11732
|
+
projectId: scope$1.project,
|
|
11733
|
+
token: scope$1.token
|
|
11734
|
+
}) : void 0);
|
|
11636
11735
|
const spinner = silent ? void 0 : ora("Creating sandbox...").start();
|
|
11637
|
-
const sandbox =
|
|
11736
|
+
const sandbox = resolvedSnapshot ? await sandboxClient.create({
|
|
11638
11737
|
name,
|
|
11639
11738
|
source: {
|
|
11640
11739
|
type: "snapshot",
|
|
11641
|
-
snapshotId:
|
|
11740
|
+
snapshotId: resolvedSnapshot
|
|
11642
11741
|
},
|
|
11643
11742
|
teamId: scope$1.team,
|
|
11644
11743
|
projectId: scope$1.project,
|
|
@@ -11651,6 +11750,7 @@ const create = import_cjs$14.command({
|
|
|
11651
11750
|
tags: tagsObj,
|
|
11652
11751
|
persistent,
|
|
11653
11752
|
snapshotExpiration: snapshotExpiration ? (0, import_ms$2.default)(snapshotExpiration) : void 0,
|
|
11753
|
+
keepLastSnapshots: keepLastSnapshotsPayload,
|
|
11654
11754
|
__interactive: true
|
|
11655
11755
|
}) : await sandboxClient.create({
|
|
11656
11756
|
name,
|
|
@@ -11666,6 +11766,7 @@ const create = import_cjs$14.command({
|
|
|
11666
11766
|
tags: tagsObj,
|
|
11667
11767
|
persistent,
|
|
11668
11768
|
snapshotExpiration: snapshotExpiration ? (0, import_ms$2.default)(snapshotExpiration) : void 0,
|
|
11769
|
+
keepLastSnapshots: keepLastSnapshotsPayload,
|
|
11669
11770
|
__interactive: true
|
|
11670
11771
|
});
|
|
11671
11772
|
spinner?.stop();
|
|
@@ -14895,6 +14996,136 @@ const snapshotExpirationCommand = import_cjs$1.command({
|
|
|
14895
14996
|
}
|
|
14896
14997
|
}
|
|
14897
14998
|
});
|
|
14999
|
+
const keepLastCountType = import_cjs$1.extendType(import_cjs$1.number, {
|
|
15000
|
+
displayName: "COUNT",
|
|
15001
|
+
async from(n) {
|
|
15002
|
+
if (!Number.isInteger(n) || n < 0 || n > 10) throw new Error(`Invalid count: ${n}. Must be an integer between 0 and 10 (0 removes the policy).`);
|
|
15003
|
+
return n;
|
|
15004
|
+
}
|
|
15005
|
+
});
|
|
15006
|
+
const keepLastSnapshotsCommand = import_cjs$1.command({
|
|
15007
|
+
name: "keep-last-snapshots",
|
|
15008
|
+
description: "Update the snapshot retention policy (keep only the N most recent snapshots) of a sandbox",
|
|
15009
|
+
args: {
|
|
15010
|
+
sandbox: import_cjs$1.positional({
|
|
15011
|
+
type: sandboxName,
|
|
15012
|
+
description: "Sandbox name to update"
|
|
15013
|
+
}),
|
|
15014
|
+
count: import_cjs$1.positional({
|
|
15015
|
+
type: keepLastCountType,
|
|
15016
|
+
description: "Number of most recent snapshots to keep (1-10). Pass 0 to remove the policy."
|
|
15017
|
+
}),
|
|
15018
|
+
scope
|
|
15019
|
+
},
|
|
15020
|
+
async handler({ scope: { token: token$1, team: team$1, project: project$1 }, sandbox: name, count }) {
|
|
15021
|
+
const sandbox = await sandboxClient.get({
|
|
15022
|
+
name,
|
|
15023
|
+
projectId: project$1,
|
|
15024
|
+
teamId: team$1,
|
|
15025
|
+
token: token$1
|
|
15026
|
+
});
|
|
15027
|
+
const spinner = ora("Updating sandbox configuration...").start();
|
|
15028
|
+
try {
|
|
15029
|
+
if (count === 0) await sandbox.update({ keepLastSnapshots: null });
|
|
15030
|
+
else {
|
|
15031
|
+
const current = sandbox.keepLastSnapshots;
|
|
15032
|
+
await sandbox.update({ keepLastSnapshots: {
|
|
15033
|
+
count,
|
|
15034
|
+
expiration: current?.expiration,
|
|
15035
|
+
deleteEvicted: current?.deleteEvicted
|
|
15036
|
+
} });
|
|
15037
|
+
}
|
|
15038
|
+
spinner.stop();
|
|
15039
|
+
process.stderr.write("✅ Configuration updated for sandbox " + source_default.cyan(name) + "\n");
|
|
15040
|
+
process.stderr.write(source_default.dim(" ╰ ") + "keep-last-snapshots: " + source_default.cyan(count === 0 ? "cleared" : `count=${count}`) + "\n");
|
|
15041
|
+
} catch (error) {
|
|
15042
|
+
spinner.stop();
|
|
15043
|
+
throw error;
|
|
15044
|
+
}
|
|
15045
|
+
}
|
|
15046
|
+
});
|
|
15047
|
+
const keepLastSnapshotsForCommand = import_cjs$1.command({
|
|
15048
|
+
name: "keep-last-snapshots-for",
|
|
15049
|
+
description: "Update the expiration applied to snapshots kept by the retention policy",
|
|
15050
|
+
args: {
|
|
15051
|
+
sandbox: import_cjs$1.positional({
|
|
15052
|
+
type: sandboxName,
|
|
15053
|
+
description: "Sandbox name to update"
|
|
15054
|
+
}),
|
|
15055
|
+
duration: import_cjs$1.positional({
|
|
15056
|
+
type: SnapshotExpiration,
|
|
15057
|
+
description: "Expiration for kept snapshots. Use \"none\" or 0 for no expiration. Example: 7d, 30d"
|
|
15058
|
+
}),
|
|
15059
|
+
scope
|
|
15060
|
+
},
|
|
15061
|
+
async handler({ scope: { token: token$1, team: team$1, project: project$1 }, sandbox: name, duration }) {
|
|
15062
|
+
const sandbox = await sandboxClient.get({
|
|
15063
|
+
name,
|
|
15064
|
+
projectId: project$1,
|
|
15065
|
+
teamId: team$1,
|
|
15066
|
+
token: token$1
|
|
15067
|
+
});
|
|
15068
|
+
const current = sandbox.keepLastSnapshots;
|
|
15069
|
+
if (!current) throw new Error(["No keep-last-snapshots policy is set on this sandbox.", `${source_default.bold("hint:")} Set a count first with: sandbox config keep-last-snapshots ${name} <count>`].join("\n"));
|
|
15070
|
+
const spinner = ora("Updating sandbox configuration...").start();
|
|
15071
|
+
try {
|
|
15072
|
+
await sandbox.update({ keepLastSnapshots: {
|
|
15073
|
+
count: current.count,
|
|
15074
|
+
expiration: (0, import_ms.default)(duration),
|
|
15075
|
+
deleteEvicted: current.deleteEvicted
|
|
15076
|
+
} });
|
|
15077
|
+
spinner.stop();
|
|
15078
|
+
const display = (0, import_ms.default)(duration) === 0 ? "none" : duration;
|
|
15079
|
+
process.stderr.write("✅ Configuration updated for sandbox " + source_default.cyan(name) + "\n");
|
|
15080
|
+
process.stderr.write(source_default.dim(" ╰ ") + "keep-last-snapshots-for: " + source_default.cyan(display) + "\n");
|
|
15081
|
+
} catch (error) {
|
|
15082
|
+
spinner.stop();
|
|
15083
|
+
throw error;
|
|
15084
|
+
}
|
|
15085
|
+
}
|
|
15086
|
+
});
|
|
15087
|
+
const deleteEvictedSnapshotsCommand = import_cjs$1.command({
|
|
15088
|
+
name: "delete-evicted-snapshots",
|
|
15089
|
+
description: "When \"true\" (the default), snapshots evicted by the keep-last-snapshots policy are deleted immediately; when \"false\", they keep the default expiration.",
|
|
15090
|
+
args: {
|
|
15091
|
+
sandbox: import_cjs$1.positional({
|
|
15092
|
+
type: sandboxName,
|
|
15093
|
+
description: "Sandbox name to update"
|
|
15094
|
+
}),
|
|
15095
|
+
value: import_cjs$1.positional({
|
|
15096
|
+
type: {
|
|
15097
|
+
...import_cjs$1.oneOf(["true", "false"]),
|
|
15098
|
+
displayName: "true|false"
|
|
15099
|
+
},
|
|
15100
|
+
description: "Whether to delete evicted snapshots immediately (\"true\") or let them keep the default expiration (\"false\")."
|
|
15101
|
+
}),
|
|
15102
|
+
scope
|
|
15103
|
+
},
|
|
15104
|
+
async handler({ scope: { token: token$1, team: team$1, project: project$1 }, sandbox: name, value }) {
|
|
15105
|
+
const sandbox = await sandboxClient.get({
|
|
15106
|
+
name,
|
|
15107
|
+
projectId: project$1,
|
|
15108
|
+
teamId: team$1,
|
|
15109
|
+
token: token$1
|
|
15110
|
+
});
|
|
15111
|
+
const current = sandbox.keepLastSnapshots;
|
|
15112
|
+
if (!current) throw new Error(["No keep-last-snapshots policy is set on this sandbox.", `${source_default.bold("hint:")} Set a count first with: sandbox config keep-last-snapshots ${name} <count>`].join("\n"));
|
|
15113
|
+
const spinner = ora("Updating sandbox configuration...").start();
|
|
15114
|
+
try {
|
|
15115
|
+
await sandbox.update({ keepLastSnapshots: {
|
|
15116
|
+
count: current.count,
|
|
15117
|
+
expiration: current.expiration,
|
|
15118
|
+
deleteEvicted: value === "true"
|
|
15119
|
+
} });
|
|
15120
|
+
spinner.stop();
|
|
15121
|
+
process.stderr.write("✅ Configuration updated for sandbox " + source_default.cyan(name) + "\n");
|
|
15122
|
+
process.stderr.write(source_default.dim(" ╰ ") + "delete-evicted-snapshots: " + source_default.cyan(value) + "\n");
|
|
15123
|
+
} catch (error) {
|
|
15124
|
+
spinner.stop();
|
|
15125
|
+
throw error;
|
|
15126
|
+
}
|
|
15127
|
+
}
|
|
15128
|
+
});
|
|
14898
15129
|
const currentSnapshotCommand = import_cjs$1.command({
|
|
14899
15130
|
name: "current-snapshot",
|
|
14900
15131
|
description: "Update the current snapshot of a sandbox",
|
|
@@ -14979,6 +15210,10 @@ const listCommand = import_cjs$1.command({
|
|
|
14979
15210
|
field: "Snapshot expiration",
|
|
14980
15211
|
value: sandbox.snapshotExpiration != null && sandbox.snapshotExpiration > 0 ? (0, import_ms.default)(sandbox.snapshotExpiration, { long: true }) : sandbox.snapshotExpiration === 0 ? "none" : "-"
|
|
14981
15212
|
},
|
|
15213
|
+
{
|
|
15214
|
+
field: "Keep last snapshots",
|
|
15215
|
+
value: formatKeepLastSnapshots(sandbox.keepLastSnapshots)
|
|
15216
|
+
},
|
|
14982
15217
|
{
|
|
14983
15218
|
field: "Current snapshot",
|
|
14984
15219
|
value: sandbox.currentSnapshotId ?? "-"
|
|
@@ -15083,6 +15318,13 @@ const tagsCommand = import_cjs$1.command({
|
|
|
15083
15318
|
}
|
|
15084
15319
|
}
|
|
15085
15320
|
});
|
|
15321
|
+
function formatKeepLastSnapshots(keepLastSnapshots) {
|
|
15322
|
+
if (!keepLastSnapshots) return "-";
|
|
15323
|
+
const parts = [`count=${keepLastSnapshots.count}`];
|
|
15324
|
+
if (keepLastSnapshots.expiration !== void 0) parts.push(`for=${keepLastSnapshots.expiration === 0 ? "none" : (0, import_ms.default)(keepLastSnapshots.expiration, { long: true })}`);
|
|
15325
|
+
if (keepLastSnapshots.deleteEvicted !== void 0) parts.push(`delete-evicted-snapshots=${keepLastSnapshots.deleteEvicted}`);
|
|
15326
|
+
return parts.join(", ");
|
|
15327
|
+
}
|
|
15086
15328
|
const config = import_cjs$1.subcommands({
|
|
15087
15329
|
name: "config",
|
|
15088
15330
|
description: "View and update sandbox configuration",
|
|
@@ -15093,6 +15335,9 @@ const config = import_cjs$1.subcommands({
|
|
|
15093
15335
|
persistent: persistentCommand,
|
|
15094
15336
|
"network-policy": networkPolicyCommand,
|
|
15095
15337
|
"snapshot-expiration": snapshotExpirationCommand,
|
|
15338
|
+
"keep-last-snapshots": keepLastSnapshotsCommand,
|
|
15339
|
+
"keep-last-snapshots-for": keepLastSnapshotsForCommand,
|
|
15340
|
+
"delete-evicted-snapshots": deleteEvictedSnapshotsCommand,
|
|
15096
15341
|
"current-snapshot": currentSnapshotCommand,
|
|
15097
15342
|
tags: tagsCommand
|
|
15098
15343
|
}
|
|
@@ -15141,4 +15386,4 @@ const app = (opts) => (0, import_cjs.subcommands)({
|
|
|
15141
15386
|
|
|
15142
15387
|
//#endregion
|
|
15143
15388
|
export { source_exports as a, init_source as i, StyledError as n, require_cjs as r, app as t };
|
|
15144
|
-
//# sourceMappingURL=app-
|
|
15389
|
+
//# sourceMappingURL=app-BjVyEIk1.mjs.map
|