vercel 49.1.1 → 49.2.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 +335 -120
  2. package/package.json +11 -11
package/dist/index.js CHANGED
@@ -34163,7 +34163,7 @@ var init_command32 = __esm({
34163
34163
  deprecated: false
34164
34164
  },
34165
34165
  {
34166
- name: "staged",
34166
+ name: "staging",
34167
34167
  description: "List redirects from the staging version",
34168
34168
  shorthand: null,
34169
34169
  type: Boolean,
@@ -34217,18 +34217,65 @@ var init_command32 = __esm({
34217
34217
  arguments: [
34218
34218
  {
34219
34219
  name: "source",
34220
- required: true
34220
+ required: false
34221
34221
  },
34222
34222
  {
34223
34223
  name: "destination",
34224
- required: true
34224
+ required: false
34225
+ }
34226
+ ],
34227
+ options: [
34228
+ {
34229
+ name: "status",
34230
+ description: "HTTP status code (301, 302, 307, or 308)",
34231
+ shorthand: null,
34232
+ type: Number,
34233
+ argument: "CODE",
34234
+ deprecated: false
34235
+ },
34236
+ {
34237
+ name: "case-sensitive",
34238
+ description: "Make the redirect case sensitive",
34239
+ shorthand: null,
34240
+ type: Boolean,
34241
+ deprecated: false
34242
+ },
34243
+ {
34244
+ name: "preserve-query-params",
34245
+ description: "Preserve query parameters when redirecting",
34246
+ shorthand: null,
34247
+ type: Boolean,
34248
+ deprecated: false
34249
+ },
34250
+ {
34251
+ name: "name",
34252
+ description: "Version name for this redirect (max 256 characters)",
34253
+ shorthand: null,
34254
+ type: String,
34255
+ argument: "NAME",
34256
+ deprecated: false
34257
+ },
34258
+ {
34259
+ ...yesOption,
34260
+ description: "Skip prompts and use default values"
34225
34261
  }
34226
34262
  ],
34227
- options: [],
34228
34263
  examples: [
34229
34264
  {
34230
- name: "Add a new redirect",
34265
+ name: "Add a new redirect interactively",
34266
+ value: `${packageName} redirects add`
34267
+ },
34268
+ {
34269
+ name: "Add a new redirect with arguments",
34231
34270
  value: `${packageName} redirects add /old-path /new-path`
34271
+ },
34272
+ {
34273
+ name: "Add a redirect with all options",
34274
+ value: `${packageName} redirects add /old-path /new-path --status 301 --case-sensitive --preserve-query-params --name "My redirect"`
34275
+ },
34276
+ {
34277
+ name: "Add a redirect non-interactively",
34278
+ value: `${packageName} redirects add /old-path /new-path --yes`
34232
34279
  }
34233
34280
  ]
34234
34281
  };
@@ -35470,6 +35517,20 @@ var init_code = __esm({
35470
35517
  });
35471
35518
 
35472
35519
  // src/util/errors-ts.ts
35520
+ function parseRetryAfterHeaderAsMillis(header) {
35521
+ if (!header)
35522
+ return void 0;
35523
+ let retryAfterMs = Number(header) * 1e3;
35524
+ if (Number.isNaN(retryAfterMs)) {
35525
+ retryAfterMs = Date.parse(header);
35526
+ if (Number.isNaN(retryAfterMs)) {
35527
+ return void 0;
35528
+ } else {
35529
+ retryAfterMs = retryAfterMs - Date.now();
35530
+ }
35531
+ }
35532
+ return Math.max(retryAfterMs, 0);
35533
+ }
35473
35534
  function isAPIError(v) {
35474
35535
  return (0, import_error_utils2.isError)(v) && "status" in v;
35475
35536
  }
@@ -35490,7 +35551,6 @@ var init_errors_ts = __esm({
35490
35551
  this.message = `${message2} (${response.status})`;
35491
35552
  this.status = response.status;
35492
35553
  this.serverMessage = message2;
35493
- this.retryAfter = null;
35494
35554
  if (body) {
35495
35555
  for (const field of Object.keys(body)) {
35496
35556
  if (field !== "message") {
@@ -35498,11 +35558,11 @@ var init_errors_ts = __esm({
35498
35558
  }
35499
35559
  }
35500
35560
  }
35501
- if (response.status === 429) {
35502
- const retryAfter = response.headers.get("Retry-After");
35503
- if (retryAfter) {
35504
- this.retryAfter = parseInt(retryAfter, 10);
35505
- }
35561
+ if (response.status === 429 || response.status === 503) {
35562
+ const parsed = parseRetryAfterHeaderAsMillis(
35563
+ response.headers.get("Retry-After")
35564
+ );
35565
+ this.retryAfterMs = parsed ?? (response.status === 429 ? 0 : void 0);
35506
35566
  }
35507
35567
  }
35508
35568
  };
@@ -35732,10 +35792,10 @@ var init_errors_ts = __esm({
35732
35792
  }
35733
35793
  };
35734
35794
  TooManyRequests = class extends NowError {
35735
- constructor(api, retryAfter) {
35795
+ constructor(api, retryAfterMs) {
35736
35796
  super({
35737
35797
  code: "TOO_MANY_REQUESTS",
35738
- meta: { api, retryAfter },
35798
+ meta: { api, retryAfterMs },
35739
35799
  message: `Rate limited. Too many requests to the same endpoint.`
35740
35800
  });
35741
35801
  }
@@ -44113,11 +44173,11 @@ async function responseError2(res, fallbackMessage = null, parsedBody = {}) {
44113
44173
  }
44114
44174
  }
44115
44175
  }
44116
- if (res.status === 429) {
44117
- const retryAfter = res.headers.get("Retry-After");
44118
- if (retryAfter) {
44119
- err.retryAfter = Number.parseInt(retryAfter, 10);
44120
- }
44176
+ if (res.status === 429 || res.status === 503) {
44177
+ const parsed = parseRetryAfterHeaderAsMillis(
44178
+ res.headers.get("Retry-After")
44179
+ );
44180
+ err.retryAfterMs = parsed ?? (res.status === 429 ? 0 : void 0);
44121
44181
  }
44122
44182
  return err;
44123
44183
  }
@@ -44163,6 +44223,7 @@ var init_error2 = __esm({
44163
44223
  "use strict";
44164
44224
  init_error();
44165
44225
  import_bytes2 = __toESM3(require_bytes());
44226
+ init_errors_ts();
44166
44227
  init_pkg_name();
44167
44228
  init_output_manager();
44168
44229
  }
@@ -91592,6 +91653,22 @@ var init_diff_env_files = __esm({
91592
91653
  }
91593
91654
  });
91594
91655
 
91656
+ // src/util/env/format-env-value.ts
91657
+ function formatEnvValue(value) {
91658
+ if (value == null)
91659
+ return "";
91660
+ const needsQuotes = /\s/.test(value) || value.startsWith("#") || value.startsWith('"');
91661
+ if (!needsQuotes)
91662
+ return value;
91663
+ const escaped = value.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/"/g, '\\"');
91664
+ return `"${escaped}"`;
91665
+ }
91666
+ var init_format_env_value = __esm({
91667
+ "src/util/env/format-env-value.ts"() {
91668
+ "use strict";
91669
+ }
91670
+ });
91671
+
91595
91672
  // ../../node_modules/.pnpm/json-parse-better-errors@1.0.2/node_modules/json-parse-better-errors/index.js
91596
91673
  var require_json_parse_better_errors = __commonJS2({
91597
91674
  "../../node_modules/.pnpm/json-parse-better-errors@1.0.2/node_modules/json-parse-better-errors/index.js"(exports2, module2) {
@@ -91842,7 +91919,7 @@ async function envPullCommandLogic(client2, filename, skipConfirmation, environm
91842
91919
  deltaString = buildDeltaString(oldEnv, newEnv);
91843
91920
  }
91844
91921
  }
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";
91922
+ 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
91923
  await (0, import_fs_extra6.outputFile)(fullPath, contents, "utf8");
91847
91924
  if (deltaString) {
91848
91925
  output_manager_default.print("\n" + deltaString);
@@ -91862,9 +91939,6 @@ async function envPullCommandLogic(client2, filename, skipConfirmation, environm
91862
91939
  `
91863
91940
  );
91864
91941
  }
91865
- function escapeValue(value) {
91866
- return value ? value.replace(new RegExp("\n", "g"), "\\n").replace(new RegExp("\r", "g"), "\\r") : "";
91867
- }
91868
91942
  var import_chalk25, import_fs_extra6, import_fs2, import_path8, import_error_utils4, import_json_parse_better_errors, CONTENTS_PREFIX, VARIABLES_TO_IGNORE;
91869
91943
  var init_pull2 = __esm({
91870
91944
  "src/commands/env/pull.ts"() {
@@ -91879,6 +91953,7 @@ var init_pull2 = __esm({
91879
91953
  init_pkg_name();
91880
91954
  init_get_env_records();
91881
91955
  init_diff_env_files();
91956
+ init_format_env_value();
91882
91957
  import_error_utils4 = __toESM3(require_dist2());
91883
91958
  init_add_to_gitignore();
91884
91959
  import_json_parse_better_errors = __toESM3(require_json_parse_better_errors());
@@ -92621,6 +92696,8 @@ ${error3.stack}`);
92621
92696
  } catch (reauthError) {
92622
92697
  return bail((0, import_error_utils7.normalizeError)(reauthError));
92623
92698
  }
92699
+ } else if (typeof error3.retryAfterMs === "number") {
92700
+ await sleep(error3.retryAfterMs);
92624
92701
  } else if (res.status >= 400 && res.status < 500) {
92625
92702
  return bail(error3);
92626
92703
  }
@@ -126942,7 +127019,7 @@ var init_issue_cert = __esm({
126942
127019
  function mapCertError(error3, cns) {
126943
127020
  const errorCode = error3.code;
126944
127021
  if (errorCode === "too_many_requests") {
126945
- const retryAfter = typeof error3.retryAfter === "number" ? error3.retryAfter : 0;
127022
+ const retryAfter = typeof error3.retryAfterMs === "number" ? error3.retryAfterMs : 0;
126946
127023
  return new TooManyRequests("certificates", retryAfter);
126947
127024
  }
126948
127025
  if (errorCode === "not_found") {
@@ -128289,7 +128366,7 @@ function handleCertError(error3) {
128289
128366
  if (error3 instanceof TooManyRequests) {
128290
128367
  output_manager_default.error(
128291
128368
  `Too many requests detected for ${error3.meta.api} API. Try again in ${(0, import_ms4.default)(
128292
- error3.meta.retryAfter * 1e3,
128369
+ error3.meta.retryAfterMs,
128293
128370
  {
128294
128371
  long: true
128295
128372
  }
@@ -152752,6 +152829,7 @@ var init_util = __esm({
152752
152829
  init_print_indications();
152753
152830
  init_client();
152754
152831
  init_output_manager();
152832
+ init_sleep();
152755
152833
  Now = class {
152756
152834
  constructor({
152757
152835
  client: client2,
@@ -152870,7 +152948,7 @@ var init_util = __esm({
152870
152948
  const err2 = Object.create(APIError.prototype);
152871
152949
  err2.message = error3.message;
152872
152950
  err2.status = error3.status;
152873
- err2.retryAfter = "never";
152951
+ err2.retryAfterMs = "never";
152874
152952
  err2.code = error3.code;
152875
152953
  return err2;
152876
152954
  }
@@ -152885,7 +152963,7 @@ var init_util = __esm({
152885
152963
  const err = Object.create(APIError.prototype);
152886
152964
  err.message = msg;
152887
152965
  err.status = error3.status;
152888
- err.retryAfter = "never";
152966
+ err.retryAfterMs = "never";
152889
152967
  return err;
152890
152968
  }
152891
152969
  if (error3.status === 400 && error3.code === "cert_missing") {
@@ -152932,10 +153010,17 @@ var init_util = __esm({
152932
153010
  method: "DELETE"
152933
153011
  });
152934
153012
  if (res.status === 200) {
152935
- } else if (res.status > 200 && res.status < 500) {
152936
- return bail(await responseError2(res, "Failed to remove deployment"));
152937
153013
  } else {
152938
- throw await responseError2(res, "Failed to remove deployment");
153014
+ const error3 = await responseError2(res, "Failed to remove deployment");
153015
+ if (typeof error3.retryAfterMs === "number") {
153016
+ await sleep(error3.retryAfterMs);
153017
+ throw error3;
153018
+ }
153019
+ if (res.status > 200 && res.status < 500) {
153020
+ return bail(error3);
153021
+ } else {
153022
+ throw error3;
153023
+ }
152939
153024
  }
152940
153025
  });
152941
153026
  return true;
@@ -153008,6 +153093,10 @@ ${err.stack}`);
153008
153093
  return res.headers.get("content-type")?.includes("application/json") ? res.json() : res;
153009
153094
  }
153010
153095
  const err = await responseError2(res);
153096
+ if (typeof err.retryAfterMs === "number") {
153097
+ await sleep(err.retryAfterMs);
153098
+ throw err;
153099
+ }
153011
153100
  if (res.status >= 400 && res.status < 500) {
153012
153101
  return bail(err);
153013
153102
  }
@@ -153528,7 +153617,7 @@ function handleCreateDeployError(error3, localConfig) {
153528
153617
  if (error3 instanceof TooManyRequests) {
153529
153618
  output_manager_default.error(
153530
153619
  `Too many requests detected for ${error3.meta.api} API. Try again in ${(0, import_ms11.default)(
153531
- error3.meta.retryAfter * 1e3,
153620
+ error3.meta.retryAfterMs,
153532
153621
  {
153533
153622
  long: true
153534
153623
  }
@@ -185782,9 +185871,12 @@ async function confirmAction(client2, skipConfirmation, message2, details) {
185782
185871
  return await client2.input.confirm(message2, false);
185783
185872
  }
185784
185873
  function isValidUrl(url3) {
185785
- try {
185786
- new URL(url3, "https://vercel.com");
185874
+ if (url3.startsWith("/")) {
185787
185875
  return true;
185876
+ }
185877
+ try {
185878
+ const parsed = new URL(url3);
185879
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
185788
185880
  } catch {
185789
185881
  return false;
185790
185882
  }
@@ -185862,11 +185954,12 @@ async function list7(client2, argv) {
185862
185954
  const search = flags["--search"];
185863
185955
  const page = flags["--page"];
185864
185956
  const perPage = flags["--per-page"];
185865
- const staged = flags["--staged"];
185957
+ const staging = flags["--staging"];
185866
185958
  const versionIdFlag = flags["--version"];
185867
185959
  let versionId;
185868
185960
  let versionName;
185869
- if (staged) {
185961
+ let useDiff = false;
185962
+ if (staging) {
185870
185963
  output_manager_default.spinner("Fetching staging version");
185871
185964
  const { versions } = await getRedirectVersions(client2, project.id, teamId);
185872
185965
  const stagingVersion = versions.find((v) => v.isStaging);
@@ -185880,10 +185973,13 @@ async function list7(client2, argv) {
185880
185973
  }
185881
185974
  versionId = stagingVersion.id;
185882
185975
  versionName = stagingVersion.name || stagingVersion.id;
185976
+ if (!search && !page) {
185977
+ useDiff = true;
185978
+ }
185883
185979
  }
185884
185980
  if (versionIdFlag) {
185885
- if (staged) {
185886
- output_manager_default.error("Cannot use both --staged and --version flags together");
185981
+ if (staging) {
185982
+ output_manager_default.error("Cannot use both --staging and --version flags together");
185887
185983
  return 1;
185888
185984
  }
185889
185985
  output_manager_default.spinner("Fetching version");
@@ -185916,25 +186012,59 @@ async function list7(client2, argv) {
185916
186012
  search,
185917
186013
  page,
185918
186014
  perPage,
185919
- versionId
186015
+ versionId,
186016
+ diff: useDiff
185920
186017
  });
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");
186018
+ if (useDiff) {
186019
+ const added = redirects.filter((r) => r.action === "+");
186020
+ const removed = redirects.filter((r) => r.action === "-");
186021
+ const unchanged = redirects.filter((r) => !r.action);
186022
+ output_manager_default.log(
186023
+ `Changes in staging version ${import_chalk125.default.bold(versionName || "")} ${import_chalk125.default.gray(lsStamp())}`
186024
+ );
186025
+ if (added.length === 0 && removed.length === 0) {
186026
+ output_manager_default.log("\n No changes from production version\n");
186027
+ } else {
186028
+ if (added.length > 0) {
186029
+ output_manager_default.print(`
186030
+ ${import_chalk125.default.bold(import_chalk125.default.green(`Added (${added.length}):`))}
186031
+ `);
186032
+ output_manager_default.print(formatRedirectsTable(added, "+"));
186033
+ }
186034
+ if (removed.length > 0) {
186035
+ output_manager_default.print(`
186036
+ ${import_chalk125.default.bold(import_chalk125.default.red(`Removed (${removed.length}):`))}
186037
+ `);
186038
+ output_manager_default.print(formatRedirectsTable(removed, "-"));
186039
+ }
186040
+ if (unchanged.length > 0) {
186041
+ output_manager_default.print(
186042
+ `
186043
+ ${import_chalk125.default.gray(`${unchanged.length} redirect${unchanged.length === 1 ? "" : "s"} unchanged`)}
186044
+ `
186045
+ );
186046
+ }
186047
+ output_manager_default.print("\n");
186048
+ }
186049
+ } else {
186050
+ let resultMessage = `${(0, import_pluralize13.default)("Redirect", redirects.length, true)} found for ${import_chalk125.default.bold(
186051
+ project.name
186052
+ )}`;
186053
+ if (versionName) {
186054
+ resultMessage += ` ${import_chalk125.default.gray(`(version: ${versionName})`)}`;
186055
+ }
186056
+ if (search) {
186057
+ resultMessage += ` matching "${search}"`;
186058
+ }
186059
+ if (pagination) {
186060
+ resultMessage += ` ${import_chalk125.default.gray(`(page ${pagination.page} of ${pagination.numPages})`)}`;
186061
+ }
186062
+ resultMessage += ` ${import_chalk125.default.gray(lsStamp())}`;
186063
+ output_manager_default.log(resultMessage);
186064
+ if (redirects.length > 0) {
186065
+ output_manager_default.print(formatRedirectsTable(redirects));
186066
+ output_manager_default.print("\n");
186067
+ }
185938
186068
  }
185939
186069
  if (pagination && pagination.page < pagination.numPages) {
185940
186070
  const nextPage = pagination.page + 1;
@@ -185949,13 +186079,15 @@ async function list7(client2, argv) {
185949
186079
  }
185950
186080
  return 0;
185951
186081
  }
185952
- function formatRedirectsTable(redirects) {
186082
+ function formatRedirectsTable(redirects, actionSymbol) {
185953
186083
  const rows = redirects.map((redirect2) => {
185954
186084
  const status3 = redirect2.statusCode || (redirect2.permanent ? 308 : 307);
186085
+ const prefix = actionSymbol || "";
186086
+ const colorFn = actionSymbol === "+" ? import_chalk125.default.green : actionSymbol === "-" ? import_chalk125.default.red : (s) => s;
185955
186087
  return [
185956
- redirect2.source,
185957
- redirect2.destination,
185958
- import_chalk125.default.cyan(status3.toString())
186088
+ colorFn(`${prefix} ${redirect2.source}`),
186089
+ colorFn(`${redirect2.destination}`),
186090
+ colorFn(status3.toString())
185959
186091
  ];
185960
186092
  });
185961
186093
  return formatTable(
@@ -186128,73 +186260,151 @@ async function add7(client2, argv) {
186128
186260
  const teamId = org.type === "team" ? org.id : void 0;
186129
186261
  const { versions } = await getRedirectVersions(client2, project.id, teamId);
186130
186262
  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;
186263
+ const { args: args2, flags } = parsed;
186264
+ const skipPrompts = flags["--yes"];
186265
+ let source;
186266
+ if (args2[0]) {
186267
+ source = args2[0];
186268
+ if (!isValidUrl(source)) {
186269
+ output_manager_default.error(
186270
+ "Source must be a relative path (starting with /) or an absolute URL"
186271
+ );
186272
+ return 1;
186142
186273
  }
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;
186274
+ } else {
186275
+ if (skipPrompts) {
186276
+ output_manager_default.error(
186277
+ "Source and destination are required when using --yes. Use: vercel redirects add <source> <destination> --yes"
186278
+ );
186279
+ return 1;
186154
186280
  }
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
186281
+ output_manager_default.log("Add a new redirect\n");
186282
+ source = await client2.input.text({
186283
+ message: "What is the source URL?",
186284
+ validate: (val) => {
186285
+ if (!val) {
186286
+ return "Source URL cannot be empty";
186287
+ }
186288
+ if (!isValidUrl(val)) {
186289
+ return "Must be a relative path (starting with /) or an absolute URL";
186290
+ }
186291
+ return true;
186174
186292
  }
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):",
186293
+ });
186294
+ }
186295
+ let destination;
186296
+ if (args2[1]) {
186297
+ destination = args2[1];
186298
+ if (!isValidUrl(destination)) {
186299
+ output_manager_default.error(
186300
+ "Destination must be a relative path (starting with /) or an absolute URL"
186301
+ );
186302
+ return 1;
186303
+ }
186304
+ } else {
186305
+ if (skipPrompts) {
186306
+ output_manager_default.error(
186307
+ "Source and destination are required when using --yes. Use: vercel redirects add <source> <destination> --yes"
186308
+ );
186309
+ return 1;
186310
+ }
186311
+ if (!args2[0]) {
186312
+ output_manager_default.log("Add a new redirect\n");
186313
+ }
186314
+ destination = await client2.input.text({
186315
+ message: "What is the destination URL?",
186189
186316
  validate: (val) => {
186190
- if (val && val.length > 256) {
186191
- return "Name must be 256 characters or less";
186317
+ if (!val) {
186318
+ return "Destination URL cannot be empty";
186319
+ }
186320
+ if (!isValidUrl(val)) {
186321
+ return "Must be a relative path (starting with /) or an absolute URL";
186192
186322
  }
186193
186323
  return true;
186194
186324
  }
186195
186325
  });
186196
- if (!versionName) {
186197
- versionName = void 0;
186326
+ }
186327
+ let statusCode;
186328
+ if (flags["--status"]) {
186329
+ statusCode = flags["--status"];
186330
+ if (![301, 302, 307, 308].includes(statusCode)) {
186331
+ output_manager_default.error("Status code must be 301, 302, 307, or 308");
186332
+ return 1;
186333
+ }
186334
+ } else if (skipPrompts) {
186335
+ statusCode = 307;
186336
+ } else {
186337
+ statusCode = await client2.input.select({
186338
+ message: "Select the status code:",
186339
+ choices: [
186340
+ {
186341
+ name: "307 - Temporary Redirect (preserves request method)",
186342
+ value: 307
186343
+ },
186344
+ {
186345
+ name: "308 - Permanent Redirect (preserves request method)",
186346
+ value: 308
186347
+ },
186348
+ {
186349
+ name: "301 - Moved Permanently (cached by browsers)",
186350
+ value: 301
186351
+ },
186352
+ {
186353
+ name: "302 - Found (temporary redirect, not cached)",
186354
+ value: 302
186355
+ }
186356
+ ]
186357
+ });
186358
+ }
186359
+ let caseSensitive;
186360
+ if (flags["--case-sensitive"] !== void 0) {
186361
+ caseSensitive = flags["--case-sensitive"];
186362
+ } else if (skipPrompts) {
186363
+ caseSensitive = false;
186364
+ } else {
186365
+ caseSensitive = await client2.input.confirm(
186366
+ "Should the redirect be case sensitive?",
186367
+ false
186368
+ );
186369
+ }
186370
+ let preserveQueryParams;
186371
+ if (flags["--preserve-query-params"] !== void 0) {
186372
+ preserveQueryParams = flags["--preserve-query-params"];
186373
+ } else if (skipPrompts) {
186374
+ preserveQueryParams = false;
186375
+ } else {
186376
+ preserveQueryParams = await client2.input.confirm(
186377
+ "Should query parameters be preserved?",
186378
+ false
186379
+ );
186380
+ }
186381
+ let versionName;
186382
+ if (flags["--name"]) {
186383
+ versionName = flags["--name"];
186384
+ if (versionName && versionName.length > 256) {
186385
+ output_manager_default.error("Name must be 256 characters or less");
186386
+ return 1;
186387
+ }
186388
+ } else if (skipPrompts) {
186389
+ versionName = void 0;
186390
+ } else {
186391
+ const provideName = await client2.input.confirm(
186392
+ "Do you want to provide a name for this version?",
186393
+ false
186394
+ );
186395
+ if (provideName) {
186396
+ versionName = await client2.input.text({
186397
+ message: "Version name (max 256 characters):",
186398
+ validate: (val) => {
186399
+ if (val && val.length > 256) {
186400
+ return "Name must be 256 characters or less";
186401
+ }
186402
+ return true;
186403
+ }
186404
+ });
186405
+ if (!versionName) {
186406
+ versionName = void 0;
186407
+ }
186198
186408
  }
186199
186409
  }
186200
186410
  const addStamp = stamp_default();
@@ -186207,7 +186417,8 @@ async function add7(client2, argv) {
186207
186417
  source,
186208
186418
  destination,
186209
186419
  statusCode,
186210
- caseSensitive
186420
+ caseSensitive,
186421
+ preserveQueryParams
186211
186422
  }
186212
186423
  ],
186213
186424
  teamId,
@@ -186223,6 +186434,10 @@ async function add7(client2, argv) {
186223
186434
  `);
186224
186435
  output_manager_default.print(` Case sensitive: ${caseSensitive ? "Yes" : "No"}
186225
186436
  `);
186437
+ output_manager_default.print(
186438
+ ` Preserve query params: ${preserveQueryParams ? "Yes" : "No"}
186439
+ `
186440
+ );
186226
186441
  if (alias2) {
186227
186442
  const testUrl = source.startsWith("/") ? `https://${alias2}${source}` : `https://${alias2}`;
186228
186443
  output_manager_default.print(
@@ -186256,7 +186471,7 @@ async function add7(client2, argv) {
186256
186471
  }
186257
186472
  } else {
186258
186473
  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.`
186474
+ `There are other staged changes. Please review all changes with ${import_chalk127.default.cyan("vercel redirects list --staging")} before promoting to production.`
186260
186475
  );
186261
186476
  }
186262
186477
  return 0;
@@ -186398,7 +186613,7 @@ async function remove5(client2, argv) {
186398
186613
  }
186399
186614
  } else {
186400
186615
  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.`
186616
+ `There are other staged changes. Review them with ${import_chalk128.default.cyan("vercel redirects list --staging")} before promoting to production.`
186402
186617
  );
186403
186618
  }
186404
186619
  return 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vercel",
3
- "version": "49.1.1",
3
+ "version": "49.2.0",
4
4
  "preferGlobal": true,
5
5
  "license": "Apache-2.0",
6
6
  "description": "The command-line interface for Vercel",
@@ -26,25 +26,25 @@
26
26
  "chokidar": "4.0.0",
27
27
  "esbuild": "0.27.0",
28
28
  "jose": "5.9.6",
29
- "@vercel/backends": "0.0.15",
29
+ "@vercel/backends": "0.0.17",
30
30
  "@vercel/build-utils": "13.2.3",
31
31
  "@vercel/detect-agent": "1.0.0",
32
32
  "@vercel/elysia": "0.1.13",
33
- "@vercel/express": "0.1.18",
33
+ "@vercel/fastify": "0.1.16",
34
+ "@vercel/express": "0.1.19",
34
35
  "@vercel/go": "3.2.4",
35
36
  "@vercel/h3": "0.1.22",
36
37
  "@vercel/hono": "0.2.16",
37
- "@vercel/fastify": "0.1.16",
38
38
  "@vercel/hydrogen": "1.3.3",
39
- "@vercel/next": "4.15.8",
40
39
  "@vercel/nestjs": "0.2.17",
40
+ "@vercel/next": "4.15.8",
41
41
  "@vercel/node": "5.5.15",
42
- "@vercel/python": "6.1.1",
43
- "@vercel/redwood": "2.4.6",
44
42
  "@vercel/remix-builder": "5.5.6",
43
+ "@vercel/python": "6.1.2",
45
44
  "@vercel/ruby": "2.2.3",
46
- "@vercel/rust": "1.0.4",
47
- "@vercel/static-build": "2.8.14"
45
+ "@vercel/redwood": "2.4.6",
46
+ "@vercel/static-build": "2.8.14",
47
+ "@vercel/rust": "1.0.4"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@alex_neo/jest-expect-message": "1.0.5",
@@ -169,10 +169,10 @@
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",
172
173
  "@vercel/client": "17.2.15",
173
- "@vercel-internals/types": "3.0.6",
174
174
  "@vercel/error-utils": "2.0.3",
175
- "@vercel-internals/get-package-json": "1.0.0",
175
+ "@vercel-internals/types": "3.0.6",
176
176
  "@vercel/frameworks": "3.15.4",
177
177
  "@vercel/fs-detectors": "5.7.9",
178
178
  "@vercel/routing-utils": "5.3.0"