sandbox 3.0.0-beta.24 → 3.0.0-beta.26

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.
@@ -2998,9 +2998,9 @@ var require_cjs = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/cmd-t
2998
2998
 
2999
2999
  //#endregion
3000
3000
  //#region src/args/runtime.ts
3001
- var import_cjs$27 = /* @__PURE__ */ __toESM(require_cjs());
3001
+ var import_cjs$30 = /* @__PURE__ */ __toESM(require_cjs());
3002
3002
  const runtimeType = {
3003
- ...import_cjs$27.oneOf([
3003
+ ...import_cjs$30.oneOf([
3004
3004
  "node22",
3005
3005
  "node24",
3006
3006
  "node26",
@@ -3008,7 +3008,7 @@ const runtimeType = {
3008
3008
  ]),
3009
3009
  displayName: "runtime"
3010
3010
  };
3011
- const runtime = import_cjs$27.option({
3011
+ const runtime = import_cjs$30.option({
3012
3012
  long: "runtime",
3013
3013
  type: runtimeType,
3014
3014
  defaultValue: () => "node24",
@@ -3102,13 +3102,13 @@ var require_ms = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/ms@2.1
3102
3102
  * @return {String}
3103
3103
  * @api private
3104
3104
  */
3105
- function fmtShort(ms$4) {
3106
- var msAbs = Math.abs(ms$4);
3107
- if (msAbs >= d) return Math.round(ms$4 / d) + "d";
3108
- if (msAbs >= h) return Math.round(ms$4 / h) + "h";
3109
- if (msAbs >= m) return Math.round(ms$4 / m) + "m";
3110
- if (msAbs >= s) return Math.round(ms$4 / s) + "s";
3111
- return ms$4 + "ms";
3105
+ function fmtShort(ms$6) {
3106
+ var msAbs = Math.abs(ms$6);
3107
+ if (msAbs >= d) return Math.round(ms$6 / d) + "d";
3108
+ if (msAbs >= h) return Math.round(ms$6 / h) + "h";
3109
+ if (msAbs >= m) return Math.round(ms$6 / m) + "m";
3110
+ if (msAbs >= s) return Math.round(ms$6 / s) + "s";
3111
+ return ms$6 + "ms";
3112
3112
  }
3113
3113
  /**
3114
3114
  * Long format for `ms`.
@@ -3117,28 +3117,28 @@ var require_ms = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/ms@2.1
3117
3117
  * @return {String}
3118
3118
  * @api private
3119
3119
  */
3120
- function fmtLong(ms$4) {
3121
- var msAbs = Math.abs(ms$4);
3122
- if (msAbs >= d) return plural(ms$4, msAbs, d, "day");
3123
- if (msAbs >= h) return plural(ms$4, msAbs, h, "hour");
3124
- if (msAbs >= m) return plural(ms$4, msAbs, m, "minute");
3125
- if (msAbs >= s) return plural(ms$4, msAbs, s, "second");
3126
- return ms$4 + " ms";
3120
+ function fmtLong(ms$6) {
3121
+ var msAbs = Math.abs(ms$6);
3122
+ if (msAbs >= d) return plural(ms$6, msAbs, d, "day");
3123
+ if (msAbs >= h) return plural(ms$6, msAbs, h, "hour");
3124
+ if (msAbs >= m) return plural(ms$6, msAbs, m, "minute");
3125
+ if (msAbs >= s) return plural(ms$6, msAbs, s, "second");
3126
+ return ms$6 + " ms";
3127
3127
  }
3128
3128
  /**
3129
3129
  * Pluralization helper.
3130
3130
  */
3131
- function plural(ms$4, msAbs, n, name) {
3131
+ function plural(ms$6, msAbs, n, name) {
3132
3132
  var isPlural = msAbs >= n * 1.5;
3133
- return Math.round(ms$4 / n) + " " + name + (isPlural ? "s" : "");
3133
+ return Math.round(ms$6 / n) + " " + name + (isPlural ? "s" : "");
3134
3134
  }
3135
3135
  }) });
3136
3136
 
3137
3137
  //#endregion
3138
3138
  //#region src/types/duration.ts
3139
- var import_cjs$26 = require_cjs();
3139
+ var import_cjs$29 = require_cjs();
3140
3140
  init_source();
3141
- const Duration = (0, import_cjs$26.extendType)(import_cjs$26.string, {
3141
+ const Duration = (0, import_cjs$29.extendType)(import_cjs$29.string, {
3142
3142
  displayName: "num UNIT",
3143
3143
  description: "A duration, e.g. 5m, 10s, 1h",
3144
3144
  async from(string$2) {
@@ -3154,8 +3154,8 @@ const Duration = (0, import_cjs$26.extendType)(import_cjs$26.string, {
3154
3154
 
3155
3155
  //#endregion
3156
3156
  //#region src/args/timeout.ts
3157
- var import_cjs$25 = /* @__PURE__ */ __toESM(require_cjs());
3158
- const timeout = import_cjs$25.option({
3157
+ var import_cjs$28 = /* @__PURE__ */ __toESM(require_cjs());
3158
+ const timeout = import_cjs$28.option({
3159
3159
  long: "timeout",
3160
3160
  type: Duration,
3161
3161
  description: "The maximum duration a sandbox can run for. Example: 5m, 30m",
@@ -3165,17 +3165,17 @@ const timeout = import_cjs$25.option({
3165
3165
 
3166
3166
  //#endregion
3167
3167
  //#region src/args/vcpus.ts
3168
- var import_cjs$24 = /* @__PURE__ */ __toESM(require_cjs());
3169
- const vcpusType = import_cjs$24.extendType(import_cjs$24.number, {
3168
+ var import_cjs$27 = /* @__PURE__ */ __toESM(require_cjs());
3169
+ const vcpusType = import_cjs$27.extendType(import_cjs$27.number, {
3170
3170
  displayName: "COUNT",
3171
3171
  async from(n) {
3172
3172
  if (!Number.isInteger(n) || n < 1) throw new Error(`Invalid vCPU count: ${n}. Must be a positive integer.`);
3173
3173
  return n;
3174
3174
  }
3175
3175
  });
3176
- const vcpus = import_cjs$24.option({
3176
+ const vcpus = import_cjs$27.option({
3177
3177
  long: "vcpus",
3178
- type: import_cjs$24.optional(vcpusType),
3178
+ type: import_cjs$27.optional(vcpusType),
3179
3179
  description: "Number of vCPUs to allocate (each vCPU includes 2048 MB of memory)"
3180
3180
  });
3181
3181
 
@@ -3257,10 +3257,10 @@ const formatDistance = (token$1, count, options) => {
3257
3257
 
3258
3258
  //#endregion
3259
3259
  //#region ../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/_lib/buildFormatLongFn.js
3260
- function buildFormatLongFn(args$4) {
3260
+ function buildFormatLongFn(args$5) {
3261
3261
  return (options = {}) => {
3262
- const width = options.width ? String(options.width) : args$4.defaultWidth;
3263
- return args$4.formats[width] || args$4.formats[args$4.defaultWidth];
3262
+ const width = options.width ? String(options.width) : args$5.defaultWidth;
3263
+ return args$5.formats[width] || args$5.formats[args$5.defaultWidth];
3264
3264
  };
3265
3265
  }
3266
3266
 
@@ -3344,20 +3344,20 @@ const formatRelative = (token$1, _date, _baseDate, _options$1) => formatRelative
3344
3344
  /**
3345
3345
  * The tuple of localized month values. The first element represents January.
3346
3346
  */
3347
- function buildLocalizeFn(args$4) {
3347
+ function buildLocalizeFn(args$5) {
3348
3348
  return (value, options) => {
3349
3349
  const context = options?.context ? String(options.context) : "standalone";
3350
3350
  let valuesArray;
3351
- if (context === "formatting" && args$4.formattingValues) {
3352
- const defaultWidth = args$4.defaultFormattingWidth || args$4.defaultWidth;
3351
+ if (context === "formatting" && args$5.formattingValues) {
3352
+ const defaultWidth = args$5.defaultFormattingWidth || args$5.defaultWidth;
3353
3353
  const width = options?.width ? String(options.width) : defaultWidth;
3354
- valuesArray = args$4.formattingValues[width] || args$4.formattingValues[defaultWidth];
3354
+ valuesArray = args$5.formattingValues[width] || args$5.formattingValues[defaultWidth];
3355
3355
  } else {
3356
- const defaultWidth = args$4.defaultWidth;
3357
- const width = options?.width ? String(options.width) : args$4.defaultWidth;
3358
- valuesArray = args$4.values[width] || args$4.values[defaultWidth];
3356
+ const defaultWidth = args$5.defaultWidth;
3357
+ const width = options?.width ? String(options.width) : args$5.defaultWidth;
3358
+ valuesArray = args$5.values[width] || args$5.values[defaultWidth];
3359
3359
  }
3360
- const index = args$4.argumentCallback ? args$4.argumentCallback(value) : value;
3360
+ const index = args$5.argumentCallback ? args$5.argumentCallback(value) : value;
3361
3361
  return valuesArray[index];
3362
3362
  };
3363
3363
  }
@@ -3574,17 +3574,17 @@ const localize = {
3574
3574
 
3575
3575
  //#endregion
3576
3576
  //#region ../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/_lib/buildMatchFn.js
3577
- function buildMatchFn(args$4) {
3577
+ function buildMatchFn(args$5) {
3578
3578
  return (string$2, options = {}) => {
3579
3579
  const width = options.width;
3580
- const matchPattern = width && args$4.matchPatterns[width] || args$4.matchPatterns[args$4.defaultMatchWidth];
3580
+ const matchPattern = width && args$5.matchPatterns[width] || args$5.matchPatterns[args$5.defaultMatchWidth];
3581
3581
  const matchResult = string$2.match(matchPattern);
3582
3582
  if (!matchResult) return null;
3583
3583
  const matchedString = matchResult[0];
3584
- const parsePatterns = width && args$4.parsePatterns[width] || args$4.parsePatterns[args$4.defaultParseWidth];
3584
+ const parsePatterns = width && args$5.parsePatterns[width] || args$5.parsePatterns[args$5.defaultParseWidth];
3585
3585
  const key = Array.isArray(parsePatterns) ? findIndex(parsePatterns, (pattern) => pattern.test(matchedString)) : findKey(parsePatterns, (pattern) => pattern.test(matchedString));
3586
3586
  let value;
3587
- value = args$4.valueCallback ? args$4.valueCallback(key) : key;
3587
+ value = args$5.valueCallback ? args$5.valueCallback(key) : key;
3588
3588
  value = options.valueCallback ? options.valueCallback(value) : value;
3589
3589
  const rest$1 = string$2.slice(matchedString.length);
3590
3590
  return {
@@ -3602,14 +3602,14 @@ function findIndex(array$1, predicate) {
3602
3602
 
3603
3603
  //#endregion
3604
3604
  //#region ../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/_lib/buildMatchPatternFn.js
3605
- function buildMatchPatternFn(args$4) {
3605
+ function buildMatchPatternFn(args$5) {
3606
3606
  return (string$2, options = {}) => {
3607
- const matchResult = string$2.match(args$4.matchPattern);
3607
+ const matchResult = string$2.match(args$5.matchPattern);
3608
3608
  if (!matchResult) return null;
3609
3609
  const matchedString = matchResult[0];
3610
- const parseResult = string$2.match(args$4.parsePattern);
3610
+ const parseResult = string$2.match(args$5.parsePattern);
3611
3611
  if (!parseResult) return null;
3612
- let value = args$4.valueCallback ? args$4.valueCallback(parseResult[0]) : parseResult[0];
3612
+ let value = args$5.valueCallback ? args$5.valueCallback(parseResult[0]) : parseResult[0];
3613
3613
  value = options.valueCallback ? options.valueCallback(value) : value;
3614
3614
  const rest$1 = string$2.slice(matchedString.length);
3615
3615
  return {
@@ -4237,15 +4237,15 @@ function formatRunDuration(d$1) {
4237
4237
  return `${d$1 / 1e3}s`;
4238
4238
  }
4239
4239
  function formatNextCursorHint(cursor) {
4240
- const args$4 = process.argv.slice(2);
4240
+ const args$5 = process.argv.slice(2);
4241
4241
  const filtered = [];
4242
- for (let i = 0; i < args$4.length; i++) {
4243
- if (args$4[i] === "--cursor") {
4242
+ for (let i = 0; i < args$5.length; i++) {
4243
+ if (args$5[i] === "--cursor") {
4244
4244
  i++;
4245
4245
  continue;
4246
4246
  }
4247
- if (args$4[i].startsWith("--cursor=")) continue;
4248
- filtered.push(args$4[i]);
4247
+ if (args$5[i].startsWith("--cursor=")) continue;
4248
+ filtered.push(args$5[i]);
4249
4249
  }
4250
4250
  return `\nMore results: sandbox ${filtered.join(" ")} --cursor ${cursor}`;
4251
4251
  }
@@ -6754,10 +6754,10 @@ function _usingCtx() {
6754
6754
 
6755
6755
  //#endregion
6756
6756
  //#region src/commands/login.ts
6757
- var import_cjs$23 = /* @__PURE__ */ __toESM(require_cjs());
6757
+ var import_cjs$26 = /* @__PURE__ */ __toESM(require_cjs());
6758
6758
  init_source();
6759
6759
  const debug$6 = createDebugger("sandbox:login");
6760
- const login = import_cjs$23.command({
6760
+ const login = import_cjs$26.command({
6761
6761
  name: "login",
6762
6762
  description: "Log in to the Sandbox CLI",
6763
6763
  args: {},
@@ -6975,7 +6975,7 @@ var require_dist = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/@ver
6975
6975
 
6976
6976
  //#endregion
6977
6977
  //#region src/args/auth.ts
6978
- var import_cjs$22 = /* @__PURE__ */ __toESM(require_cjs());
6978
+ var import_cjs$25 = /* @__PURE__ */ __toESM(require_cjs());
6979
6979
  init_source();
6980
6980
  var import_dist = require_dist();
6981
6981
  const debug$5 = createDebugger("sandbox:args:auth");
@@ -6992,11 +6992,11 @@ function isTokenFresh() {
6992
6992
  function markTokenAsFresh() {
6993
6993
  freshTokenAcquiredAt = Date.now();
6994
6994
  }
6995
- const token = import_cjs$22.option({
6995
+ const token = import_cjs$25.option({
6996
6996
  long: "token",
6997
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.",
6998
6998
  type: {
6999
- ...import_cjs$22.string,
6999
+ ...import_cjs$25.string,
7000
7000
  displayName: "pat_or_oidc",
7001
7001
  defaultValueIsSerializable: false,
7002
7002
  onMissing: async () => {
@@ -7179,29 +7179,29 @@ function getAuthFailureStatus(error) {
7179
7179
 
7180
7180
  //#endregion
7181
7181
  //#region src/args/scope.ts
7182
- var import_cjs$21 = /* @__PURE__ */ __toESM(require_cjs());
7182
+ var import_cjs$24 = /* @__PURE__ */ __toESM(require_cjs());
7183
7183
  init_source();
7184
- const project = import_cjs$21.option({
7184
+ const project = import_cjs$24.option({
7185
7185
  long: "project",
7186
7186
  type: {
7187
- ...import_cjs$21.optional(import_cjs$21.string),
7187
+ ...import_cjs$24.optional(import_cjs$24.string),
7188
7188
  displayName: "my-project"
7189
7189
  },
7190
7190
  description: "The project name or ID to associate with the command. Can be inferred from VERCEL_OIDC_TOKEN."
7191
7191
  });
7192
7192
  /** Parser for the `--team` option. */
7193
- const teamParser = import_cjs$21.option({
7193
+ const teamParser = import_cjs$24.option({
7194
7194
  long: "team",
7195
7195
  type: {
7196
- ...import_cjs$21.optional(import_cjs$21.string),
7196
+ ...import_cjs$24.optional(import_cjs$24.string),
7197
7197
  displayName: "my-team"
7198
7198
  }
7199
7199
  });
7200
7200
  /** Parser for the `--scope` option. */
7201
- const scopeParser = import_cjs$21.option({
7201
+ const scopeParser = import_cjs$24.option({
7202
7202
  long: "scope",
7203
7203
  type: {
7204
- ...import_cjs$21.optional(import_cjs$21.string),
7204
+ ...import_cjs$24.optional(import_cjs$24.string),
7205
7205
  displayName: "my-team"
7206
7206
  },
7207
7207
  description: "The scope/team to associate with the command. Can be inferred from VERCEL_OIDC_TOKEN. [alias: --team]"
@@ -7290,7 +7290,7 @@ const scope = {
7290
7290
 
7291
7291
  //#endregion
7292
7292
  //#region package.json
7293
- var version = "3.0.0-beta.24";
7293
+ var version = "3.0.0-beta.26";
7294
7294
 
7295
7295
  //#endregion
7296
7296
  //#region src/error.ts
@@ -7318,6 +7318,10 @@ const sandboxClient = {
7318
7318
  fetch: fetchWithUserAgent,
7319
7319
  ...params
7320
7320
  })),
7321
+ fork: (params) => withErrorHandling(() => Sandbox.fork({
7322
+ fetch: fetchWithUserAgent,
7323
+ ...params
7324
+ })),
7321
7325
  list: (params) => withErrorHandling(() => Sandbox.list({
7322
7326
  fetch: fetchWithUserAgent,
7323
7327
  ...params
@@ -7329,10 +7333,6 @@ const snapshotClient = {
7329
7333
  ...params
7330
7334
  })),
7331
7335
  get: (params) => withErrorHandling(() => Snapshot.get({ ...params })),
7332
- fromSandbox: (name, opts) => withErrorHandling(() => Snapshot.fromSandbox(name, {
7333
- fetch: fetchWithUserAgent,
7334
- ...opts
7335
- })),
7336
7336
  tree: (params) => withErrorHandling(() => Snapshot.tree({
7337
7337
  fetch: fetchWithUserAgent,
7338
7338
  ...params
@@ -7389,9 +7389,9 @@ async function writeResponseToTemp({ response, text }) {
7389
7389
 
7390
7390
  //#endregion
7391
7391
  //#region src/args/snapshot-id.ts
7392
- var import_cjs$20 = /* @__PURE__ */ __toESM(require_cjs());
7392
+ var import_cjs$23 = /* @__PURE__ */ __toESM(require_cjs());
7393
7393
  init_source();
7394
- const snapshotId = import_cjs$20.extendType(import_cjs$20.string, {
7394
+ const snapshotId = import_cjs$23.extendType(import_cjs$23.string, {
7395
7395
  displayName: "snapshot_id",
7396
7396
  description: "The ID of the snapshot",
7397
7397
  async from(s$1) {
@@ -7400,6 +7400,78 @@ const snapshotId = import_cjs$20.extendType(import_cjs$20.string, {
7400
7400
  }
7401
7401
  });
7402
7402
 
7403
+ //#endregion
7404
+ //#region src/args/ports.ts
7405
+ var import_cjs$22 = /* @__PURE__ */ __toESM(require_cjs());
7406
+ init_source();
7407
+ const publishPorts = import_cjs$22.multioption({
7408
+ long: "publish-port",
7409
+ short: "p",
7410
+ description: "Publish sandbox port(s) to DOMAIN.vercel.run",
7411
+ type: import_cjs$22.array(import_cjs$22.extendType(import_cjs$22.number, {
7412
+ displayName: "PORT",
7413
+ async from(number) {
7414
+ if (!Number.isInteger(number) || number < 1024 || number > 65535) throw new Error([
7415
+ `Invalid port: ${number}.`,
7416
+ `${source_default.bold("hint:")} Ports must be integers between 1024-65535 (privileged ports 0-1023 are reserved).`,
7417
+ "Examples: 3000, 8443"
7418
+ ].join("\n"));
7419
+ return number;
7420
+ }
7421
+ }))
7422
+ });
7423
+
7424
+ //#endregion
7425
+ //#region src/types/snapshot-expiration.ts
7426
+ var import_cjs$21 = require_cjs();
7427
+ const SnapshotExpiration = (0, import_cjs$21.extendType)(import_cjs$21.string, {
7428
+ displayName: "DURATION|none",
7429
+ description: "A duration (e.g. 7d, 30d) or \"none\" for no expiration",
7430
+ async from(value) {
7431
+ if (value === "none") return "0";
7432
+ return Duration.from(value);
7433
+ }
7434
+ });
7435
+
7436
+ //#endregion
7437
+ //#region src/args/snapshot-retention.ts
7438
+ var import_cjs$20 = /* @__PURE__ */ __toESM(require_cjs());
7439
+ const snapshotExpiration = import_cjs$20.option({
7440
+ long: "snapshot-expiration",
7441
+ type: import_cjs$20.optional(SnapshotExpiration),
7442
+ description: "Default snapshot expiration. Use \"none\" or 0 for no expiration. Example: 7d, 30d"
7443
+ });
7444
+ const keepLastSnapshots = import_cjs$20.option({
7445
+ long: "keep-last-snapshots",
7446
+ type: import_cjs$20.optional(import_cjs$20.extendType(import_cjs$20.number, {
7447
+ displayName: "COUNT",
7448
+ async from(n) {
7449
+ 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.`);
7450
+ return n;
7451
+ }
7452
+ })),
7453
+ description: "Keep only the N most recent snapshots of this sandbox (1-10)."
7454
+ });
7455
+ const keepLastSnapshotsFor = import_cjs$20.option({
7456
+ long: "keep-last-snapshots-for",
7457
+ type: import_cjs$20.optional(SnapshotExpiration),
7458
+ description: "Expiration applied to kept snapshots. Use \"none\" or 0 for no expiration. Example: 7d, 30d"
7459
+ });
7460
+ const deleteEvictedSnapshots = import_cjs$20.option({
7461
+ long: "delete-evicted-snapshots",
7462
+ type: import_cjs$20.optional({
7463
+ ...import_cjs$20.oneOf(["true", "false"]),
7464
+ displayName: "true|false"
7465
+ }),
7466
+ description: "When \"true\" (the default), evicted snapshots are deleted immediately; when \"false\", they keep the default expiration."
7467
+ });
7468
+ const snapshotRetentionArgs = {
7469
+ snapshotExpiration,
7470
+ keepLastSnapshots,
7471
+ keepLastSnapshotsFor,
7472
+ deleteEvictedSnapshots
7473
+ };
7474
+
7403
7475
  //#endregion
7404
7476
  //#region src/args/sandbox-name.ts
7405
7477
  var import_cjs$19 = /* @__PURE__ */ __toESM(require_cjs());
@@ -11112,15 +11184,15 @@ async function waitForOpen(ws) {
11112
11184
  //#endregion
11113
11185
  //#region src/util/print-command.ts
11114
11186
  init_source();
11115
- function printCommand(command$1, args$4) {
11116
- return source_default.gray(source_default.dim("$ ") + [command$1, ...args$4].join(" "));
11187
+ function printCommand(command$1, args$5) {
11188
+ return source_default.gray(source_default.dim("$ ") + [command$1, ...args$5].join(" "));
11117
11189
  }
11118
11190
 
11119
11191
  //#endregion
11120
11192
  //#region src/interactive-shell/extend-sandbox-timeout.ts
11121
- var import_ms$3 = /* @__PURE__ */ __toESM(require_ms());
11193
+ var import_ms$5 = /* @__PURE__ */ __toESM(require_ms());
11122
11194
  const debug$2 = createDebugger("sandbox:timeout");
11123
- const BUFFER = (0, import_ms$3.default)("10 seconds");
11195
+ const BUFFER = (0, import_ms$5.default)("10 seconds");
11124
11196
  async function extendSandboxTimeoutPeriodically(sandbox, signal) {
11125
11197
  const session = sandbox.currentSession();
11126
11198
  const timeout$1 = session.timeout;
@@ -11135,7 +11207,7 @@ async function extendSandboxTimeoutPeriodically(sandbox, signal) {
11135
11207
  debug$2(`sleeping for ${sleepMs}ms until next timeout extension`);
11136
11208
  await setTimeout$1(sleepMs, null, { signal });
11137
11209
  }
11138
- await sandbox.extendTimeout((0, import_ms$3.default)("5 minutes"));
11210
+ await sandbox.extendTimeout((0, import_ms$5.default)("5 minutes"));
11139
11211
  const updatedTimeout = session.timeout;
11140
11212
  if (updatedTimeout == null) return;
11141
11213
  const nextTick$1 = session.createdAt.getTime() + updatedTimeout;
@@ -11441,7 +11513,7 @@ const ObjectFromKeyValue = import_cjs$18.extendType(import_cjs$18.array(KeyValue
11441
11513
  //#region src/commands/exec.ts
11442
11514
  var import_cjs$17 = /* @__PURE__ */ __toESM(require_cjs());
11443
11515
  init_source();
11444
- const args$3 = {
11516
+ const args$4 = {
11445
11517
  sandbox: import_cjs$17.positional({ type: sandboxName }),
11446
11518
  command: import_cjs$17.positional({
11447
11519
  displayName: "command",
@@ -11495,8 +11567,8 @@ const args$3 = {
11495
11567
  const exec = import_cjs$17.command({
11496
11568
  name: "exec",
11497
11569
  description: "Execute a command in an existing sandbox",
11498
- args: args$3,
11499
- async handler({ command: command$1, cwd, args: args$4, asSudo, sandbox: sandboxName$1, scope: { token: token$1, team: team$1, project: project$1 }, interactive, envVars, skipExtendingTimeout }) {
11570
+ args: args$4,
11571
+ async handler({ command: command$1, cwd, args: args$5, asSudo, sandbox: sandboxName$1, scope: { token: token$1, team: team$1, project: project$1 }, interactive, envVars, skipExtendingTimeout }) {
11500
11572
  const sandbox = typeof sandboxName$1 !== "string" ? sandboxName$1 : await sandboxClient.get({
11501
11573
  name: sandboxName$1,
11502
11574
  projectId: project$1,
@@ -11505,10 +11577,10 @@ const exec = import_cjs$17.command({
11505
11577
  __includeSystemRoutes: true
11506
11578
  });
11507
11579
  if (!interactive) {
11508
- console.error(printCommand(command$1, args$4));
11580
+ console.error(printCommand(command$1, args$5));
11509
11581
  const result = await sandbox.runCommand({
11510
11582
  cmd: command$1,
11511
- args: args$4,
11583
+ args: args$5,
11512
11584
  stderr: process.stderr,
11513
11585
  stdout: process.stdout,
11514
11586
  sudo: asSudo,
@@ -11519,7 +11591,7 @@ const exec = import_cjs$17.command({
11519
11591
  } else await startInteractiveShell({
11520
11592
  sandbox,
11521
11593
  cwd,
11522
- execution: [command$1, ...args$4],
11594
+ execution: [command$1, ...args$5],
11523
11595
  envVars,
11524
11596
  sudo: asSudo,
11525
11597
  skipExtendingTimeout
@@ -11583,8 +11655,8 @@ function resolveMode(networkPolicy$1, mode) {
11583
11655
  /**
11584
11656
  * Builds a NetworkPolicy from CLI arguments.
11585
11657
  */
11586
- function buildNetworkPolicy(args$4) {
11587
- const { networkPolicy: networkPolicy$1, allowedDomains: allowedDomains$1, allowedCIDRs: allowedCIDRs$1, deniedCIDRs: deniedCIDRs$1 } = args$4;
11658
+ function buildNetworkPolicy(args$5) {
11659
+ const { networkPolicy: networkPolicy$1, allowedDomains: allowedDomains$1, allowedCIDRs: allowedCIDRs$1, deniedCIDRs: deniedCIDRs$1 } = args$5;
11588
11660
  const hasListOptions = allowedDomains$1.length > 0 || allowedCIDRs$1.length > 0 || deniedCIDRs$1.length > 0;
11589
11661
  if (networkPolicy$1 && hasListOptions) throw new Error([`Cannot combine --network-policy=${networkPolicy$1} with --allowed-domain, --allowed-cidr, or --denied-cidr.`, `${source_default.bold("hint:")} Use --allowed-domain / --allowed-cidr / --denied-cidr without --network-policy for custom policies.`].join("\n"));
11590
11662
  if (hasListOptions) return {
@@ -11598,162 +11670,152 @@ function buildNetworkPolicy(args$4) {
11598
11670
  }
11599
11671
 
11600
11672
  //#endregion
11601
- //#region src/types/snapshot-expiration.ts
11602
- var import_cjs$15 = require_cjs();
11603
- const SnapshotExpiration = (0, import_cjs$15.extendType)(import_cjs$15.string, {
11604
- displayName: "DURATION|none",
11605
- description: "A duration (e.g. 7d, 30d) or \"none\" for no expiration",
11606
- async from(value) {
11607
- if (value === "none") return "0";
11608
- return Duration.from(value);
11609
- }
11610
- });
11673
+ //#region src/util/keep-last-snapshots.ts
11674
+ var import_ms$4 = /* @__PURE__ */ __toESM(require_ms());
11675
+ init_source();
11676
+ /**
11677
+ * Validates the `--keep-last-snapshots*` flag combination and builds the
11678
+ * payload object that the SDK expects, or returns `undefined` when no
11679
+ * retention policy was configured.
11680
+ *
11681
+ * Throws when `--keep-last-snapshots-for` or `--delete-evicted-snapshots` are
11682
+ * passed without `--keep-last-snapshots`.
11683
+ */
11684
+ function buildKeepLastSnapshotsPayload(input) {
11685
+ const { keepLastSnapshots: keepLastSnapshots$1, keepLastSnapshotsFor: keepLastSnapshotsFor$1, deleteEvictedSnapshots: deleteEvictedSnapshots$1 } = input;
11686
+ if (keepLastSnapshots$1 === void 0 && (keepLastSnapshotsFor$1 !== void 0 || deleteEvictedSnapshots$1 !== 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"));
11687
+ if (keepLastSnapshots$1 === void 0) return;
11688
+ return {
11689
+ count: keepLastSnapshots$1,
11690
+ expiration: keepLastSnapshotsFor$1 !== void 0 ? (0, import_ms$4.default)(keepLastSnapshotsFor$1) : void 0,
11691
+ deleteEvicted: deleteEvictedSnapshots$1 !== void 0 ? deleteEvictedSnapshots$1 === "true" : void 0
11692
+ };
11693
+ }
11694
+
11695
+ //#endregion
11696
+ //#region src/util/print-sandbox-summary.ts
11697
+ init_source();
11698
+ /**
11699
+ * Print the "✅ Sandbox <name> <action>." summary that the create and fork
11700
+ * commands emit after a successful creation, including project/team and any
11701
+ * published port routes.
11702
+ *
11703
+ * - The sandbox name is written to stdout, everything else to stderr — so
11704
+ * `sandbox create | xargs -I {} sandbox exec {} -- ...` keeps working.
11705
+ * - Pass `action: "created"` for create, or `action: \`forked from ${chalk.cyan(source)}\``
11706
+ * for fork.
11707
+ */
11708
+ function printSandboxSummary(opts) {
11709
+ const { sandbox, scope: scope$1, action } = opts;
11710
+ const teamDisplay = scope$1.teamSlug ?? scope$1.team;
11711
+ const projectDisplay = scope$1.projectSlug ?? scope$1.project;
11712
+ const routes = sandbox.routes.filter((x) => x.port !== sandbox.interactivePort);
11713
+ const hasPorts = routes.length > 0;
11714
+ process.stderr.write("✅ Sandbox ");
11715
+ process.stdout.write(source_default.cyan(sandbox.name));
11716
+ process.stderr.write(" " + action + ".\n");
11717
+ process.stderr.write(source_default.dim(" │ ") + "team: " + source_default.cyan(teamDisplay) + "\n");
11718
+ if (hasPorts) {
11719
+ process.stderr.write(source_default.dim(" │ ") + "project: " + source_default.cyan(projectDisplay) + "\n");
11720
+ process.stderr.write(source_default.dim(" │ ") + "ports:\n");
11721
+ for (let i = 0; i < routes.length; i++) {
11722
+ const route = routes[i];
11723
+ const prefix$1 = i === routes.length - 1 ? source_default.dim(" ╰ ") : source_default.dim(" │ ");
11724
+ process.stderr.write(prefix$1 + "• " + route.port + " -> " + source_default.cyan(route.url) + "\n");
11725
+ }
11726
+ } else process.stderr.write(source_default.dim(" ╰ ") + "project: " + source_default.cyan(projectDisplay) + "\n");
11727
+ }
11611
11728
 
11612
11729
  //#endregion
11613
11730
  //#region src/commands/create.ts
11614
- var import_cjs$14 = /* @__PURE__ */ __toESM(require_cjs());
11615
- var import_ms$2 = /* @__PURE__ */ __toESM(require_ms());
11731
+ var import_cjs$15 = /* @__PURE__ */ __toESM(require_cjs());
11732
+ var import_ms$3 = /* @__PURE__ */ __toESM(require_ms());
11616
11733
  init_source();
11617
- const args$2 = {
11618
- name: import_cjs$14.option({
11734
+ const args$3 = {
11735
+ name: import_cjs$15.option({
11619
11736
  long: "name",
11620
11737
  description: "A user-chosen name for the sandbox. It must be unique per project.",
11621
- type: import_cjs$14.optional(import_cjs$14.string)
11738
+ type: import_cjs$15.optional(import_cjs$15.string)
11622
11739
  }),
11623
- nonPersistent: import_cjs$14.flag({
11740
+ nonPersistent: import_cjs$15.flag({
11624
11741
  long: "non-persistent",
11625
11742
  description: "Disable automatic restore of the filesystem between sessions."
11626
11743
  }),
11627
11744
  runtime,
11628
11745
  timeout,
11629
11746
  vcpus,
11630
- ports: import_cjs$14.multioption({
11631
- long: "publish-port",
11632
- short: "p",
11633
- description: "Publish sandbox port(s) to DOMAIN.vercel.run",
11634
- type: import_cjs$14.array(import_cjs$14.extendType(import_cjs$14.number, {
11635
- displayName: "PORT",
11636
- async from(number) {
11637
- if (number < 1024 || number > 65535) throw new Error([
11638
- `Invalid port: ${number}.`,
11639
- `${source_default.bold("hint:")} Ports must be between 1024-65535 (privileged ports 0-1023 are reserved).`,
11640
- "╰▶ Examples: 3000, 8080, 8443"
11641
- ].join("\n"));
11642
- return number;
11643
- }
11644
- }))
11645
- }),
11646
- silent: import_cjs$14.flag({
11747
+ ports: publishPorts,
11748
+ silent: import_cjs$15.flag({
11647
11749
  long: "silent",
11648
11750
  description: "Don't write sandbox name to stdout"
11649
11751
  }),
11650
- snapshot: import_cjs$14.option({
11752
+ snapshot: import_cjs$15.option({
11651
11753
  long: "snapshot",
11652
11754
  short: "s",
11653
11755
  description: "Start the sandbox from a snapshot ID",
11654
- type: import_cjs$14.optional(snapshotId)
11756
+ type: import_cjs$15.optional(snapshotId)
11655
11757
  }),
11656
- sandboxSnapshot: import_cjs$14.option({
11657
- long: "sandbox-snapshot",
11658
- description: "Start the sandbox from another sandbox's current snapshot",
11659
- type: import_cjs$14.optional(sandboxName)
11660
- }),
11661
- connect: import_cjs$14.flag({
11758
+ connect: import_cjs$15.flag({
11662
11759
  long: "connect",
11663
11760
  description: "Start an interactive shell session after creating the sandbox"
11664
11761
  }),
11665
- envVars: import_cjs$14.multioption({
11762
+ envVars: import_cjs$15.multioption({
11666
11763
  long: "env",
11667
11764
  short: "e",
11668
11765
  type: ObjectFromKeyValue,
11669
11766
  description: "Default environment variables for sandbox commands"
11670
11767
  }),
11671
- tags: import_cjs$14.multioption({
11768
+ tags: import_cjs$15.multioption({
11672
11769
  long: "tag",
11673
11770
  short: "t",
11674
11771
  type: ObjectFromKeyValue,
11675
11772
  description: "Key-value tags to associate with the sandbox (e.g. --tag env=staging)"
11676
11773
  }),
11677
- snapshotExpiration: import_cjs$14.option({
11678
- long: "snapshot-expiration",
11679
- type: import_cjs$14.optional(SnapshotExpiration),
11680
- description: "Default snapshot expiration. Use \"none\" or 0 for no expiration. Example: 7d, 30d"
11681
- }),
11682
- keepLastSnapshots: import_cjs$14.option({
11683
- long: "keep-last-snapshots",
11684
- type: import_cjs$14.optional(import_cjs$14.extendType(import_cjs$14.number, {
11685
- displayName: "COUNT",
11686
- async from(n) {
11687
- 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.`);
11688
- return n;
11689
- }
11690
- })),
11691
- description: "Keep only the N most recent snapshots of this sandbox (1-10)."
11692
- }),
11693
- keepLastSnapshotsFor: import_cjs$14.option({
11694
- long: "keep-last-snapshots-for",
11695
- type: import_cjs$14.optional(SnapshotExpiration),
11696
- description: "Expiration applied to kept snapshots. Use \"none\" or 0 for no expiration. Example: 7d, 30d"
11697
- }),
11698
- deleteEvictedSnapshots: import_cjs$14.option({
11699
- long: "delete-evicted-snapshots",
11700
- type: import_cjs$14.optional({
11701
- ...import_cjs$14.oneOf(["true", "false"]),
11702
- displayName: "true|false"
11703
- }),
11704
- description: "When \"true\" (the default), evicted snapshots are deleted immediately; when \"false\", they keep the default expiration."
11705
- }),
11774
+ ...snapshotRetentionArgs,
11706
11775
  ...networkPolicyArgs,
11707
11776
  scope
11708
11777
  };
11709
- const create = import_cjs$14.command({
11778
+ const create = import_cjs$15.command({
11710
11779
  name: "create",
11711
11780
  description: "Create a sandbox in the specified account and project.",
11712
- args: args$2,
11781
+ args: args$3,
11713
11782
  examples: [{
11714
11783
  description: "Create and connect to a sandbox without a network access",
11715
11784
  command: `sandbox run --network-policy=none --connect`
11716
11785
  }],
11717
- 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 }) {
11718
- 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"));
11786
+ 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: snapshotExpiration$1, keepLastSnapshots: keepLastSnapshots$1, keepLastSnapshotsFor: keepLastSnapshotsFor$1, deleteEvictedSnapshots: deleteEvictedSnapshots$1, networkPolicy: networkPolicyMode$1, allowedDomains: allowedDomains$1, allowedCIDRs: allowedCIDRs$1, deniedCIDRs: deniedCIDRs$1 }) {
11719
11787
  const networkPolicy$1 = buildNetworkPolicy({
11720
11788
  networkPolicy: networkPolicyMode$1,
11721
11789
  allowedDomains: allowedDomains$1,
11722
11790
  allowedCIDRs: allowedCIDRs$1,
11723
11791
  deniedCIDRs: deniedCIDRs$1
11724
11792
  });
11725
- 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"));
11726
- const keepLastSnapshotsPayload = keepLastSnapshots !== void 0 ? {
11727
- count: keepLastSnapshots,
11728
- expiration: keepLastSnapshotsFor !== void 0 ? (0, import_ms$2.default)(keepLastSnapshotsFor) : void 0,
11729
- deleteEvicted: deleteEvictedSnapshots !== void 0 ? deleteEvictedSnapshots === "true" : void 0
11730
- } : void 0;
11793
+ const keepLastSnapshotsPayload = buildKeepLastSnapshotsPayload({
11794
+ keepLastSnapshots: keepLastSnapshots$1,
11795
+ keepLastSnapshotsFor: keepLastSnapshotsFor$1,
11796
+ deleteEvictedSnapshots: deleteEvictedSnapshots$1
11797
+ });
11731
11798
  const persistent = !nonPersistent;
11732
11799
  const resources = vcpus$1 ? { vcpus: vcpus$1 } : void 0;
11733
11800
  const tagsObj = Object.keys(tags).length > 0 ? tags : void 0;
11734
- const resolvedSnapshot = snapshot$1 ?? (sandboxSnapshot ? await snapshotClient.fromSandbox(sandboxSnapshot, {
11735
- teamId: scope$1.team,
11736
- projectId: scope$1.project,
11737
- token: scope$1.token
11738
- }) : void 0);
11739
11801
  const spinner = silent ? void 0 : ora("Creating sandbox...").start();
11740
- const sandbox = resolvedSnapshot ? await sandboxClient.create({
11802
+ const sandbox = snapshot$1 ? await sandboxClient.create({
11741
11803
  name,
11742
11804
  source: {
11743
11805
  type: "snapshot",
11744
- snapshotId: resolvedSnapshot
11806
+ snapshotId: snapshot$1
11745
11807
  },
11746
11808
  teamId: scope$1.team,
11747
11809
  projectId: scope$1.project,
11748
11810
  token: scope$1.token,
11749
11811
  ports,
11750
- timeout: (0, import_ms$2.default)(timeout$1),
11812
+ timeout: (0, import_ms$3.default)(timeout$1),
11751
11813
  resources,
11752
11814
  networkPolicy: networkPolicy$1,
11753
11815
  env: envVars,
11754
11816
  tags: tagsObj,
11755
11817
  persistent,
11756
- snapshotExpiration: snapshotExpiration ? (0, import_ms$2.default)(snapshotExpiration) : void 0,
11818
+ snapshotExpiration: snapshotExpiration$1 ? (0, import_ms$3.default)(snapshotExpiration$1) : void 0,
11757
11819
  keepLastSnapshots: keepLastSnapshotsPayload,
11758
11820
  __interactive: true
11759
11821
  }) : await sandboxClient.create({
@@ -11763,13 +11825,13 @@ const create = import_cjs$14.command({
11763
11825
  token: scope$1.token,
11764
11826
  ports,
11765
11827
  runtime: runtime$1,
11766
- timeout: (0, import_ms$2.default)(timeout$1),
11828
+ timeout: (0, import_ms$3.default)(timeout$1),
11767
11829
  resources,
11768
11830
  networkPolicy: networkPolicy$1,
11769
11831
  env: envVars,
11770
11832
  tags: tagsObj,
11771
11833
  persistent,
11772
- snapshotExpiration: snapshotExpiration ? (0, import_ms$2.default)(snapshotExpiration) : void 0,
11834
+ snapshotExpiration: snapshotExpiration$1 ? (0, import_ms$3.default)(snapshotExpiration$1) : void 0,
11773
11835
  keepLastSnapshots: keepLastSnapshotsPayload,
11774
11836
  __interactive: true
11775
11837
  });
@@ -11779,25 +11841,132 @@ const create = import_cjs$14.command({
11779
11841
  `${source_default.bold("hint:")} This is an internal error. Please try again.`,
11780
11842
  "╰▶ Report this issue: https://github.com/vercel/sandbox/issues"
11781
11843
  ].join("\n"));
11782
- const routes = sandbox.routes.filter((x) => x.port !== sandbox.interactivePort);
11783
- if (!silent) {
11784
- const teamDisplay = scope$1.teamSlug ?? scope$1.team;
11785
- const projectDisplay = scope$1.projectSlug ?? scope$1.project;
11786
- const hasPorts = routes.length > 0;
11787
- process.stderr.write("✅ Sandbox ");
11788
- process.stdout.write(source_default.cyan(sandbox.name));
11789
- process.stderr.write(" created.\n");
11790
- process.stderr.write(source_default.dim(" │ ") + "team: " + source_default.cyan(teamDisplay) + "\n");
11791
- if (hasPorts) {
11792
- process.stderr.write(source_default.dim(" │ ") + "project: " + source_default.cyan(projectDisplay) + "\n");
11793
- process.stderr.write(source_default.dim(" │ ") + "ports:\n");
11794
- for (let i = 0; i < routes.length; i++) {
11795
- const route = routes[i];
11796
- const prefix$1 = i === routes.length - 1 ? source_default.dim(" ╰ ") : source_default.dim(" │ ");
11797
- process.stderr.write(prefix$1 + "• " + route.port + " -> " + source_default.cyan(route.url) + "\n");
11798
- }
11799
- } else process.stderr.write(source_default.dim(" ╰ ") + "project: " + source_default.cyan(projectDisplay) + "\n");
11800
- }
11844
+ if (!silent) printSandboxSummary({
11845
+ sandbox,
11846
+ scope: scope$1,
11847
+ action: "created"
11848
+ });
11849
+ if (connect$2) await exec.handler({
11850
+ scope: scope$1,
11851
+ asSudo: false,
11852
+ args: [],
11853
+ cwd: void 0,
11854
+ skipExtendingTimeout: false,
11855
+ envVars: {},
11856
+ command: "sh",
11857
+ interactive: true,
11858
+ tty: true,
11859
+ sandbox
11860
+ });
11861
+ return sandbox;
11862
+ }
11863
+ });
11864
+
11865
+ //#endregion
11866
+ //#region src/commands/fork.ts
11867
+ var import_cjs$14 = /* @__PURE__ */ __toESM(require_cjs());
11868
+ var import_ms$2 = /* @__PURE__ */ __toESM(require_ms());
11869
+ init_source();
11870
+ const args$2 = {
11871
+ source: import_cjs$14.positional({
11872
+ displayName: "source",
11873
+ description: "Name of the source sandbox to fork from.",
11874
+ type: sandboxName
11875
+ }),
11876
+ name: import_cjs$14.option({
11877
+ long: "name",
11878
+ description: "A user-chosen name for the forked sandbox. Must be unique per project.",
11879
+ type: import_cjs$14.optional(import_cjs$14.string)
11880
+ }),
11881
+ nonPersistent: import_cjs$14.flag({
11882
+ long: "non-persistent",
11883
+ description: "Disable automatic restore of the filesystem between sessions."
11884
+ }),
11885
+ timeout: import_cjs$14.option({
11886
+ long: "timeout",
11887
+ type: import_cjs$14.optional(Duration),
11888
+ description: "Override the maximum sandbox runtime (inherited from source if omitted). Example: 5m, 30m"
11889
+ }),
11890
+ vcpus,
11891
+ ports: publishPorts,
11892
+ silent: import_cjs$14.flag({
11893
+ long: "silent",
11894
+ description: "Don't write sandbox name to stdout"
11895
+ }),
11896
+ connect: import_cjs$14.flag({
11897
+ long: "connect",
11898
+ description: "Start an interactive shell session after creating the forked sandbox"
11899
+ }),
11900
+ envVars: import_cjs$14.multioption({
11901
+ long: "env",
11902
+ short: "e",
11903
+ type: ObjectFromKeyValue,
11904
+ description: "Environment variables to set on the fork. Env vars from the source sandbox are not copied (encrypted server-side)."
11905
+ }),
11906
+ tags: import_cjs$14.multioption({
11907
+ long: "tag",
11908
+ short: "t",
11909
+ type: ObjectFromKeyValue,
11910
+ description: "Key-value tags to associate with the fork. When provided, fully replaces the tags copied from the source (no per-key merge)."
11911
+ }),
11912
+ ...snapshotRetentionArgs,
11913
+ ...networkPolicyArgs,
11914
+ scope
11915
+ };
11916
+ const fork = import_cjs$14.command({
11917
+ name: "fork",
11918
+ description: "Fork an existing sandbox into a new one. Copies config (cpu, timeout, network policy, tags, etc.) from the source sandbox; env vars are NOT copied and must be re-supplied via --env.",
11919
+ args: args$2,
11920
+ examples: [{
11921
+ description: "Fork a sandbox with all config copied from the source",
11922
+ command: `sandbox fork my-source`
11923
+ }, {
11924
+ description: "Fork with a specific name and overridden vcpus",
11925
+ command: `sandbox fork my-source --name my-forked-sandbox --vcpus 4`
11926
+ }],
11927
+ async handler({ source, name, nonPersistent, ports, scope: scope$1, timeout: timeout$1, vcpus: vcpus$1, silent, connect: connect$2, envVars, tags, snapshotExpiration: snapshotExpiration$1, keepLastSnapshots: keepLastSnapshots$1, keepLastSnapshotsFor: keepLastSnapshotsFor$1, deleteEvictedSnapshots: deleteEvictedSnapshots$1, networkPolicy: networkPolicyMode$1, allowedDomains: allowedDomains$1, allowedCIDRs: allowedCIDRs$1, deniedCIDRs: deniedCIDRs$1 }) {
11928
+ const networkPolicy$1 = networkPolicyMode$1 !== void 0 || allowedDomains$1.length > 0 || allowedCIDRs$1.length > 0 || deniedCIDRs$1.length > 0 ? buildNetworkPolicy({
11929
+ networkPolicy: networkPolicyMode$1,
11930
+ allowedDomains: allowedDomains$1,
11931
+ allowedCIDRs: allowedCIDRs$1,
11932
+ deniedCIDRs: deniedCIDRs$1
11933
+ }) : void 0;
11934
+ const keepLastSnapshotsPayload = buildKeepLastSnapshotsPayload({
11935
+ keepLastSnapshots: keepLastSnapshots$1,
11936
+ keepLastSnapshotsFor: keepLastSnapshotsFor$1,
11937
+ deleteEvictedSnapshots: deleteEvictedSnapshots$1
11938
+ });
11939
+ const tagsObj = Object.keys(tags).length > 0 ? tags : void 0;
11940
+ const envObj = Object.keys(envVars).length > 0 ? envVars : void 0;
11941
+ const spinner = silent ? void 0 : ora(`Forking sandbox ${source_default.cyan(source)}...`).start();
11942
+ const sandbox = await sandboxClient.fork({
11943
+ sourceSandbox: source,
11944
+ teamId: scope$1.team,
11945
+ projectId: scope$1.project,
11946
+ token: scope$1.token,
11947
+ ...name !== void 0 && { name },
11948
+ ...ports.length > 0 && { ports },
11949
+ ...timeout$1 !== void 0 && { timeout: (0, import_ms$2.default)(timeout$1) },
11950
+ ...vcpus$1 !== void 0 && { resources: { vcpus: vcpus$1 } },
11951
+ ...networkPolicy$1 !== void 0 && { networkPolicy: networkPolicy$1 },
11952
+ ...envObj !== void 0 && { env: envObj },
11953
+ ...tagsObj !== void 0 && { tags: tagsObj },
11954
+ ...nonPersistent && { persistent: false },
11955
+ ...snapshotExpiration$1 !== void 0 && { snapshotExpiration: (0, import_ms$2.default)(snapshotExpiration$1) },
11956
+ ...keepLastSnapshotsPayload !== void 0 && { keepLastSnapshots: keepLastSnapshotsPayload },
11957
+ __interactive: true
11958
+ });
11959
+ spinner?.stop();
11960
+ if (!sandbox.interactivePort) throw new Error([
11961
+ `Sandbox forked but interactive port is missing.`,
11962
+ `${source_default.bold("hint:")} This is an internal error. Please try again.`,
11963
+ "╰▶ Report this issue: https://github.com/vercel/sandbox/issues"
11964
+ ].join("\n"));
11965
+ if (!silent) printSandboxSummary({
11966
+ sandbox,
11967
+ scope: scope$1,
11968
+ action: `forked from ${source_default.cyan(source)}`
11969
+ });
11801
11970
  if (connect$2) await exec.handler({
11802
11971
  scope: scope$1,
11803
11972
  asSudo: false,
@@ -11826,8 +11995,8 @@ function omit(obj, ...keys) {
11826
11995
  //#region src/commands/run.ts
11827
11996
  var import_cjs$13 = /* @__PURE__ */ __toESM(require_cjs());
11828
11997
  const args$1 = {
11829
- ...args$2,
11830
- ...omit(args$3, "sandbox"),
11998
+ ...args$3,
11999
+ ...omit(args$4, "sandbox"),
11831
12000
  removeAfterUse: import_cjs$13.flag({
11832
12001
  long: "rm",
11833
12002
  description: "Automatically remove the sandbox when the command exits."
@@ -12002,14 +12171,14 @@ const connect = import_cjs$11.command({
12002
12171
  name: "connect",
12003
12172
  aliases: ["ssh", "shell"],
12004
12173
  description: "Start an interactive shell in an existing sandbox",
12005
- args: omit(args$3, "command", "args", "interactive", "tty"),
12006
- async handler(args$4) {
12174
+ args: omit(args$4, "command", "args", "interactive", "tty"),
12175
+ async handler(args$5) {
12007
12176
  return exec.handler({
12008
12177
  command: "sh",
12009
12178
  args: [],
12010
12179
  interactive: true,
12011
12180
  tty: true,
12012
- ...args$4
12181
+ ...args$5
12013
12182
  });
12014
12183
  }
12015
12184
  });
@@ -12236,7 +12405,7 @@ var require_eventemitter3 = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.
12236
12405
  EventEmitter$1.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
12237
12406
  var evt = prefix ? prefix + event : event;
12238
12407
  if (!this._events[evt]) return false;
12239
- var listeners = this._events[evt], len = arguments.length, args$4, i;
12408
+ var listeners = this._events[evt], len = arguments.length, args$5, i;
12240
12409
  if (listeners.fn) {
12241
12410
  if (listeners.once) this.removeListener(event, listeners.fn, void 0, true);
12242
12411
  switch (len) {
@@ -12247,8 +12416,8 @@ var require_eventemitter3 = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.
12247
12416
  case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
12248
12417
  case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
12249
12418
  }
12250
- for (i = 1, args$4 = new Array(len - 1); i < len; i++) args$4[i - 1] = arguments[i];
12251
- listeners.fn.apply(listeners.context, args$4);
12419
+ for (i = 1, args$5 = new Array(len - 1); i < len; i++) args$5[i - 1] = arguments[i];
12420
+ listeners.fn.apply(listeners.context, args$5);
12252
12421
  } else {
12253
12422
  var length = listeners.length, j;
12254
12423
  for (i = 0; i < length; i++) {
@@ -12267,8 +12436,8 @@ var require_eventemitter3 = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.
12267
12436
  listeners[i].fn.call(listeners[i].context, a1, a2, a3);
12268
12437
  break;
12269
12438
  default:
12270
- if (!args$4) for (j = 1, args$4 = new Array(len - 1); j < len; j++) args$4[j - 1] = arguments[j];
12271
- listeners[i].fn.apply(listeners[i].context, args$4);
12439
+ if (!args$5) for (j = 1, args$5 = new Array(len - 1); j < len; j++) args$5[j - 1] = arguments[j];
12440
+ listeners[i].fn.apply(listeners[i].context, args$5);
12272
12441
  }
12273
12442
  }
12274
12443
  }
@@ -12681,8 +12850,8 @@ var EventManager = class {
12681
12850
  constructor() {
12682
12851
  this.emitter = new eventemitter3_default();
12683
12852
  }
12684
- emit(dispatch, args$4) {
12685
- this.emitter.emit(dispatch, args$4);
12853
+ emit(dispatch, args$5) {
12854
+ this.emitter.emit(dispatch, args$5);
12686
12855
  }
12687
12856
  on(dispatch, handler) {
12688
12857
  this.emitter.addListener(dispatch, handler);
@@ -12834,9 +13003,9 @@ var ListrLogger = class {
12834
13003
  if (!message) return message;
12835
13004
  return this.applyFormat(`[${message}]`, options);
12836
13005
  }
12837
- splat(...args$4) {
12838
- const message = args$4.shift() ?? "";
12839
- return args$4.length === 0 ? message : splat(message, args$4);
13006
+ splat(...args$5) {
13007
+ const message = args$5.shift() ?? "";
13008
+ return args$5.length === 0 ? message : splat(message, args$5);
12840
13009
  }
12841
13010
  suffix(message, ...suffixes) {
12842
13011
  suffixes.filter(Boolean).forEach((suffix) => {
@@ -12918,12 +13087,12 @@ var ProcessOutputBuffer = class {
12918
13087
  get length() {
12919
13088
  return this.buffer.length;
12920
13089
  }
12921
- write(data, ...args$4) {
12922
- const callback = args$4[args$4.length - 1];
13090
+ write(data, ...args$5) {
13091
+ const callback = args$5[args$5.length - 1];
12923
13092
  this.buffer.push({
12924
13093
  time: Date.now(),
12925
13094
  stream: this.options?.stream,
12926
- entry: this.decoder.write(typeof data === "string" ? Buffer.from(data, typeof args$4[0] === "string" ? args$4[0] : void 0) : Buffer.from(data))
13095
+ entry: this.decoder.write(typeof data === "string" ? Buffer.from(data, typeof args$5[0] === "string" ? args$5[0] : void 0) : Buffer.from(data))
12927
13096
  });
12928
13097
  if (this.options?.limit) this.buffer = this.buffer.slice(-this.options.limit);
12929
13098
  if (typeof callback === "function") callback();
@@ -12951,8 +13120,8 @@ var ProcessOutputStream = class {
12951
13120
  this.buffer.reset();
12952
13121
  return buffer;
12953
13122
  }
12954
- write(...args$4) {
12955
- return this.method.apply(this.stream, args$4);
13123
+ write(...args$5) {
13124
+ return this.method.apply(this.stream, args$5);
12956
13125
  }
12957
13126
  };
12958
13127
  /**
@@ -13815,8 +13984,8 @@ function getRenderer(options) {
13815
13984
  * If the value itself is a function it will evaluate it with the passed in arguments,
13816
13985
  * elsewise it will directly return itself.
13817
13986
  */
13818
- function assertFunctionOrSelf(functionOrSelf, ...args$4) {
13819
- if (typeof functionOrSelf === "function") return functionOrSelf(...args$4);
13987
+ function assertFunctionOrSelf(functionOrSelf, ...args$5) {
13988
+ if (typeof functionOrSelf === "function") return functionOrSelf(...args$5);
13820
13989
  else return functionOrSelf;
13821
13990
  }
13822
13991
  const clone = (0, import_rfdc.default)({ circles: true });
@@ -14596,10 +14765,10 @@ const snapshot = import_cjs$6.command({
14596
14765
  init_source();
14597
14766
  function formatExpires(expiresAt) {
14598
14767
  if (expiresAt === void 0) return source_default.gray("never");
14599
- const ms$4 = expiresAt - Date.now();
14600
- if (ms$4 <= 0) return source_default.red("expired");
14768
+ const ms$6 = expiresAt - Date.now();
14769
+ if (ms$6 <= 0) return source_default.red("expired");
14601
14770
  const formatted = timeAgo(expiresAt);
14602
- return ms$4 <= 3600 * 1e3 ? source_default.red(formatted) : source_default.green(formatted);
14771
+ return ms$6 <= 3600 * 1e3 ? source_default.red(formatted) : source_default.green(formatted);
14603
14772
  }
14604
14773
  function renderNode(id, expiresAt, isCurrent) {
14605
14774
  const bullet = isCurrent ? source_default.magenta.bold("●") : source_default.magenta("●");
@@ -15375,6 +15544,47 @@ const currentSnapshotCommand = import_cjs$1.command({
15375
15544
  }
15376
15545
  }
15377
15546
  });
15547
+ const portsCommand = import_cjs$1.command({
15548
+ name: "ports",
15549
+ description: "Update the published ports of a sandbox. Replaces all existing published ports.",
15550
+ args: {
15551
+ sandbox: import_cjs$1.positional({
15552
+ type: sandboxName,
15553
+ description: "Sandbox name to update"
15554
+ }),
15555
+ ports: publishPorts,
15556
+ scope
15557
+ },
15558
+ async handler({ scope: { token: token$1, team: team$1, project: project$1 }, sandbox: name, ports }) {
15559
+ const sandbox = await sandboxClient.get({
15560
+ name,
15561
+ projectId: project$1,
15562
+ teamId: team$1,
15563
+ token: token$1
15564
+ });
15565
+ const spinner = ora("Updating sandbox ports...").start();
15566
+ try {
15567
+ await sandbox.update({ ports });
15568
+ spinner.stop();
15569
+ process.stderr.write("✅ Ports updated for sandbox " + source_default.cyan(name) + "\n");
15570
+ if (ports.length === 0) process.stderr.write(source_default.dim(" ╰ ") + "all ports unpublished\n");
15571
+ else {
15572
+ const routes = getPublishedRoutes(sandbox);
15573
+ process.stderr.write(source_default.dim(" │ ") + "ports:\n");
15574
+ for (let i = 0; i < ports.length; i++) {
15575
+ const port = ports[i];
15576
+ const route = routes?.find((route$1) => route$1.port === port);
15577
+ const prefix$1 = i === ports.length - 1 ? source_default.dim(" ╰ ") : source_default.dim(" │ ");
15578
+ const url = route ? " -> " + source_default.cyan(route.url) : "";
15579
+ process.stderr.write(prefix$1 + "• " + port + url + "\n");
15580
+ }
15581
+ }
15582
+ } catch (error) {
15583
+ spinner.stop();
15584
+ throw error;
15585
+ }
15586
+ }
15587
+ });
15378
15588
  const listCommand = import_cjs$1.command({
15379
15589
  name: "list",
15380
15590
  description: "Display the current configuration of a sandbox",
@@ -15421,6 +15631,10 @@ const listCommand = import_cjs$1.command({
15421
15631
  field: "Network policy",
15422
15632
  value: String(networkPolicy$1)
15423
15633
  },
15634
+ {
15635
+ field: "Ports",
15636
+ value: formatPorts(sandbox)
15637
+ },
15424
15638
  {
15425
15639
  field: "Snapshot expiration",
15426
15640
  value: sandbox.snapshotExpiration != null && sandbox.snapshotExpiration > 0 ? (0, import_ms.default)(sandbox.snapshotExpiration, { long: true }) : sandbox.snapshotExpiration === 0 ? "none" : "-"
@@ -15533,13 +15747,21 @@ const tagsCommand = import_cjs$1.command({
15533
15747
  }
15534
15748
  }
15535
15749
  });
15536
- function formatKeepLastSnapshots(keepLastSnapshots) {
15537
- if (!keepLastSnapshots) return "-";
15538
- const parts = [`count=${keepLastSnapshots.count}`];
15539
- if (keepLastSnapshots.expiration !== void 0) parts.push(`for=${keepLastSnapshots.expiration === 0 ? "none" : (0, import_ms.default)(keepLastSnapshots.expiration, { long: true })}`);
15540
- if (keepLastSnapshots.deleteEvicted !== void 0) parts.push(`delete-evicted-snapshots=${keepLastSnapshots.deleteEvicted}`);
15750
+ function formatKeepLastSnapshots(keepLastSnapshots$1) {
15751
+ if (!keepLastSnapshots$1) return "-";
15752
+ const parts = [`count=${keepLastSnapshots$1.count}`];
15753
+ if (keepLastSnapshots$1.expiration !== void 0) parts.push(`for=${keepLastSnapshots$1.expiration === 0 ? "none" : (0, import_ms.default)(keepLastSnapshots$1.expiration, { long: true })}`);
15754
+ if (keepLastSnapshots$1.deleteEvicted !== void 0) parts.push(`delete-evicted-snapshots=${keepLastSnapshots$1.deleteEvicted}`);
15541
15755
  return parts.join(", ");
15542
15756
  }
15757
+ function formatPorts(sandbox) {
15758
+ const ports = getPublishedRoutes(sandbox)?.map((route) => route.port) ?? [];
15759
+ if (ports.length === 0) return "-";
15760
+ return ports.join(", ");
15761
+ }
15762
+ function getPublishedRoutes(sandbox) {
15763
+ return sandbox.routes.filter((route) => route.port !== sandbox.interactivePort);
15764
+ }
15543
15765
  const config = import_cjs$1.subcommands({
15544
15766
  name: "config",
15545
15767
  description: "View and update sandbox configuration",
@@ -15554,6 +15776,7 @@ const config = import_cjs$1.subcommands({
15554
15776
  "keep-last-snapshots-for": keepLastSnapshotsForCommand,
15555
15777
  "delete-evicted-snapshots": deleteEvictedSnapshotsCommand,
15556
15778
  "current-snapshot": currentSnapshotCommand,
15779
+ ports: portsCommand,
15557
15780
  tags: tagsCommand
15558
15781
  }
15559
15782
  });
@@ -15568,6 +15791,7 @@ const app = (opts) => (0, import_cjs.subcommands)({
15568
15791
  cmds: {
15569
15792
  list,
15570
15793
  create,
15794
+ fork,
15571
15795
  config,
15572
15796
  copy: cp,
15573
15797
  exec,
@@ -15601,4 +15825,4 @@ const app = (opts) => (0, import_cjs.subcommands)({
15601
15825
 
15602
15826
  //#endregion
15603
15827
  export { source_exports as a, init_source as i, StyledError as n, require_cjs as r, app as t };
15604
- //# sourceMappingURL=app-CpryW0ai.mjs.map
15828
+ //# sourceMappingURL=app-jQvr1S8n.mjs.map