vercel 49.1.2 → 50.0.0

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.
Files changed (2) hide show
  1. package/dist/index.js +438 -125
  2. package/package.json +14 -14
package/dist/index.js CHANGED
@@ -33066,6 +33066,13 @@ var init_command16 = __esm({
33066
33066
  type: Boolean,
33067
33067
  deprecated: false,
33068
33068
  description: "Prints the build logs instead of the deployment summary"
33069
+ },
33070
+ {
33071
+ name: "json",
33072
+ shorthand: null,
33073
+ type: Boolean,
33074
+ deprecated: false,
33075
+ description: "Output the deployment information as JSON"
33069
33076
  }
33070
33077
  ],
33071
33078
  examples: [
@@ -33088,6 +33095,10 @@ var init_command16 = __esm({
33088
33095
  {
33089
33096
  name: "Get deployment build logs",
33090
33097
  value: `${packageName} inspect my-deployment.vercel.app --logs`
33098
+ },
33099
+ {
33100
+ name: "Get deployment information as JSON",
33101
+ value: `${packageName} inspect my-deployment.vercel.app --json`
33091
33102
  }
33092
33103
  ]
33093
33104
  };
@@ -34163,7 +34174,7 @@ var init_command32 = __esm({
34163
34174
  deprecated: false
34164
34175
  },
34165
34176
  {
34166
- name: "staged",
34177
+ name: "staging",
34167
34178
  description: "List redirects from the staging version",
34168
34179
  shorthand: null,
34169
34180
  type: Boolean,
@@ -34217,18 +34228,65 @@ var init_command32 = __esm({
34217
34228
  arguments: [
34218
34229
  {
34219
34230
  name: "source",
34220
- required: true
34231
+ required: false
34221
34232
  },
34222
34233
  {
34223
34234
  name: "destination",
34224
- required: true
34235
+ required: false
34236
+ }
34237
+ ],
34238
+ options: [
34239
+ {
34240
+ name: "status",
34241
+ description: "HTTP status code (301, 302, 307, or 308)",
34242
+ shorthand: null,
34243
+ type: Number,
34244
+ argument: "CODE",
34245
+ deprecated: false
34246
+ },
34247
+ {
34248
+ name: "case-sensitive",
34249
+ description: "Make the redirect case sensitive",
34250
+ shorthand: null,
34251
+ type: Boolean,
34252
+ deprecated: false
34253
+ },
34254
+ {
34255
+ name: "preserve-query-params",
34256
+ description: "Preserve query parameters when redirecting",
34257
+ shorthand: null,
34258
+ type: Boolean,
34259
+ deprecated: false
34260
+ },
34261
+ {
34262
+ name: "name",
34263
+ description: "Version name for this redirect (max 256 characters)",
34264
+ shorthand: null,
34265
+ type: String,
34266
+ argument: "NAME",
34267
+ deprecated: false
34268
+ },
34269
+ {
34270
+ ...yesOption,
34271
+ description: "Skip prompts and use default values"
34225
34272
  }
34226
34273
  ],
34227
- options: [],
34228
34274
  examples: [
34229
34275
  {
34230
- name: "Add a new redirect",
34276
+ name: "Add a new redirect interactively",
34277
+ value: `${packageName} redirects add`
34278
+ },
34279
+ {
34280
+ name: "Add a new redirect with arguments",
34231
34281
  value: `${packageName} redirects add /old-path /new-path`
34282
+ },
34283
+ {
34284
+ name: "Add a redirect with all options",
34285
+ value: `${packageName} redirects add /old-path /new-path --status 301 --case-sensitive --preserve-query-params --name "My redirect"`
34286
+ },
34287
+ {
34288
+ name: "Add a redirect non-interactively",
34289
+ value: `${packageName} redirects add /old-path /new-path --yes`
34232
34290
  }
34233
34291
  ]
34234
34292
  };
@@ -35470,6 +35528,20 @@ var init_code = __esm({
35470
35528
  });
35471
35529
 
35472
35530
  // src/util/errors-ts.ts
35531
+ function parseRetryAfterHeaderAsMillis(header) {
35532
+ if (!header)
35533
+ return void 0;
35534
+ let retryAfterMs = Number(header) * 1e3;
35535
+ if (Number.isNaN(retryAfterMs)) {
35536
+ retryAfterMs = Date.parse(header);
35537
+ if (Number.isNaN(retryAfterMs)) {
35538
+ return void 0;
35539
+ } else {
35540
+ retryAfterMs = retryAfterMs - Date.now();
35541
+ }
35542
+ }
35543
+ return Math.max(retryAfterMs, 0);
35544
+ }
35473
35545
  function isAPIError(v) {
35474
35546
  return (0, import_error_utils2.isError)(v) && "status" in v;
35475
35547
  }
@@ -35490,7 +35562,6 @@ var init_errors_ts = __esm({
35490
35562
  this.message = `${message2} (${response.status})`;
35491
35563
  this.status = response.status;
35492
35564
  this.serverMessage = message2;
35493
- this.retryAfter = null;
35494
35565
  if (body) {
35495
35566
  for (const field of Object.keys(body)) {
35496
35567
  if (field !== "message") {
@@ -35498,11 +35569,11 @@ var init_errors_ts = __esm({
35498
35569
  }
35499
35570
  }
35500
35571
  }
35501
- if (response.status === 429) {
35502
- const retryAfter = response.headers.get("Retry-After");
35503
- if (retryAfter) {
35504
- this.retryAfter = parseInt(retryAfter, 10);
35505
- }
35572
+ if (response.status === 429 || response.status === 503) {
35573
+ const parsed = parseRetryAfterHeaderAsMillis(
35574
+ response.headers.get("Retry-After")
35575
+ );
35576
+ this.retryAfterMs = parsed ?? (response.status === 429 ? 0 : void 0);
35506
35577
  }
35507
35578
  }
35508
35579
  };
@@ -35732,10 +35803,10 @@ var init_errors_ts = __esm({
35732
35803
  }
35733
35804
  };
35734
35805
  TooManyRequests = class extends NowError {
35735
- constructor(api, retryAfter) {
35806
+ constructor(api, retryAfterMs) {
35736
35807
  super({
35737
35808
  code: "TOO_MANY_REQUESTS",
35738
- meta: { api, retryAfter },
35809
+ meta: { api, retryAfterMs },
35739
35810
  message: `Rate limited. Too many requests to the same endpoint.`
35740
35811
  });
35741
35812
  }
@@ -44113,11 +44184,11 @@ async function responseError2(res, fallbackMessage = null, parsedBody = {}) {
44113
44184
  }
44114
44185
  }
44115
44186
  }
44116
- if (res.status === 429) {
44117
- const retryAfter = res.headers.get("Retry-After");
44118
- if (retryAfter) {
44119
- err.retryAfter = Number.parseInt(retryAfter, 10);
44120
- }
44187
+ if (res.status === 429 || res.status === 503) {
44188
+ const parsed = parseRetryAfterHeaderAsMillis(
44189
+ res.headers.get("Retry-After")
44190
+ );
44191
+ err.retryAfterMs = parsed ?? (res.status === 429 ? 0 : void 0);
44121
44192
  }
44122
44193
  return err;
44123
44194
  }
@@ -44163,6 +44234,7 @@ var init_error2 = __esm({
44163
44234
  "use strict";
44164
44235
  init_error();
44165
44236
  import_bytes2 = __toESM3(require_bytes());
44237
+ init_errors_ts();
44166
44238
  init_pkg_name();
44167
44239
  init_output_manager();
44168
44240
  }
@@ -49985,7 +50057,7 @@ var require_package = __commonJS2({
49985
50057
  "../client/package.json"(exports2, module2) {
49986
50058
  module2.exports = {
49987
50059
  name: "@vercel/client",
49988
- version: "17.2.15",
50060
+ version: "17.2.16",
49989
50061
  main: "dist/index.js",
49990
50062
  typings: "dist/index.d.ts",
49991
50063
  homepage: "https://vercel.com",
@@ -91592,6 +91664,31 @@ var init_diff_env_files = __esm({
91592
91664
  }
91593
91665
  });
91594
91666
 
91667
+ // src/util/env/format-env-value.ts
91668
+ function formatEnvValue(value) {
91669
+ if (value == null)
91670
+ return "";
91671
+ if (!/[\r\n]/.test(value)) {
91672
+ try {
91673
+ const parsed = JSON.parse(value);
91674
+ if (typeof parsed === "object" && parsed !== null) {
91675
+ return value;
91676
+ }
91677
+ } catch {
91678
+ }
91679
+ }
91680
+ const needsQuotes = /\s/.test(value) || value.startsWith("#") || value.startsWith('"');
91681
+ if (!needsQuotes)
91682
+ return value;
91683
+ const escaped = value.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/"/g, '\\"');
91684
+ return `"${escaped}"`;
91685
+ }
91686
+ var init_format_env_value = __esm({
91687
+ "src/util/env/format-env-value.ts"() {
91688
+ "use strict";
91689
+ }
91690
+ });
91691
+
91595
91692
  // ../../node_modules/.pnpm/json-parse-better-errors@1.0.2/node_modules/json-parse-better-errors/index.js
91596
91693
  var require_json_parse_better_errors = __commonJS2({
91597
91694
  "../../node_modules/.pnpm/json-parse-better-errors@1.0.2/node_modules/json-parse-better-errors/index.js"(exports2, module2) {
@@ -91842,7 +91939,7 @@ async function envPullCommandLogic(client2, filename, skipConfirmation, environm
91842
91939
  deltaString = buildDeltaString(oldEnv, newEnv);
91843
91940
  }
91844
91941
  }
91845
- const contents = CONTENTS_PREFIX + Object.keys(records).sort().filter((key) => !VARIABLES_TO_IGNORE.includes(key)).map((key) => `${key}="${escapeValue(records[key])}"`).join("\n") + "\n";
91942
+ const contents = CONTENTS_PREFIX + Object.keys(records).sort().filter((key) => !VARIABLES_TO_IGNORE.includes(key)).map((key) => `${key}=${formatEnvValue(records[key])}`).join("\n") + "\n";
91846
91943
  await (0, import_fs_extra6.outputFile)(fullPath, contents, "utf8");
91847
91944
  if (deltaString) {
91848
91945
  output_manager_default.print("\n" + deltaString);
@@ -91862,9 +91959,6 @@ async function envPullCommandLogic(client2, filename, skipConfirmation, environm
91862
91959
  `
91863
91960
  );
91864
91961
  }
91865
- function escapeValue(value) {
91866
- return value ? value.replace(new RegExp("\n", "g"), "\\n").replace(new RegExp("\r", "g"), "\\r") : "";
91867
- }
91868
91962
  var import_chalk25, import_fs_extra6, import_fs2, import_path8, import_error_utils4, import_json_parse_better_errors, CONTENTS_PREFIX, VARIABLES_TO_IGNORE;
91869
91963
  var init_pull2 = __esm({
91870
91964
  "src/commands/env/pull.ts"() {
@@ -91879,6 +91973,7 @@ var init_pull2 = __esm({
91879
91973
  init_pkg_name();
91880
91974
  init_get_env_records();
91881
91975
  init_diff_env_files();
91976
+ init_format_env_value();
91882
91977
  import_error_utils4 = __toESM3(require_dist2());
91883
91978
  init_add_to_gitignore();
91884
91979
  import_json_parse_better_errors = __toESM3(require_json_parse_better_errors());
@@ -92621,6 +92716,8 @@ ${error3.stack}`);
92621
92716
  } catch (reauthError) {
92622
92717
  return bail((0, import_error_utils7.normalizeError)(reauthError));
92623
92718
  }
92719
+ } else if (typeof error3.retryAfterMs === "number") {
92720
+ await sleep(error3.retryAfterMs);
92624
92721
  } else if (res.status >= 400 && res.status < 500) {
92625
92722
  return bail(error3);
92626
92723
  }
@@ -126942,7 +127039,7 @@ var init_issue_cert = __esm({
126942
127039
  function mapCertError(error3, cns) {
126943
127040
  const errorCode = error3.code;
126944
127041
  if (errorCode === "too_many_requests") {
126945
- const retryAfter = typeof error3.retryAfter === "number" ? error3.retryAfter : 0;
127042
+ const retryAfter = typeof error3.retryAfterMs === "number" ? error3.retryAfterMs : 0;
126946
127043
  return new TooManyRequests("certificates", retryAfter);
126947
127044
  }
126948
127045
  if (errorCode === "not_found") {
@@ -128289,7 +128386,7 @@ function handleCertError(error3) {
128289
128386
  if (error3 instanceof TooManyRequests) {
128290
128387
  output_manager_default.error(
128291
128388
  `Too many requests detected for ${error3.meta.api} API. Try again in ${(0, import_ms4.default)(
128292
- error3.meta.retryAfter * 1e3,
128389
+ error3.meta.retryAfterMs,
128293
128390
  {
128294
128391
  long: true
128295
128392
  }
@@ -134484,6 +134581,9 @@ var require_superstatic = __commonJS2({
134484
134581
  headers: { Location: loc },
134485
134582
  status: status3
134486
134583
  };
134584
+ if (typeof r.env !== "undefined") {
134585
+ route.env = r.env;
134586
+ }
134487
134587
  if (r.has) {
134488
134588
  route.has = r.has;
134489
134589
  }
@@ -134511,6 +134611,9 @@ var require_superstatic = __commonJS2({
134511
134611
  internalParamNames
134512
134612
  );
134513
134613
  const route = { src, dest, check: true };
134614
+ if (typeof r.env !== "undefined") {
134615
+ route.env = r.env;
134616
+ }
134514
134617
  if (r.has) {
134515
134618
  route.has = r.has;
134516
134619
  }
@@ -135429,7 +135532,17 @@ var require_schemas = __commonJS2({
135429
135532
  has: hasSchema,
135430
135533
  missing: hasSchema,
135431
135534
  mitigate: mitigateSchema,
135432
- transforms: transformsSchema
135535
+ transforms: transformsSchema,
135536
+ env: {
135537
+ description: "An array of environment variable names that should be replaced at runtime in the destination or headers",
135538
+ type: "array",
135539
+ minItems: 1,
135540
+ maxItems: 64,
135541
+ items: {
135542
+ type: "string",
135543
+ maxLength: 256
135544
+ }
135545
+ }
135433
135546
  }
135434
135547
  },
135435
135548
  {
@@ -135473,6 +135586,16 @@ var require_schemas = __commonJS2({
135473
135586
  type: "integer",
135474
135587
  minimum: 100,
135475
135588
  maximum: 999
135589
+ },
135590
+ env: {
135591
+ description: "An array of environment variable names that should be replaced at runtime in the destination",
135592
+ type: "array",
135593
+ minItems: 1,
135594
+ maxItems: 64,
135595
+ items: {
135596
+ type: "string",
135597
+ maxLength: 256
135598
+ }
135476
135599
  }
135477
135600
  }
135478
135601
  }
@@ -135509,7 +135632,17 @@ var require_schemas = __commonJS2({
135509
135632
  maximum: 999
135510
135633
  },
135511
135634
  has: hasSchema,
135512
- missing: hasSchema
135635
+ missing: hasSchema,
135636
+ env: {
135637
+ description: "An array of environment variable names that should be replaced at runtime in the destination",
135638
+ type: "array",
135639
+ minItems: 1,
135640
+ maxItems: 64,
135641
+ items: {
135642
+ type: "string",
135643
+ maxLength: 256
135644
+ }
135645
+ }
135513
135646
  }
135514
135647
  }
135515
135648
  };
@@ -152752,6 +152885,7 @@ var init_util = __esm({
152752
152885
  init_print_indications();
152753
152886
  init_client();
152754
152887
  init_output_manager();
152888
+ init_sleep();
152755
152889
  Now = class {
152756
152890
  constructor({
152757
152891
  client: client2,
@@ -152870,7 +153004,7 @@ var init_util = __esm({
152870
153004
  const err2 = Object.create(APIError.prototype);
152871
153005
  err2.message = error3.message;
152872
153006
  err2.status = error3.status;
152873
- err2.retryAfter = "never";
153007
+ err2.retryAfterMs = "never";
152874
153008
  err2.code = error3.code;
152875
153009
  return err2;
152876
153010
  }
@@ -152885,7 +153019,7 @@ var init_util = __esm({
152885
153019
  const err = Object.create(APIError.prototype);
152886
153020
  err.message = msg;
152887
153021
  err.status = error3.status;
152888
- err.retryAfter = "never";
153022
+ err.retryAfterMs = "never";
152889
153023
  return err;
152890
153024
  }
152891
153025
  if (error3.status === 400 && error3.code === "cert_missing") {
@@ -152932,10 +153066,17 @@ var init_util = __esm({
152932
153066
  method: "DELETE"
152933
153067
  });
152934
153068
  if (res.status === 200) {
152935
- } else if (res.status > 200 && res.status < 500) {
152936
- return bail(await responseError2(res, "Failed to remove deployment"));
152937
153069
  } else {
152938
- throw await responseError2(res, "Failed to remove deployment");
153070
+ const error3 = await responseError2(res, "Failed to remove deployment");
153071
+ if (typeof error3.retryAfterMs === "number") {
153072
+ await sleep(error3.retryAfterMs);
153073
+ throw error3;
153074
+ }
153075
+ if (res.status > 200 && res.status < 500) {
153076
+ return bail(error3);
153077
+ } else {
153078
+ throw error3;
153079
+ }
152939
153080
  }
152940
153081
  });
152941
153082
  return true;
@@ -153008,6 +153149,10 @@ ${err.stack}`);
153008
153149
  return res.headers.get("content-type")?.includes("application/json") ? res.json() : res;
153009
153150
  }
153010
153151
  const err = await responseError2(res);
153152
+ if (typeof err.retryAfterMs === "number") {
153153
+ await sleep(err.retryAfterMs);
153154
+ throw err;
153155
+ }
153011
153156
  if (res.status >= 400 && res.status < 500) {
153012
153157
  return bail(err);
153013
153158
  }
@@ -153528,7 +153673,7 @@ function handleCreateDeployError(error3, localConfig) {
153528
153673
  if (error3 instanceof TooManyRequests) {
153529
153674
  output_manager_default.error(
153530
153675
  `Too many requests detected for ${error3.meta.api} API. Try again in ${(0, import_ms11.default)(
153531
- error3.meta.retryAfter * 1e3,
153676
+ error3.meta.retryAfterMs,
153532
153677
  {
153533
153678
  long: true
153534
153679
  }
@@ -179806,6 +179951,11 @@ var init_inspect3 = __esm({
179806
179951
  this.trackCliFlag("wait");
179807
179952
  }
179808
179953
  }
179954
+ trackCliFlagJson(json) {
179955
+ if (json) {
179956
+ this.trackCliFlag("json");
179957
+ }
179958
+ }
179809
179959
  };
179810
179960
  }
179811
179961
  });
@@ -179854,6 +180004,7 @@ async function inspect3(client2) {
179854
180004
  telemetry2.trackCliOptionTimeout(parsedArguments.flags["--timeout"]);
179855
180005
  telemetry2.trackCliFlagLogs(parsedArguments.flags["--logs"]);
179856
180006
  telemetry2.trackCliFlagWait(parsedArguments.flags["--wait"]);
180007
+ telemetry2.trackCliFlagJson(parsedArguments.flags["--json"]);
179857
180008
  const timeout = (0, import_ms19.default)(parsedArguments.flags["--timeout"] ?? "3m");
179858
180009
  if (timeout === void 0) {
179859
180010
  error3(`Invalid timeout "${parsedArguments.flags["--timeout"]}"`);
@@ -179872,6 +180023,7 @@ async function inspect3(client2) {
179872
180023
  const until = Date.now() + timeout;
179873
180024
  const wait3 = parsedArguments.flags["--wait"] ?? false;
179874
180025
  const withLogs = parsedArguments.flags["--logs"];
180026
+ const asJson = parsedArguments.flags["--json"] ?? false;
179875
180027
  const startTimestamp = Date.now();
179876
180028
  try {
179877
180029
  deploymentIdOrHost = new import_url16.URL(deploymentIdOrHost).hostname;
@@ -179882,7 +180034,7 @@ async function inspect3(client2) {
179882
180034
  );
179883
180035
  let deployment = await getDeployment(client2, contextName, deploymentIdOrHost);
179884
180036
  let abortController;
179885
- if (withLogs) {
180037
+ if (withLogs && !asJson) {
179886
180038
  let promise;
179887
180039
  ({ abortController, promise } = displayBuildLogs(client2, deployment, wait3));
179888
180040
  if (wait3) {
@@ -179904,7 +180056,10 @@ async function inspect3(client2) {
179904
180056
  break;
179905
180057
  }
179906
180058
  }
179907
- if (withLogs) {
180059
+ if (asJson) {
180060
+ output_manager_default.stopSpinner();
180061
+ await printJson({ deployment, contextName, client: client2 });
180062
+ } else if (withLogs) {
179908
180063
  print(`${import_chalk103.default.cyan("status")} ${stateString(deployment.readyState)}
179909
180064
  `);
179910
180065
  } else {
@@ -180013,6 +180168,38 @@ async function printDetails({
180013
180168
  `);
180014
180169
  }
180015
180170
  }
180171
+ async function printJson({
180172
+ deployment,
180173
+ contextName,
180174
+ client: client2
180175
+ }) {
180176
+ const {
180177
+ id,
180178
+ name,
180179
+ url: url3,
180180
+ createdAt,
180181
+ routes: routes2,
180182
+ readyState,
180183
+ alias: aliases,
180184
+ target,
180185
+ customEnvironment
180186
+ } = deployment;
180187
+ const { builds } = deployment.version === 2 ? await client2.fetch(`/v11/deployments/${id}/builds`) : { builds: [] };
180188
+ const jsonOutput = {
180189
+ id,
180190
+ name,
180191
+ url: url3,
180192
+ target: customEnvironment?.slug ?? target ?? "preview",
180193
+ readyState,
180194
+ createdAt,
180195
+ ...aliases && aliases.length > 0 && { aliases },
180196
+ ...builds.length > 0 && { builds },
180197
+ ...Array.isArray(routes2) && routes2.length > 0 && { routes: routes2 },
180198
+ ...contextName && { contextName }
180199
+ };
180200
+ client2.stdout.write(`${JSON.stringify(jsonOutput, null, 2)}
180201
+ `);
180202
+ }
180016
180203
  function exitCode(state) {
180017
180204
  if (state === "ERROR" || state === "CANCELED") {
180018
180205
  return 1;
@@ -185782,9 +185969,12 @@ async function confirmAction(client2, skipConfirmation, message2, details) {
185782
185969
  return await client2.input.confirm(message2, false);
185783
185970
  }
185784
185971
  function isValidUrl(url3) {
185785
- try {
185786
- new URL(url3, "https://vercel.com");
185972
+ if (url3.startsWith("/")) {
185787
185973
  return true;
185974
+ }
185975
+ try {
185976
+ const parsed = new URL(url3);
185977
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
185788
185978
  } catch {
185789
185979
  return false;
185790
185980
  }
@@ -185862,11 +186052,12 @@ async function list7(client2, argv) {
185862
186052
  const search = flags["--search"];
185863
186053
  const page = flags["--page"];
185864
186054
  const perPage = flags["--per-page"];
185865
- const staged = flags["--staged"];
186055
+ const staging = flags["--staging"];
185866
186056
  const versionIdFlag = flags["--version"];
185867
186057
  let versionId;
185868
186058
  let versionName;
185869
- if (staged) {
186059
+ let useDiff = false;
186060
+ if (staging) {
185870
186061
  output_manager_default.spinner("Fetching staging version");
185871
186062
  const { versions } = await getRedirectVersions(client2, project.id, teamId);
185872
186063
  const stagingVersion = versions.find((v) => v.isStaging);
@@ -185880,10 +186071,13 @@ async function list7(client2, argv) {
185880
186071
  }
185881
186072
  versionId = stagingVersion.id;
185882
186073
  versionName = stagingVersion.name || stagingVersion.id;
186074
+ if (!search && !page) {
186075
+ useDiff = true;
186076
+ }
185883
186077
  }
185884
186078
  if (versionIdFlag) {
185885
- if (staged) {
185886
- output_manager_default.error("Cannot use both --staged and --version flags together");
186079
+ if (staging) {
186080
+ output_manager_default.error("Cannot use both --staging and --version flags together");
185887
186081
  return 1;
185888
186082
  }
185889
186083
  output_manager_default.spinner("Fetching version");
@@ -185916,25 +186110,59 @@ async function list7(client2, argv) {
185916
186110
  search,
185917
186111
  page,
185918
186112
  perPage,
185919
- versionId
186113
+ versionId,
186114
+ diff: useDiff
185920
186115
  });
185921
- let resultMessage = `${(0, import_pluralize13.default)("Redirect", redirects.length, true)} found for ${import_chalk125.default.bold(
185922
- project.name
185923
- )}`;
185924
- if (versionName) {
185925
- resultMessage += ` ${import_chalk125.default.gray(`(version: ${versionName})`)}`;
185926
- }
185927
- if (search) {
185928
- resultMessage += ` matching "${search}"`;
185929
- }
185930
- if (pagination) {
185931
- resultMessage += ` ${import_chalk125.default.gray(`(page ${pagination.page} of ${pagination.numPages})`)}`;
185932
- }
185933
- resultMessage += ` ${import_chalk125.default.gray(lsStamp())}`;
185934
- output_manager_default.log(resultMessage);
185935
- if (redirects.length > 0) {
185936
- output_manager_default.print(formatRedirectsTable(redirects));
185937
- output_manager_default.print("\n");
186116
+ if (useDiff) {
186117
+ const added = redirects.filter((r) => r.action === "+");
186118
+ const removed = redirects.filter((r) => r.action === "-");
186119
+ const unchanged = redirects.filter((r) => !r.action);
186120
+ output_manager_default.log(
186121
+ `Changes in staging version ${import_chalk125.default.bold(versionName || "")} ${import_chalk125.default.gray(lsStamp())}`
186122
+ );
186123
+ if (added.length === 0 && removed.length === 0) {
186124
+ output_manager_default.log("\n No changes from production version\n");
186125
+ } else {
186126
+ if (added.length > 0) {
186127
+ output_manager_default.print(`
186128
+ ${import_chalk125.default.bold(import_chalk125.default.green(`Added (${added.length}):`))}
186129
+ `);
186130
+ output_manager_default.print(formatRedirectsTable(added, "+"));
186131
+ }
186132
+ if (removed.length > 0) {
186133
+ output_manager_default.print(`
186134
+ ${import_chalk125.default.bold(import_chalk125.default.red(`Removed (${removed.length}):`))}
186135
+ `);
186136
+ output_manager_default.print(formatRedirectsTable(removed, "-"));
186137
+ }
186138
+ if (unchanged.length > 0) {
186139
+ output_manager_default.print(
186140
+ `
186141
+ ${import_chalk125.default.gray(`${unchanged.length} redirect${unchanged.length === 1 ? "" : "s"} unchanged`)}
186142
+ `
186143
+ );
186144
+ }
186145
+ output_manager_default.print("\n");
186146
+ }
186147
+ } else {
186148
+ let resultMessage = `${(0, import_pluralize13.default)("Redirect", redirects.length, true)} found for ${import_chalk125.default.bold(
186149
+ project.name
186150
+ )}`;
186151
+ if (versionName) {
186152
+ resultMessage += ` ${import_chalk125.default.gray(`(version: ${versionName})`)}`;
186153
+ }
186154
+ if (search) {
186155
+ resultMessage += ` matching "${search}"`;
186156
+ }
186157
+ if (pagination) {
186158
+ resultMessage += ` ${import_chalk125.default.gray(`(page ${pagination.page} of ${pagination.numPages})`)}`;
186159
+ }
186160
+ resultMessage += ` ${import_chalk125.default.gray(lsStamp())}`;
186161
+ output_manager_default.log(resultMessage);
186162
+ if (redirects.length > 0) {
186163
+ output_manager_default.print(formatRedirectsTable(redirects));
186164
+ output_manager_default.print("\n");
186165
+ }
185938
186166
  }
185939
186167
  if (pagination && pagination.page < pagination.numPages) {
185940
186168
  const nextPage = pagination.page + 1;
@@ -185949,13 +186177,15 @@ async function list7(client2, argv) {
185949
186177
  }
185950
186178
  return 0;
185951
186179
  }
185952
- function formatRedirectsTable(redirects) {
186180
+ function formatRedirectsTable(redirects, actionSymbol) {
185953
186181
  const rows = redirects.map((redirect2) => {
185954
186182
  const status3 = redirect2.statusCode || (redirect2.permanent ? 308 : 307);
186183
+ const prefix = actionSymbol || "";
186184
+ const colorFn = actionSymbol === "+" ? import_chalk125.default.green : actionSymbol === "-" ? import_chalk125.default.red : (s) => s;
185955
186185
  return [
185956
- redirect2.source,
185957
- redirect2.destination,
185958
- import_chalk125.default.cyan(status3.toString())
186186
+ colorFn(`${prefix} ${redirect2.source}`),
186187
+ colorFn(`${redirect2.destination}`),
186188
+ colorFn(status3.toString())
185959
186189
  ];
185960
186190
  });
185961
186191
  return formatTable(
@@ -186128,73 +186358,151 @@ async function add7(client2, argv) {
186128
186358
  const teamId = org.type === "team" ? org.id : void 0;
186129
186359
  const { versions } = await getRedirectVersions(client2, project.id, teamId);
186130
186360
  const existingStagingVersion = versions.find((v) => v.isStaging);
186131
- output_manager_default.log("Add a new redirect\n");
186132
- const source = await client2.input.text({
186133
- message: "What is the source URL?",
186134
- validate: (val) => {
186135
- if (!val) {
186136
- return "Source URL cannot be empty";
186137
- }
186138
- if (!isValidUrl(val)) {
186139
- return "Must be a relative path (starting with /) or an absolute URL";
186140
- }
186141
- return true;
186361
+ const { args: args2, flags } = parsed;
186362
+ const skipPrompts = flags["--yes"];
186363
+ let source;
186364
+ if (args2[0]) {
186365
+ source = args2[0];
186366
+ if (!isValidUrl(source)) {
186367
+ output_manager_default.error(
186368
+ "Source must be a relative path (starting with /) or an absolute URL"
186369
+ );
186370
+ return 1;
186142
186371
  }
186143
- });
186144
- const destination = await client2.input.text({
186145
- message: "What is the destination URL?",
186146
- validate: (val) => {
186147
- if (!val) {
186148
- return "Destination URL cannot be empty";
186149
- }
186150
- if (!isValidUrl(val)) {
186151
- return "Must be a relative path (starting with /) or an absolute URL";
186152
- }
186153
- return true;
186372
+ } else {
186373
+ if (skipPrompts) {
186374
+ output_manager_default.error(
186375
+ "Source and destination are required when using --yes. Use: vercel redirects add <source> <destination> --yes"
186376
+ );
186377
+ return 1;
186154
186378
  }
186155
- });
186156
- const statusCode = await client2.input.select({
186157
- message: "Select the status code:",
186158
- choices: [
186159
- {
186160
- name: "301 - Moved Permanently (cached by browsers)",
186161
- value: 301
186162
- },
186163
- {
186164
- name: "302 - Found (temporary redirect, not cached)",
186165
- value: 302
186166
- },
186167
- {
186168
- name: "307 - Temporary Redirect (preserves request method)",
186169
- value: 307
186170
- },
186171
- {
186172
- name: "308 - Permanent Redirect (preserves request method)",
186173
- value: 308
186379
+ output_manager_default.log("Add a new redirect\n");
186380
+ source = await client2.input.text({
186381
+ message: "What is the source URL?",
186382
+ validate: (val) => {
186383
+ if (!val) {
186384
+ return "Source URL cannot be empty";
186385
+ }
186386
+ if (!isValidUrl(val)) {
186387
+ return "Must be a relative path (starting with /) or an absolute URL";
186388
+ }
186389
+ return true;
186174
186390
  }
186175
- ]
186176
- });
186177
- const caseSensitive = await client2.input.confirm(
186178
- "Should the redirect be case sensitive?",
186179
- false
186180
- );
186181
- const provideName = await client2.input.confirm(
186182
- "Do you want to provide a name for this version?",
186183
- false
186184
- );
186185
- let versionName;
186186
- if (provideName) {
186187
- versionName = await client2.input.text({
186188
- message: "Version name (max 256 characters):",
186391
+ });
186392
+ }
186393
+ let destination;
186394
+ if (args2[1]) {
186395
+ destination = args2[1];
186396
+ if (!isValidUrl(destination)) {
186397
+ output_manager_default.error(
186398
+ "Destination must be a relative path (starting with /) or an absolute URL"
186399
+ );
186400
+ return 1;
186401
+ }
186402
+ } else {
186403
+ if (skipPrompts) {
186404
+ output_manager_default.error(
186405
+ "Source and destination are required when using --yes. Use: vercel redirects add <source> <destination> --yes"
186406
+ );
186407
+ return 1;
186408
+ }
186409
+ if (!args2[0]) {
186410
+ output_manager_default.log("Add a new redirect\n");
186411
+ }
186412
+ destination = await client2.input.text({
186413
+ message: "What is the destination URL?",
186189
186414
  validate: (val) => {
186190
- if (val && val.length > 256) {
186191
- return "Name must be 256 characters or less";
186415
+ if (!val) {
186416
+ return "Destination URL cannot be empty";
186417
+ }
186418
+ if (!isValidUrl(val)) {
186419
+ return "Must be a relative path (starting with /) or an absolute URL";
186192
186420
  }
186193
186421
  return true;
186194
186422
  }
186195
186423
  });
186196
- if (!versionName) {
186197
- versionName = void 0;
186424
+ }
186425
+ let statusCode;
186426
+ if (flags["--status"]) {
186427
+ statusCode = flags["--status"];
186428
+ if (![301, 302, 307, 308].includes(statusCode)) {
186429
+ output_manager_default.error("Status code must be 301, 302, 307, or 308");
186430
+ return 1;
186431
+ }
186432
+ } else if (skipPrompts) {
186433
+ statusCode = 307;
186434
+ } else {
186435
+ statusCode = await client2.input.select({
186436
+ message: "Select the status code:",
186437
+ choices: [
186438
+ {
186439
+ name: "307 - Temporary Redirect (preserves request method)",
186440
+ value: 307
186441
+ },
186442
+ {
186443
+ name: "308 - Permanent Redirect (preserves request method)",
186444
+ value: 308
186445
+ },
186446
+ {
186447
+ name: "301 - Moved Permanently (cached by browsers)",
186448
+ value: 301
186449
+ },
186450
+ {
186451
+ name: "302 - Found (temporary redirect, not cached)",
186452
+ value: 302
186453
+ }
186454
+ ]
186455
+ });
186456
+ }
186457
+ let caseSensitive;
186458
+ if (flags["--case-sensitive"] !== void 0) {
186459
+ caseSensitive = flags["--case-sensitive"];
186460
+ } else if (skipPrompts) {
186461
+ caseSensitive = false;
186462
+ } else {
186463
+ caseSensitive = await client2.input.confirm(
186464
+ "Should the redirect be case sensitive?",
186465
+ false
186466
+ );
186467
+ }
186468
+ let preserveQueryParams;
186469
+ if (flags["--preserve-query-params"] !== void 0) {
186470
+ preserveQueryParams = flags["--preserve-query-params"];
186471
+ } else if (skipPrompts) {
186472
+ preserveQueryParams = false;
186473
+ } else {
186474
+ preserveQueryParams = await client2.input.confirm(
186475
+ "Should query parameters be preserved?",
186476
+ false
186477
+ );
186478
+ }
186479
+ let versionName;
186480
+ if (flags["--name"]) {
186481
+ versionName = flags["--name"];
186482
+ if (versionName && versionName.length > 256) {
186483
+ output_manager_default.error("Name must be 256 characters or less");
186484
+ return 1;
186485
+ }
186486
+ } else if (skipPrompts) {
186487
+ versionName = void 0;
186488
+ } else {
186489
+ const provideName = await client2.input.confirm(
186490
+ "Do you want to provide a name for this version?",
186491
+ false
186492
+ );
186493
+ if (provideName) {
186494
+ versionName = await client2.input.text({
186495
+ message: "Version name (max 256 characters):",
186496
+ validate: (val) => {
186497
+ if (val && val.length > 256) {
186498
+ return "Name must be 256 characters or less";
186499
+ }
186500
+ return true;
186501
+ }
186502
+ });
186503
+ if (!versionName) {
186504
+ versionName = void 0;
186505
+ }
186198
186506
  }
186199
186507
  }
186200
186508
  const addStamp = stamp_default();
@@ -186207,7 +186515,8 @@ async function add7(client2, argv) {
186207
186515
  source,
186208
186516
  destination,
186209
186517
  statusCode,
186210
- caseSensitive
186518
+ caseSensitive,
186519
+ preserveQueryParams
186211
186520
  }
186212
186521
  ],
186213
186522
  teamId,
@@ -186223,6 +186532,10 @@ async function add7(client2, argv) {
186223
186532
  `);
186224
186533
  output_manager_default.print(` Case sensitive: ${caseSensitive ? "Yes" : "No"}
186225
186534
  `);
186535
+ output_manager_default.print(
186536
+ ` Preserve query params: ${preserveQueryParams ? "Yes" : "No"}
186537
+ `
186538
+ );
186226
186539
  if (alias2) {
186227
186540
  const testUrl = source.startsWith("/") ? `https://${alias2}${source}` : `https://${alias2}`;
186228
186541
  output_manager_default.print(
@@ -186256,7 +186569,7 @@ async function add7(client2, argv) {
186256
186569
  }
186257
186570
  } else {
186258
186571
  output_manager_default.warn(
186259
- `There are other staged changes. Please review all changes with ${import_chalk127.default.cyan("vercel redirects list --staged")} before promoting to production.`
186572
+ `There are other staged changes. Please review all changes with ${import_chalk127.default.cyan("vercel redirects list --staging")} before promoting to production.`
186260
186573
  );
186261
186574
  }
186262
186575
  return 0;
@@ -186398,7 +186711,7 @@ async function remove5(client2, argv) {
186398
186711
  }
186399
186712
  } else {
186400
186713
  output_manager_default.warn(
186401
- `There are other staged changes. Review them with ${import_chalk128.default.cyan("vercel redirects list --staged")} before promoting to production.`
186714
+ `There are other staged changes. Review them with ${import_chalk128.default.cyan("vercel redirects list --staging")} before promoting to production.`
186402
186715
  );
186403
186716
  }
186404
186717
  return 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vercel",
3
- "version": "49.1.2",
3
+ "version": "50.0.0",
4
4
  "preferGlobal": true,
5
5
  "license": "Apache-2.0",
6
6
  "description": "The command-line interface for Vercel",
@@ -26,21 +26,21 @@
26
26
  "chokidar": "4.0.0",
27
27
  "esbuild": "0.27.0",
28
28
  "jose": "5.9.6",
29
- "@vercel/backends": "0.0.16",
29
+ "@vercel/backends": "0.0.17",
30
30
  "@vercel/build-utils": "13.2.3",
31
31
  "@vercel/detect-agent": "1.0.0",
32
- "@vercel/elysia": "0.1.13",
33
- "@vercel/express": "0.1.18",
34
- "@vercel/fastify": "0.1.16",
32
+ "@vercel/fastify": "0.1.17",
35
33
  "@vercel/go": "3.2.4",
36
- "@vercel/h3": "0.1.22",
37
- "@vercel/hono": "0.2.16",
38
- "@vercel/hydrogen": "1.3.3",
34
+ "@vercel/express": "0.1.20",
35
+ "@vercel/h3": "0.1.23",
36
+ "@vercel/elysia": "0.1.14",
37
+ "@vercel/hono": "0.2.17",
39
38
  "@vercel/next": "4.15.8",
40
- "@vercel/nestjs": "0.2.17",
39
+ "@vercel/nestjs": "0.2.18",
40
+ "@vercel/hydrogen": "1.3.3",
41
41
  "@vercel/node": "5.5.15",
42
- "@vercel/python": "6.1.1",
43
42
  "@vercel/redwood": "2.4.6",
43
+ "@vercel/python": "6.1.3",
44
44
  "@vercel/remix-builder": "5.5.6",
45
45
  "@vercel/ruby": "2.2.3",
46
46
  "@vercel/rust": "1.0.4",
@@ -169,12 +169,12 @@
169
169
  "xdg-app-paths": "5.1.0",
170
170
  "yauzl-promise": "2.1.3",
171
171
  "@vercel-internals/constants": "1.0.4",
172
- "@vercel-internals/get-package-json": "1.0.0",
173
172
  "@vercel-internals/types": "3.0.6",
174
- "@vercel/client": "17.2.15",
173
+ "@vercel-internals/get-package-json": "1.0.0",
174
+ "@vercel/client": "17.2.16",
175
175
  "@vercel/frameworks": "3.15.4",
176
- "@vercel/fs-detectors": "5.7.9",
177
- "@vercel/routing-utils": "5.3.0",
176
+ "@vercel/fs-detectors": "5.7.10",
177
+ "@vercel/routing-utils": "5.3.1",
178
178
  "@vercel/error-utils": "2.0.3"
179
179
  },
180
180
  "scripts": {