vercel-cli 48.6.6__py3-none-any.whl → 50.4.6__py3-none-any.whl

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 (34) hide show
  1. vercel_cli/vendor/dist/index.js +70005 -64961
  2. vercel_cli/vendor/dist/vc.js +4 -3
  3. vercel_cli/vendor/node_modules/.package-lock.json +6 -6
  4. vercel_cli/vendor/node_modules/@vercel/build-utils/CHANGELOG.md +132 -0
  5. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/framework-helpers.d.ts +5 -4
  6. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/framework-helpers.js +28 -2
  7. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/node-version.js +8 -3
  8. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/read-config-file.d.ts +6 -0
  9. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/read-config-file.js +11 -0
  10. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/run-user-scripts.d.ts +25 -6
  11. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/run-user-scripts.js +53 -11
  12. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/generate-node-builder-functions.d.ts +8 -2
  13. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/generate-node-builder-functions.js +4 -2
  14. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/index.d.ts +5 -4
  15. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/index.js +2545 -502
  16. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/lambda.d.ts +17 -0
  17. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/lambda.js +11 -1
  18. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/python.d.ts +22 -0
  19. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/python.js +85 -0
  20. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/types.d.ts +9 -0
  21. vercel_cli/vendor/node_modules/@vercel/build-utils/lib/python/ast_parser.py +72 -0
  22. vercel_cli/vendor/node_modules/@vercel/build-utils/lib/python/tests/test_ast_parser.py +72 -0
  23. vercel_cli/vendor/node_modules/@vercel/build-utils/package.json +4 -4
  24. vercel_cli/vendor/node_modules/@vercel/python/dist/index.js +910 -421
  25. vercel_cli/vendor/node_modules/@vercel/python/package.json +3 -3
  26. vercel_cli/vendor/node_modules/@vercel/python/vc_init.py +371 -161
  27. vercel_cli/vendor/node_modules/@vercel/python/vc_init_dev_asgi.py +3 -2
  28. vercel_cli/vendor/package.json +5 -4
  29. {vercel_cli-48.6.6.dist-info → vercel_cli-50.4.6.dist-info}/METADATA +1 -1
  30. {vercel_cli-48.6.6.dist-info → vercel_cli-50.4.6.dist-info}/RECORD +34 -30
  31. {vercel_cli-48.6.6.dist-info → vercel_cli-50.4.6.dist-info}/WHEEL +1 -1
  32. /vercel_cli/vendor/dist/{builder-worker.js → builder-worker.cjs} +0 -0
  33. /vercel_cli/vendor/dist/{get-latest-worker.js → get-latest-worker.cjs} +0 -0
  34. {vercel_cli-48.6.6.dist-info → vercel_cli-50.4.6.dist-info}/entry_points.txt +0 -0
@@ -137,12 +137,12 @@ var require_isexe = __commonJS({
137
137
  if (typeof Promise !== "function") {
138
138
  throw new TypeError("callback not provided");
139
139
  }
140
- return new Promise(function(resolve, reject) {
140
+ return new Promise(function(resolve2, reject) {
141
141
  isexe(path, options || {}, function(er, is) {
142
142
  if (er) {
143
143
  reject(er);
144
144
  } else {
145
- resolve(is);
145
+ resolve2(is);
146
146
  }
147
147
  });
148
148
  });
@@ -423,15 +423,15 @@ var require_readShebang = __commonJS({
423
423
  var require_semver = __commonJS({
424
424
  "../../node_modules/.pnpm/semver@5.7.2/node_modules/semver/semver.js"(exports, module2) {
425
425
  exports = module2.exports = SemVer;
426
- var debug5;
426
+ var debug6;
427
427
  if (typeof process === "object" && process.env && process.env.NODE_DEBUG && /\bsemver\b/i.test(process.env.NODE_DEBUG)) {
428
- debug5 = function() {
428
+ debug6 = function() {
429
429
  var args = Array.prototype.slice.call(arguments, 0);
430
430
  args.unshift("SEMVER");
431
431
  console.log.apply(console, args);
432
432
  };
433
433
  } else {
434
- debug5 = function() {
434
+ debug6 = function() {
435
435
  };
436
436
  }
437
437
  exports.SEMVER_SPEC_VERSION = "2.0.0";
@@ -540,7 +540,7 @@ var require_semver = __commonJS({
540
540
  var STAR = R++;
541
541
  src[STAR] = "(<|>)?=?\\s*\\*";
542
542
  for (i = 0; i < R; i++) {
543
- debug5(i, src[i]);
543
+ debug6(i, src[i]);
544
544
  if (!re[i]) {
545
545
  re[i] = new RegExp(src[i]);
546
546
  safeRe[i] = new RegExp(makeSafeRe(src[i]));
@@ -607,7 +607,7 @@ var require_semver = __commonJS({
607
607
  if (!(this instanceof SemVer)) {
608
608
  return new SemVer(version2, options);
609
609
  }
610
- debug5("SemVer", version2, options);
610
+ debug6("SemVer", version2, options);
611
611
  this.options = options;
612
612
  this.loose = !!options.loose;
613
613
  var m = version2.trim().match(options.loose ? safeRe[LOOSE] : safeRe[FULL]);
@@ -654,7 +654,7 @@ var require_semver = __commonJS({
654
654
  return this.version;
655
655
  };
656
656
  SemVer.prototype.compare = function(other) {
657
- debug5("SemVer.compare", this.version, this.options, other);
657
+ debug6("SemVer.compare", this.version, this.options, other);
658
658
  if (!(other instanceof SemVer)) {
659
659
  other = new SemVer(other, this.options);
660
660
  }
@@ -681,7 +681,7 @@ var require_semver = __commonJS({
681
681
  do {
682
682
  var a = this.prerelease[i2];
683
683
  var b = other.prerelease[i2];
684
- debug5("prerelease compare", i2, a, b);
684
+ debug6("prerelease compare", i2, a, b);
685
685
  if (a === void 0 && b === void 0) {
686
686
  return 0;
687
687
  } else if (b === void 0) {
@@ -935,7 +935,7 @@ var require_semver = __commonJS({
935
935
  return new Comparator(comp, options);
936
936
  }
937
937
  comp = comp.trim().split(/\s+/).join(" ");
938
- debug5("comparator", comp, options);
938
+ debug6("comparator", comp, options);
939
939
  this.options = options;
940
940
  this.loose = !!options.loose;
941
941
  this.parse(comp);
@@ -944,7 +944,7 @@ var require_semver = __commonJS({
944
944
  } else {
945
945
  this.value = this.operator + this.semver.version;
946
946
  }
947
- debug5("comp", this);
947
+ debug6("comp", this);
948
948
  }
949
949
  var ANY = {};
950
950
  Comparator.prototype.parse = function(comp) {
@@ -967,7 +967,7 @@ var require_semver = __commonJS({
967
967
  return this.value;
968
968
  };
969
969
  Comparator.prototype.test = function(version2) {
970
- debug5("Comparator.test", version2, this.options.loose);
970
+ debug6("Comparator.test", version2, this.options.loose);
971
971
  if (this.semver === ANY) {
972
972
  return true;
973
973
  }
@@ -989,10 +989,10 @@ var require_semver = __commonJS({
989
989
  var rangeTmp;
990
990
  if (this.operator === "") {
991
991
  rangeTmp = new Range(comp.value, options);
992
- return satisfies(this.value, rangeTmp, options);
992
+ return satisfies2(this.value, rangeTmp, options);
993
993
  } else if (comp.operator === "") {
994
994
  rangeTmp = new Range(this.value, options);
995
- return satisfies(comp.semver, rangeTmp, options);
995
+ return satisfies2(comp.semver, rangeTmp, options);
996
996
  }
997
997
  var sameDirectionIncreasing = (this.operator === ">=" || this.operator === ">") && (comp.operator === ">=" || comp.operator === ">");
998
998
  var sameDirectionDecreasing = (this.operator === "<=" || this.operator === "<") && (comp.operator === "<=" || comp.operator === "<");
@@ -1050,9 +1050,9 @@ var require_semver = __commonJS({
1050
1050
  var loose = this.options.loose;
1051
1051
  var hr = loose ? safeRe[HYPHENRANGELOOSE] : safeRe[HYPHENRANGE];
1052
1052
  range = range.replace(hr, hyphenReplace);
1053
- debug5("hyphen replace", range);
1053
+ debug6("hyphen replace", range);
1054
1054
  range = range.replace(safeRe[COMPARATORTRIM], comparatorTrimReplace);
1055
- debug5("comparator trim", range, safeRe[COMPARATORTRIM]);
1055
+ debug6("comparator trim", range, safeRe[COMPARATORTRIM]);
1056
1056
  range = range.replace(safeRe[TILDETRIM], tildeTrimReplace);
1057
1057
  range = range.replace(safeRe[CARETTRIM], caretTrimReplace);
1058
1058
  var compRe = loose ? safeRe[COMPARATORLOOSE] : safeRe[COMPARATOR];
@@ -1092,15 +1092,15 @@ var require_semver = __commonJS({
1092
1092
  });
1093
1093
  }
1094
1094
  function parseComparator(comp, options) {
1095
- debug5("comp", comp, options);
1095
+ debug6("comp", comp, options);
1096
1096
  comp = replaceCarets(comp, options);
1097
- debug5("caret", comp);
1097
+ debug6("caret", comp);
1098
1098
  comp = replaceTildes(comp, options);
1099
- debug5("tildes", comp);
1099
+ debug6("tildes", comp);
1100
1100
  comp = replaceXRanges(comp, options);
1101
- debug5("xrange", comp);
1101
+ debug6("xrange", comp);
1102
1102
  comp = replaceStars(comp, options);
1103
- debug5("stars", comp);
1103
+ debug6("stars", comp);
1104
1104
  return comp;
1105
1105
  }
1106
1106
  function isX(id) {
@@ -1114,7 +1114,7 @@ var require_semver = __commonJS({
1114
1114
  function replaceTilde(comp, options) {
1115
1115
  var r = options.loose ? safeRe[TILDELOOSE] : safeRe[TILDE];
1116
1116
  return comp.replace(r, function(_, M, m, p, pr) {
1117
- debug5("tilde", comp, _, M, m, p, pr);
1117
+ debug6("tilde", comp, _, M, m, p, pr);
1118
1118
  var ret;
1119
1119
  if (isX(M)) {
1120
1120
  ret = "";
@@ -1123,12 +1123,12 @@ var require_semver = __commonJS({
1123
1123
  } else if (isX(p)) {
1124
1124
  ret = ">=" + M + "." + m + ".0 <" + M + "." + (+m + 1) + ".0";
1125
1125
  } else if (pr) {
1126
- debug5("replaceTilde pr", pr);
1126
+ debug6("replaceTilde pr", pr);
1127
1127
  ret = ">=" + M + "." + m + "." + p + "-" + pr + " <" + M + "." + (+m + 1) + ".0";
1128
1128
  } else {
1129
1129
  ret = ">=" + M + "." + m + "." + p + " <" + M + "." + (+m + 1) + ".0";
1130
1130
  }
1131
- debug5("tilde return", ret);
1131
+ debug6("tilde return", ret);
1132
1132
  return ret;
1133
1133
  });
1134
1134
  }
@@ -1138,10 +1138,10 @@ var require_semver = __commonJS({
1138
1138
  }).join(" ");
1139
1139
  }
1140
1140
  function replaceCaret(comp, options) {
1141
- debug5("caret", comp, options);
1141
+ debug6("caret", comp, options);
1142
1142
  var r = options.loose ? safeRe[CARETLOOSE] : safeRe[CARET];
1143
1143
  return comp.replace(r, function(_, M, m, p, pr) {
1144
- debug5("caret", comp, _, M, m, p, pr);
1144
+ debug6("caret", comp, _, M, m, p, pr);
1145
1145
  var ret;
1146
1146
  if (isX(M)) {
1147
1147
  ret = "";
@@ -1154,7 +1154,7 @@ var require_semver = __commonJS({
1154
1154
  ret = ">=" + M + "." + m + ".0 <" + (+M + 1) + ".0.0";
1155
1155
  }
1156
1156
  } else if (pr) {
1157
- debug5("replaceCaret pr", pr);
1157
+ debug6("replaceCaret pr", pr);
1158
1158
  if (M === "0") {
1159
1159
  if (m === "0") {
1160
1160
  ret = ">=" + M + "." + m + "." + p + "-" + pr + " <" + M + "." + m + "." + (+p + 1);
@@ -1165,7 +1165,7 @@ var require_semver = __commonJS({
1165
1165
  ret = ">=" + M + "." + m + "." + p + "-" + pr + " <" + (+M + 1) + ".0.0";
1166
1166
  }
1167
1167
  } else {
1168
- debug5("no pr");
1168
+ debug6("no pr");
1169
1169
  if (M === "0") {
1170
1170
  if (m === "0") {
1171
1171
  ret = ">=" + M + "." + m + "." + p + " <" + M + "." + m + "." + (+p + 1);
@@ -1176,12 +1176,12 @@ var require_semver = __commonJS({
1176
1176
  ret = ">=" + M + "." + m + "." + p + " <" + (+M + 1) + ".0.0";
1177
1177
  }
1178
1178
  }
1179
- debug5("caret return", ret);
1179
+ debug6("caret return", ret);
1180
1180
  return ret;
1181
1181
  });
1182
1182
  }
1183
1183
  function replaceXRanges(comp, options) {
1184
- debug5("replaceXRanges", comp, options);
1184
+ debug6("replaceXRanges", comp, options);
1185
1185
  return comp.split(/\s+/).map(function(comp2) {
1186
1186
  return replaceXRange(comp2, options);
1187
1187
  }).join(" ");
@@ -1190,7 +1190,7 @@ var require_semver = __commonJS({
1190
1190
  comp = comp.trim();
1191
1191
  var r = options.loose ? safeRe[XRANGELOOSE] : safeRe[XRANGE];
1192
1192
  return comp.replace(r, function(ret, gtlt, M, m, p, pr) {
1193
- debug5("xRange", comp, ret, gtlt, M, m, p, pr);
1193
+ debug6("xRange", comp, ret, gtlt, M, m, p, pr);
1194
1194
  var xM = isX(M);
1195
1195
  var xm = xM || isX(m);
1196
1196
  var xp = xm || isX(p);
@@ -1233,12 +1233,12 @@ var require_semver = __commonJS({
1233
1233
  } else if (xp) {
1234
1234
  ret = ">=" + M + "." + m + ".0 <" + M + "." + (+m + 1) + ".0";
1235
1235
  }
1236
- debug5("xRange return", ret);
1236
+ debug6("xRange return", ret);
1237
1237
  return ret;
1238
1238
  });
1239
1239
  }
1240
1240
  function replaceStars(comp, options) {
1241
- debug5("replaceStars", comp, options);
1241
+ debug6("replaceStars", comp, options);
1242
1242
  return comp.trim().replace(safeRe[STAR], "");
1243
1243
  }
1244
1244
  function hyphenReplace($0, from, fM, fm, fp, fpr, fb, to, tM, tm, tp, tpr, tb) {
@@ -1286,7 +1286,7 @@ var require_semver = __commonJS({
1286
1286
  }
1287
1287
  if (version2.prerelease.length && !options.includePrerelease) {
1288
1288
  for (i2 = 0; i2 < set.length; i2++) {
1289
- debug5(set[i2].semver);
1289
+ debug6(set[i2].semver);
1290
1290
  if (set[i2].semver === ANY) {
1291
1291
  continue;
1292
1292
  }
@@ -1301,8 +1301,8 @@ var require_semver = __commonJS({
1301
1301
  }
1302
1302
  return true;
1303
1303
  }
1304
- exports.satisfies = satisfies;
1305
- function satisfies(version2, range, options) {
1304
+ exports.satisfies = satisfies2;
1305
+ function satisfies2(version2, range, options) {
1306
1306
  try {
1307
1307
  range = new Range(range, options);
1308
1308
  } catch (er) {
@@ -1430,7 +1430,7 @@ var require_semver = __commonJS({
1430
1430
  default:
1431
1431
  throw new TypeError('Must provide a hilo val of "<" or ">"');
1432
1432
  }
1433
- if (satisfies(version2, range, options)) {
1433
+ if (satisfies2(version2, range, options)) {
1434
1434
  return false;
1435
1435
  }
1436
1436
  for (var i2 = 0; i2 < range.set.length; ++i2) {
@@ -1498,7 +1498,7 @@ var require_parse = __commonJS({
1498
1498
  var escape = require_escape();
1499
1499
  var readShebang = require_readShebang();
1500
1500
  var semver = require_semver();
1501
- var isWin2 = process.platform === "win32";
1501
+ var isWin3 = process.platform === "win32";
1502
1502
  var isExecutableRegExp = /\.(?:com|exe)$/i;
1503
1503
  var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
1504
1504
  var supportsShellOption = niceTry(() => semver.satisfies(process.version, "^4.8.0 || ^5.7.0 || >= 6.0.0", true)) || false;
@@ -1513,7 +1513,7 @@ var require_parse = __commonJS({
1513
1513
  return parsed.file;
1514
1514
  }
1515
1515
  function parseNonShell(parsed) {
1516
- if (!isWin2) {
1516
+ if (!isWin3) {
1517
1517
  return parsed;
1518
1518
  }
1519
1519
  const commandFile = detectShebang(parsed);
@@ -1535,7 +1535,7 @@ var require_parse = __commonJS({
1535
1535
  return parsed;
1536
1536
  }
1537
1537
  const shellCommand = [parsed.command].concat(parsed.args).join(" ");
1538
- if (isWin2) {
1538
+ if (isWin3) {
1539
1539
  parsed.command = typeof parsed.options.shell === "string" ? parsed.options.shell : process.env.comspec || "cmd.exe";
1540
1540
  parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
1541
1541
  parsed.options.windowsVerbatimArguments = true;
@@ -1578,7 +1578,7 @@ var require_parse = __commonJS({
1578
1578
  var require_enoent = __commonJS({
1579
1579
  "../../node_modules/.pnpm/cross-spawn@6.0.5/node_modules/cross-spawn/lib/enoent.js"(exports, module2) {
1580
1580
  "use strict";
1581
- var isWin2 = process.platform === "win32";
1581
+ var isWin3 = process.platform === "win32";
1582
1582
  function notFoundError(original, syscall) {
1583
1583
  return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
1584
1584
  code: "ENOENT",
@@ -1589,7 +1589,7 @@ var require_enoent = __commonJS({
1589
1589
  });
1590
1590
  }
1591
1591
  function hookChildProcess(cp, parsed) {
1592
- if (!isWin2) {
1592
+ if (!isWin3) {
1593
1593
  return;
1594
1594
  }
1595
1595
  const originalEmit = cp.emit;
@@ -1604,13 +1604,13 @@ var require_enoent = __commonJS({
1604
1604
  };
1605
1605
  }
1606
1606
  function verifyENOENT(status, parsed) {
1607
- if (isWin2 && status === 1 && !parsed.file) {
1607
+ if (isWin3 && status === 1 && !parsed.file) {
1608
1608
  return notFoundError(parsed.original, "spawn");
1609
1609
  }
1610
1610
  return null;
1611
1611
  }
1612
1612
  function verifyENOENTSync(status, parsed) {
1613
- if (isWin2 && status === 1 && !parsed.file) {
1613
+ if (isWin3 && status === 1 && !parsed.file) {
1614
1614
  return notFoundError(parsed.original, "spawnSync");
1615
1615
  }
1616
1616
  return null;
@@ -2042,7 +2042,7 @@ var require_get_stream = __commonJS({
2042
2042
  options = Object.assign({ maxBuffer: Infinity }, options);
2043
2043
  const { maxBuffer } = options;
2044
2044
  let stream;
2045
- return new Promise((resolve, reject) => {
2045
+ return new Promise((resolve2, reject) => {
2046
2046
  const rejectPromise = (error) => {
2047
2047
  if (error) {
2048
2048
  error.bufferedData = stream.getBufferedValue();
@@ -2054,7 +2054,7 @@ var require_get_stream = __commonJS({
2054
2054
  rejectPromise(error);
2055
2055
  return;
2056
2056
  }
2057
- resolve();
2057
+ resolve2();
2058
2058
  });
2059
2059
  stream.on("data", () => {
2060
2060
  if (stream.getBufferedLength() > maxBuffer) {
@@ -2078,11 +2078,11 @@ var require_p_finally = __commonJS({
2078
2078
  onFinally = onFinally || (() => {
2079
2079
  });
2080
2080
  return promise.then(
2081
- (val) => new Promise((resolve) => {
2082
- resolve(onFinally());
2081
+ (val) => new Promise((resolve2) => {
2082
+ resolve2(onFinally());
2083
2083
  }).then(() => val),
2084
- (err) => new Promise((resolve) => {
2085
- resolve(onFinally());
2084
+ (err) => new Promise((resolve2) => {
2085
+ resolve2(onFinally());
2086
2086
  }).then(() => {
2087
2087
  throw err;
2088
2088
  })
@@ -2143,7 +2143,7 @@ var require_signal_exit = __commonJS({
2143
2143
  } else {
2144
2144
  assert = require("assert");
2145
2145
  signals = require_signals();
2146
- isWin2 = /^win/i.test(process2.platform);
2146
+ isWin3 = /^win/i.test(process2.platform);
2147
2147
  EE = require("events");
2148
2148
  if (typeof EE !== "function") {
2149
2149
  EE = EE.EventEmitter;
@@ -2215,7 +2215,7 @@ var require_signal_exit = __commonJS({
2215
2215
  unload();
2216
2216
  emit("exit", null, sig);
2217
2217
  emit("afterexit", null, sig);
2218
- if (isWin2 && sig === "SIGHUP") {
2218
+ if (isWin3 && sig === "SIGHUP") {
2219
2219
  sig = "SIGINT";
2220
2220
  }
2221
2221
  process2.kill(process2.pid, sig);
@@ -2272,7 +2272,7 @@ var require_signal_exit = __commonJS({
2272
2272
  }
2273
2273
  var assert;
2274
2274
  var signals;
2275
- var isWin2;
2275
+ var isWin3;
2276
2276
  var EE;
2277
2277
  var emitter;
2278
2278
  var unload;
@@ -2461,8 +2461,8 @@ var require_execa = __commonJS({
2461
2461
  }
2462
2462
  let ret;
2463
2463
  if (!buffer) {
2464
- ret = new Promise((resolve, reject) => {
2465
- process2[stream].once("end", resolve).once("error", reject);
2464
+ ret = new Promise((resolve2, reject) => {
2465
+ process2[stream].once("end", resolve2).once("error", reject);
2466
2466
  });
2467
2467
  } else if (encoding) {
2468
2468
  ret = _getStream(process2[stream], {
@@ -2551,19 +2551,19 @@ ${stderr}${stdout}`;
2551
2551
  spawned.kill(parsed.opts.killSignal);
2552
2552
  }, parsed.opts.timeout);
2553
2553
  }
2554
- const processDone = new Promise((resolve) => {
2554
+ const processDone = new Promise((resolve2) => {
2555
2555
  spawned.on("exit", (code, signal) => {
2556
2556
  cleanup();
2557
- resolve({ code, signal });
2557
+ resolve2({ code, signal });
2558
2558
  });
2559
2559
  spawned.on("error", (err) => {
2560
2560
  cleanup();
2561
- resolve({ error: err });
2561
+ resolve2({ error: err });
2562
2562
  });
2563
2563
  if (spawned.stdin) {
2564
2564
  spawned.stdin.on("error", (err) => {
2565
2565
  cleanup();
2566
- resolve({ error: err });
2566
+ resolve2({ error: err });
2567
2567
  });
2568
2568
  }
2569
2569
  });
@@ -2651,7 +2651,7 @@ ${stderr}${stdout}`;
2651
2651
  var require_lib = __commonJS({
2652
2652
  "../../node_modules/.pnpm/which@3.0.0/node_modules/which/lib/index.js"(exports, module2) {
2653
2653
  var isexe = require_isexe();
2654
- var { join: join5, delimiter, sep, posix } = require("path");
2654
+ var { join: join6, delimiter, sep, posix } = require("path");
2655
2655
  var isWindows = process.platform === "win32";
2656
2656
  var rSlash = new RegExp(`[${posix.sep}${sep === posix.sep ? "" : sep}]`.replace(/(\\)/g, "\\$1"));
2657
2657
  var rRel = new RegExp(`^\\.${rSlash.source}`);
@@ -2680,7 +2680,7 @@ var require_lib = __commonJS({
2680
2680
  var getPathPart = (raw, cmd) => {
2681
2681
  const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw;
2682
2682
  const prefix = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : "";
2683
- return prefix + join5(pathPart, cmd);
2683
+ return prefix + join6(pathPart, cmd);
2684
2684
  };
2685
2685
  var which3 = async (cmd, opt = {}) => {
2686
2686
  const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
@@ -2751,17 +2751,146 @@ module.exports = __toCommonJS(src_exports);
2751
2751
  var import_fs5 = __toESM(require("fs"));
2752
2752
  var import_util = require("util");
2753
2753
  var import_path5 = require("path");
2754
- var import_build_utils5 = require("@vercel/build-utils");
2754
+ var import_build_utils7 = require("@vercel/build-utils");
2755
2755
 
2756
2756
  // src/install.ts
2757
- var import_execa = __toESM(require_execa());
2758
- var import_fs = __toESM(require("fs"));
2757
+ var import_execa2 = __toESM(require_execa());
2758
+ var import_fs2 = __toESM(require("fs"));
2759
2759
  var import_os = __toESM(require("os"));
2760
- var import_path = require("path");
2760
+ var import_path2 = require("path");
2761
2761
  var import_which = __toESM(require_lib());
2762
+ var import_build_utils2 = require("@vercel/build-utils");
2763
+
2764
+ // src/utils.ts
2765
+ var import_fs = __toESM(require("fs"));
2766
+ var import_path = require("path");
2762
2767
  var import_build_utils = require("@vercel/build-utils");
2768
+ var import_execa = __toESM(require_execa());
2763
2769
  var isWin = process.platform === "win32";
2764
- var uvExec = isWin ? "uv.exe" : "uv";
2770
+ var isInVirtualEnv = () => {
2771
+ return process.env.VIRTUAL_ENV;
2772
+ };
2773
+ function getVenvBinDir(venvPath) {
2774
+ return (0, import_path.join)(venvPath, isWin ? "Scripts" : "bin");
2775
+ }
2776
+ function useVirtualEnv(workPath, env, systemPython) {
2777
+ const venvDirs = [".venv", "venv"];
2778
+ let pythonCmd = systemPython;
2779
+ for (const venv of venvDirs) {
2780
+ const venvRoot = (0, import_path.join)(workPath, venv);
2781
+ const binDir = process.platform === "win32" ? (0, import_path.join)(venvRoot, "Scripts") : (0, import_path.join)(venvRoot, "bin");
2782
+ const candidates = process.platform === "win32" ? [(0, import_path.join)(binDir, "python.exe"), (0, import_path.join)(binDir, "python")] : [(0, import_path.join)(binDir, "python3"), (0, import_path.join)(binDir, "python")];
2783
+ const found = candidates.find((p) => import_fs.default.existsSync(p));
2784
+ if (found) {
2785
+ pythonCmd = found;
2786
+ env.VIRTUAL_ENV = venvRoot;
2787
+ env.PATH = `${binDir}${import_path.delimiter}${env.PATH || ""}`;
2788
+ return { pythonCmd, venvRoot };
2789
+ }
2790
+ }
2791
+ return { pythonCmd };
2792
+ }
2793
+ function createVenvEnv(venvPath, baseEnv = process.env) {
2794
+ const env = { ...baseEnv, VIRTUAL_ENV: venvPath };
2795
+ const binDir = getVenvBinDir(venvPath);
2796
+ const existingPath = env.PATH || process.env.PATH || "";
2797
+ env.PATH = existingPath ? `${binDir}${import_path.delimiter}${existingPath}` : binDir;
2798
+ return env;
2799
+ }
2800
+ async function ensureVenv({
2801
+ pythonPath,
2802
+ venvPath
2803
+ }) {
2804
+ const marker = (0, import_path.join)(venvPath, "pyvenv.cfg");
2805
+ try {
2806
+ await import_fs.default.promises.access(marker);
2807
+ return;
2808
+ } catch {
2809
+ }
2810
+ await import_fs.default.promises.mkdir(venvPath, { recursive: true });
2811
+ console.log(`Creating virtual environment at "${venvPath}"...`);
2812
+ await (0, import_execa.default)(pythonPath, ["-m", "venv", venvPath]);
2813
+ }
2814
+ function getVenvPythonBin(venvPath) {
2815
+ return (0, import_path.join)(getVenvBinDir(venvPath), isWin ? "python.exe" : "python");
2816
+ }
2817
+ async function runPyprojectScript(workPath, scriptNames, env, useUserVirtualEnv = true) {
2818
+ const pyprojectPath = (0, import_path.join)(workPath, "pyproject.toml");
2819
+ if (!import_fs.default.existsSync(pyprojectPath))
2820
+ return false;
2821
+ let pyproject = null;
2822
+ try {
2823
+ pyproject = await (0, import_build_utils.readConfigFile)(pyprojectPath);
2824
+ } catch {
2825
+ console.error("Failed to parse pyproject.toml");
2826
+ return false;
2827
+ }
2828
+ const scripts = pyproject?.tool?.vercel?.scripts || {};
2829
+ const candidates = typeof scriptNames === "string" ? [scriptNames] : Array.from(scriptNames);
2830
+ const scriptToRun = candidates.find((name) => Boolean(scripts[name]));
2831
+ if (!scriptToRun)
2832
+ return false;
2833
+ const systemPython = process.platform === "win32" ? "python" : "python3";
2834
+ const finalEnv = { ...process.env, ...env };
2835
+ if (useUserVirtualEnv) {
2836
+ useVirtualEnv(workPath, finalEnv, systemPython);
2837
+ }
2838
+ const scriptCommand = scripts[scriptToRun];
2839
+ if (typeof scriptCommand === "string" && scriptCommand.trim()) {
2840
+ console.log(`Executing: ${scriptCommand}`);
2841
+ await (0, import_build_utils.execCommand)(scriptCommand, {
2842
+ cwd: workPath,
2843
+ env: finalEnv
2844
+ });
2845
+ return true;
2846
+ }
2847
+ return false;
2848
+ }
2849
+ async function runUvCommand(options) {
2850
+ const { uvPath, args, cwd, venvPath } = options;
2851
+ const pretty = `uv ${args.join(" ")}`;
2852
+ (0, import_build_utils.debug)(`Running "${pretty}"...`);
2853
+ if (!uvPath) {
2854
+ throw new Error(`uv is required to run "${pretty}" but is not available`);
2855
+ }
2856
+ try {
2857
+ await (0, import_execa.default)(uvPath, args, {
2858
+ cwd,
2859
+ env: createVenvEnv(venvPath)
2860
+ });
2861
+ return true;
2862
+ } catch (err) {
2863
+ const error = new Error(
2864
+ `Failed to run "${pretty}": ${err instanceof Error ? err.message : String(err)}`
2865
+ );
2866
+ if (err && typeof err === "object") {
2867
+ if ("code" in err) {
2868
+ error.code = err.code;
2869
+ } else if ("signal" in err) {
2870
+ error.code = err.signal;
2871
+ }
2872
+ }
2873
+ throw error;
2874
+ }
2875
+ }
2876
+ function findDir({
2877
+ file,
2878
+ entryDirectory,
2879
+ workPath,
2880
+ fsFiles
2881
+ }) {
2882
+ if (fsFiles[(0, import_path.join)(entryDirectory, file)]) {
2883
+ return (0, import_path.join)(workPath, entryDirectory);
2884
+ }
2885
+ if (fsFiles[file]) {
2886
+ return workPath;
2887
+ }
2888
+ return null;
2889
+ }
2890
+
2891
+ // src/install.ts
2892
+ var isWin2 = process.platform === "win32";
2893
+ var uvExec = isWin2 ? "uv.exe" : "uv";
2765
2894
  var makeDependencyCheckCode = (dependency) => `
2766
2895
  from importlib import util
2767
2896
  dep = '${dependency}'.replace('-', '_')
@@ -2770,13 +2899,13 @@ print(spec.origin)
2770
2899
  `;
2771
2900
  async function isInstalled(pythonPath, dependency, cwd) {
2772
2901
  try {
2773
- const { stdout } = await (0, import_execa.default)(
2902
+ const { stdout } = await (0, import_execa2.default)(
2774
2903
  pythonPath,
2775
2904
  ["-c", makeDependencyCheckCode(dependency)],
2776
2905
  {
2777
2906
  stdio: "pipe",
2778
2907
  cwd,
2779
- env: { ...process.env, PYTHONPATH: (0, import_path.join)(cwd, resolveVendorDir()) }
2908
+ env: { ...process.env, PYTHONPATH: (0, import_path2.join)(cwd, resolveVendorDir()) }
2780
2909
  }
2781
2910
  );
2782
2911
  return stdout.startsWith(cwd);
@@ -2793,13 +2922,13 @@ pkg_resources.require(dependencies)
2793
2922
  `;
2794
2923
  async function areRequirementsInstalled(pythonPath, requirementsPath, cwd) {
2795
2924
  try {
2796
- await (0, import_execa.default)(
2925
+ await (0, import_execa2.default)(
2797
2926
  pythonPath,
2798
2927
  ["-c", makeRequirementsCheckCode(requirementsPath)],
2799
2928
  {
2800
2929
  stdio: "pipe",
2801
2930
  cwd,
2802
- env: { ...process.env, PYTHONPATH: (0, import_path.join)(cwd, resolveVendorDir()) }
2931
+ env: { ...process.env, PYTHONPATH: (0, import_path2.join)(cwd, resolveVendorDir()) }
2803
2932
  }
2804
2933
  );
2805
2934
  return true;
@@ -2807,18 +2936,354 @@ async function areRequirementsInstalled(pythonPath, requirementsPath, cwd) {
2807
2936
  return false;
2808
2937
  }
2809
2938
  }
2939
+ async function runUvSync({
2940
+ uvPath,
2941
+ venvPath,
2942
+ projectDir,
2943
+ locked
2944
+ }) {
2945
+ const args = ["sync", "--active", "--no-dev", "--link-mode", "copy"];
2946
+ if (locked) {
2947
+ args.push("--locked");
2948
+ }
2949
+ args.push("--no-editable");
2950
+ await runUvCommand({
2951
+ uvPath,
2952
+ args,
2953
+ cwd: projectDir,
2954
+ venvPath
2955
+ });
2956
+ }
2957
+ async function getSitePackagesDirs(pythonBin) {
2958
+ const code = `
2959
+ import json
2960
+ import sysconfig
2961
+ paths = []
2962
+ for key in ("purelib", "platlib"):
2963
+ candidate = sysconfig.get_path(key)
2964
+ if candidate and candidate not in paths:
2965
+ paths.append(candidate)
2966
+ print(json.dumps(paths))
2967
+ `.trim();
2968
+ const { stdout } = await (0, import_execa2.default)(pythonBin, ["-c", code]);
2969
+ try {
2970
+ const parsed = JSON.parse(stdout);
2971
+ if (Array.isArray(parsed)) {
2972
+ return parsed.filter((p) => typeof p === "string");
2973
+ }
2974
+ } catch (err) {
2975
+ (0, import_build_utils2.debug)("Failed to parse site-packages output", err);
2976
+ }
2977
+ return [];
2978
+ }
2979
+ async function getVenvSitePackagesDirs(venvPath) {
2980
+ const pythonBin = getVenvPythonBin(venvPath);
2981
+ return getSitePackagesDirs(pythonBin);
2982
+ }
2810
2983
  function resolveVendorDir() {
2811
2984
  const vendorDir = process.env.VERCEL_PYTHON_VENDOR_DIR || "_vendor";
2812
2985
  return vendorDir;
2813
2986
  }
2987
+ async function detectInstallSource({
2988
+ workPath,
2989
+ entryDirectory,
2990
+ fsFiles
2991
+ }) {
2992
+ const uvLockDir = findDir({
2993
+ file: "uv.lock",
2994
+ entryDirectory,
2995
+ workPath,
2996
+ fsFiles
2997
+ });
2998
+ const pyprojectDir = findDir({
2999
+ file: "pyproject.toml",
3000
+ entryDirectory,
3001
+ workPath,
3002
+ fsFiles
3003
+ });
3004
+ const pipfileLockDir = findDir({
3005
+ file: "Pipfile.lock",
3006
+ entryDirectory,
3007
+ workPath,
3008
+ fsFiles
3009
+ });
3010
+ const pipfileDir = findDir({
3011
+ file: "Pipfile",
3012
+ entryDirectory,
3013
+ workPath,
3014
+ fsFiles
3015
+ });
3016
+ const requirementsDir = findDir({
3017
+ file: "requirements.txt",
3018
+ entryDirectory,
3019
+ workPath,
3020
+ fsFiles
3021
+ });
3022
+ let manifestPath = null;
3023
+ let manifestType = null;
3024
+ if (uvLockDir && pyprojectDir) {
3025
+ manifestType = "uv.lock";
3026
+ manifestPath = (0, import_path2.join)(uvLockDir, "uv.lock");
3027
+ } else if (pyprojectDir) {
3028
+ manifestType = "pyproject.toml";
3029
+ manifestPath = (0, import_path2.join)(pyprojectDir, "pyproject.toml");
3030
+ } else if (pipfileLockDir) {
3031
+ manifestType = "Pipfile.lock";
3032
+ manifestPath = (0, import_path2.join)(pipfileLockDir, "Pipfile.lock");
3033
+ } else if (pipfileDir) {
3034
+ manifestType = "Pipfile";
3035
+ manifestPath = (0, import_path2.join)(pipfileDir, "Pipfile");
3036
+ } else if (requirementsDir) {
3037
+ manifestType = "requirements.txt";
3038
+ manifestPath = (0, import_path2.join)(requirementsDir, "requirements.txt");
3039
+ }
3040
+ let manifestContent;
3041
+ if (manifestPath) {
3042
+ try {
3043
+ manifestContent = await import_fs2.default.promises.readFile(manifestPath, "utf8");
3044
+ } catch (err) {
3045
+ (0, import_build_utils2.debug)("Failed to read install manifest contents", err);
3046
+ }
3047
+ }
3048
+ return { manifestPath, manifestType, manifestContent };
3049
+ }
3050
+ async function createPyprojectToml({
3051
+ projectName,
3052
+ pyprojectPath,
3053
+ dependencies
3054
+ }) {
3055
+ const requiresPython = ">=3.12";
3056
+ const depsToml = dependencies.length > 0 ? [
3057
+ "dependencies = [",
3058
+ ...dependencies.map((dep) => ` "${dep}",`),
3059
+ "]"
3060
+ ].join("\n") : "dependencies = []";
3061
+ const content = [
3062
+ "[project]",
3063
+ `name = "${projectName}"`,
3064
+ 'version = "0.1.0"',
3065
+ `requires-python = "${requiresPython}"`,
3066
+ "classifiers = [",
3067
+ ' "Private :: Do Not Upload",',
3068
+ "]",
3069
+ depsToml,
3070
+ ""
3071
+ ].join("\n");
3072
+ await import_fs2.default.promises.writeFile(pyprojectPath, content);
3073
+ }
3074
+ async function uvLock({
3075
+ projectDir,
3076
+ uvPath
3077
+ }) {
3078
+ const args = ["lock"];
3079
+ const pretty = `${uvPath} ${args.join(" ")}`;
3080
+ (0, import_build_utils2.debug)(`Running "${pretty}" in ${projectDir}...`);
3081
+ try {
3082
+ await (0, import_execa2.default)(uvPath, args, { cwd: projectDir });
3083
+ } catch (err) {
3084
+ throw new Error(
3085
+ `Failed to run "${pretty}": ${err instanceof Error ? err.message : String(err)}`
3086
+ );
3087
+ }
3088
+ }
3089
+ async function uvAddDependencies({
3090
+ projectDir,
3091
+ uvPath,
3092
+ venvPath,
3093
+ dependencies
3094
+ }) {
3095
+ const toAdd = dependencies.filter(Boolean);
3096
+ if (!toAdd.length)
3097
+ return;
3098
+ const args = ["add", "--active", ...toAdd];
3099
+ const pretty = `${uvPath} ${args.join(" ")}`;
3100
+ (0, import_build_utils2.debug)(`Running "${pretty}" in ${projectDir}...`);
3101
+ await runUvCommand({ uvPath, args, cwd: projectDir, venvPath });
3102
+ }
3103
+ async function uvAddFromFile({
3104
+ projectDir,
3105
+ uvPath,
3106
+ venvPath,
3107
+ requirementsPath
3108
+ }) {
3109
+ const args = ["add", "--active", "-r", requirementsPath];
3110
+ const pretty = `${uvPath} ${args.join(" ")}`;
3111
+ (0, import_build_utils2.debug)(`Running "${pretty}" in ${projectDir}...`);
3112
+ await runUvCommand({ uvPath, args, cwd: projectDir, venvPath });
3113
+ }
3114
+ function getDependencyName(spec) {
3115
+ const match = spec.match(/^[A-Za-z0-9_.-]+/);
3116
+ return match ? match[0].toLowerCase() : spec.toLowerCase();
3117
+ }
3118
+ async function filterMissingRuntimeDependencies({
3119
+ pyprojectPath,
3120
+ runtimeDependencies
3121
+ }) {
3122
+ let declared = [];
3123
+ try {
3124
+ const config = await (0, import_build_utils2.readConfigFile)(pyprojectPath);
3125
+ declared = config?.project?.dependencies || [];
3126
+ } catch (err) {
3127
+ (0, import_build_utils2.debug)("Failed to parse pyproject.toml when filtering runtime deps", err);
3128
+ }
3129
+ const declaredNames = new Set(declared.map(getDependencyName));
3130
+ return runtimeDependencies.filter((spec) => {
3131
+ const name = getDependencyName(spec);
3132
+ return !declaredNames.has(name);
3133
+ });
3134
+ }
3135
+ function findUvLockUpwards(startDir, repoRootPath) {
3136
+ const start = (0, import_path2.resolve)(startDir);
3137
+ const base = repoRootPath ? (0, import_path2.resolve)(repoRootPath) : void 0;
3138
+ for (const dir of (0, import_build_utils2.traverseUpDirectories)({ start, base })) {
3139
+ const lockPath = (0, import_path2.join)(dir, "uv.lock");
3140
+ const pyprojectPath = (0, import_path2.join)(dir, "pyproject.toml");
3141
+ if (import_fs2.default.existsSync(lockPath) && import_fs2.default.existsSync(pyprojectPath)) {
3142
+ return lockPath;
3143
+ }
3144
+ }
3145
+ return null;
3146
+ }
3147
+ async function ensureUvProject({
3148
+ workPath,
3149
+ entryDirectory,
3150
+ fsFiles,
3151
+ repoRootPath,
3152
+ pythonPath,
3153
+ pipPath,
3154
+ uvPath,
3155
+ venvPath,
3156
+ meta,
3157
+ runtimeDependencies
3158
+ }) {
3159
+ const installInfo = await detectInstallSource({
3160
+ workPath,
3161
+ entryDirectory,
3162
+ fsFiles
3163
+ });
3164
+ const { manifestType, manifestPath } = installInfo;
3165
+ let projectDir;
3166
+ let pyprojectPath;
3167
+ let lockPath = null;
3168
+ if (manifestType === "uv.lock") {
3169
+ if (!manifestPath) {
3170
+ throw new Error("Expected uv.lock path to be resolved, but it was null");
3171
+ }
3172
+ projectDir = (0, import_path2.dirname)(manifestPath);
3173
+ pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3174
+ if (!import_fs2.default.existsSync(pyprojectPath)) {
3175
+ throw new Error(
3176
+ `Expected "pyproject.toml" next to "uv.lock" in "${projectDir}"`
3177
+ );
3178
+ }
3179
+ lockPath = manifestPath;
3180
+ console.log("Installing required dependencies from uv.lock...");
3181
+ } else if (manifestType === "pyproject.toml") {
3182
+ if (!manifestPath) {
3183
+ throw new Error(
3184
+ "Expected pyproject.toml path to be resolved, but it was null"
3185
+ );
3186
+ }
3187
+ projectDir = (0, import_path2.dirname)(manifestPath);
3188
+ pyprojectPath = manifestPath;
3189
+ console.log("Installing required dependencies from pyproject.toml...");
3190
+ const workspaceLock = findUvLockUpwards(projectDir, repoRootPath);
3191
+ if (workspaceLock) {
3192
+ lockPath = workspaceLock;
3193
+ } else {
3194
+ await uvLock({ projectDir, uvPath });
3195
+ }
3196
+ } else if (manifestType === "Pipfile.lock" || manifestType === "Pipfile") {
3197
+ if (!manifestPath) {
3198
+ throw new Error(
3199
+ "Expected Pipfile/Pipfile.lock path to be resolved, but it was null"
3200
+ );
3201
+ }
3202
+ projectDir = (0, import_path2.dirname)(manifestPath);
3203
+ console.log(`Installing required dependencies from ${manifestType}...`);
3204
+ const exportedReq = await exportRequirementsFromPipfile({
3205
+ pythonPath,
3206
+ pipPath,
3207
+ uvPath,
3208
+ projectDir,
3209
+ meta
3210
+ });
3211
+ pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3212
+ if (!import_fs2.default.existsSync(pyprojectPath)) {
3213
+ await createPyprojectToml({
3214
+ projectName: "app",
3215
+ pyprojectPath,
3216
+ dependencies: []
3217
+ });
3218
+ }
3219
+ await uvAddFromFile({
3220
+ projectDir,
3221
+ uvPath,
3222
+ venvPath,
3223
+ requirementsPath: exportedReq
3224
+ });
3225
+ } else if (manifestType === "requirements.txt") {
3226
+ if (!manifestPath) {
3227
+ throw new Error(
3228
+ "Expected requirements.txt path to be resolved, but it was null"
3229
+ );
3230
+ }
3231
+ projectDir = (0, import_path2.dirname)(manifestPath);
3232
+ pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3233
+ console.log(
3234
+ "Installing required dependencies from requirements.txt with uv..."
3235
+ );
3236
+ if (!import_fs2.default.existsSync(pyprojectPath)) {
3237
+ await createPyprojectToml({
3238
+ projectName: "app",
3239
+ pyprojectPath,
3240
+ dependencies: []
3241
+ });
3242
+ }
3243
+ await uvAddFromFile({
3244
+ projectDir,
3245
+ uvPath,
3246
+ venvPath,
3247
+ requirementsPath: manifestPath
3248
+ });
3249
+ } else {
3250
+ projectDir = workPath;
3251
+ pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3252
+ console.log(
3253
+ "No Python manifest found; creating an empty pyproject.toml and uv.lock..."
3254
+ );
3255
+ await createPyprojectToml({
3256
+ projectName: "app",
3257
+ pyprojectPath,
3258
+ dependencies: []
3259
+ });
3260
+ await uvLock({ projectDir, uvPath });
3261
+ }
3262
+ if (runtimeDependencies.length) {
3263
+ const missingRuntimeDeps = await filterMissingRuntimeDependencies({
3264
+ pyprojectPath,
3265
+ runtimeDependencies
3266
+ });
3267
+ if (missingRuntimeDeps.length) {
3268
+ await uvAddDependencies({
3269
+ projectDir,
3270
+ uvPath,
3271
+ venvPath,
3272
+ dependencies: missingRuntimeDeps
3273
+ });
3274
+ }
3275
+ }
3276
+ const resolvedLockPath = lockPath && import_fs2.default.existsSync(lockPath) ? lockPath : findUvLockUpwards(projectDir, repoRootPath) || (0, import_path2.join)(projectDir, "uv.lock");
3277
+ return { projectDir, pyprojectPath, lockPath: resolvedLockPath };
3278
+ }
2814
3279
  async function getGlobalScriptsDir(pythonPath) {
2815
3280
  const code = `import sysconfig; print(sysconfig.get_path('scripts'))`;
2816
3281
  try {
2817
- const { stdout } = await (0, import_execa.default)(pythonPath, ["-c", code]);
3282
+ const { stdout } = await (0, import_execa2.default)(pythonPath, ["-c", code]);
2818
3283
  const out = stdout.trim();
2819
3284
  return out || null;
2820
3285
  } catch (err) {
2821
- (0, import_build_utils.debug)("Failed to resolve Python global scripts directory", err);
3286
+ (0, import_build_utils2.debug)("Failed to resolve Python global scripts directory", err);
2822
3287
  return null;
2823
3288
  }
2824
3289
  }
@@ -2828,16 +3293,16 @@ async function getUserScriptsDir(pythonPath) {
2828
3293
  " "
2829
3294
  );
2830
3295
  try {
2831
- const { stdout } = await (0, import_execa.default)(pythonPath, ["-c", code]);
3296
+ const { stdout } = await (0, import_execa2.default)(pythonPath, ["-c", code]);
2832
3297
  const out = stdout.trim();
2833
3298
  return out || null;
2834
3299
  } catch (err) {
2835
- (0, import_build_utils.debug)("Failed to resolve Python user scripts directory", err);
3300
+ (0, import_build_utils2.debug)("Failed to resolve Python user scripts directory", err);
2836
3301
  return null;
2837
3302
  }
2838
3303
  }
2839
3304
  async function pipInstall(pipPath, uvPath, workPath, args, targetDir) {
2840
- const target = targetDir ? (0, import_path.join)(targetDir, resolveVendorDir()) : resolveVendorDir();
3305
+ const target = targetDir ? (0, import_path2.join)(targetDir, resolveVendorDir()) : resolveVendorDir();
2841
3306
  process.env.PIP_USER = "0";
2842
3307
  if (uvPath) {
2843
3308
  const uvArgs = [
@@ -2847,18 +3312,18 @@ async function pipInstall(pipPath, uvPath, workPath, args, targetDir) {
2847
3312
  "--no-cache-dir",
2848
3313
  "--target",
2849
3314
  target,
2850
- ...args
3315
+ ...filterUnsafeUvPipArgs(args)
2851
3316
  ];
2852
3317
  const prettyUv = `${uvPath} ${uvArgs.join(" ")}`;
2853
- (0, import_build_utils.debug)(`Running "${prettyUv}"...`);
3318
+ (0, import_build_utils2.debug)(`Running "${prettyUv}"...`);
2854
3319
  try {
2855
- await (0, import_execa.default)(uvPath, uvArgs, {
3320
+ await (0, import_execa2.default)(uvPath, uvArgs, {
2856
3321
  cwd: workPath
2857
3322
  });
2858
3323
  return;
2859
3324
  } catch (err) {
2860
3325
  console.log(`Failed to run "${prettyUv}", falling back to pip`);
2861
- (0, import_build_utils.debug)(`error: ${err}`);
3326
+ (0, import_build_utils2.debug)(`error: ${err}`);
2862
3327
  }
2863
3328
  }
2864
3329
  const cmdArgs = [
@@ -2871,14 +3336,14 @@ async function pipInstall(pipPath, uvPath, workPath, args, targetDir) {
2871
3336
  ...args
2872
3337
  ];
2873
3338
  const pretty = `${pipPath} ${cmdArgs.join(" ")}`;
2874
- (0, import_build_utils.debug)(`Running "${pretty}"...`);
3339
+ (0, import_build_utils2.debug)(`Running "${pretty}"...`);
2875
3340
  try {
2876
- await (0, import_execa.default)(pipPath, cmdArgs, {
3341
+ await (0, import_execa2.default)(pipPath, cmdArgs, {
2877
3342
  cwd: workPath
2878
3343
  });
2879
3344
  } catch (err) {
2880
3345
  console.log(`Failed to run "${pretty}"`);
2881
- (0, import_build_utils.debug)(`error: ${err}`);
3346
+ (0, import_build_utils2.debug)(`error: ${err}`);
2882
3347
  throw err;
2883
3348
  }
2884
3349
  }
@@ -2889,38 +3354,38 @@ async function maybeFindUvBin(pythonPath) {
2889
3354
  try {
2890
3355
  const globalScriptsDir = await getGlobalScriptsDir(pythonPath);
2891
3356
  if (globalScriptsDir) {
2892
- const uvPath = (0, import_path.join)(globalScriptsDir, uvExec);
2893
- if (import_fs.default.existsSync(uvPath))
3357
+ const uvPath = (0, import_path2.join)(globalScriptsDir, uvExec);
3358
+ if (import_fs2.default.existsSync(uvPath))
2894
3359
  return uvPath;
2895
3360
  }
2896
3361
  } catch (err) {
2897
- (0, import_build_utils.debug)("Failed to resolve Python global scripts directory", err);
3362
+ (0, import_build_utils2.debug)("Failed to resolve Python global scripts directory", err);
2898
3363
  }
2899
3364
  try {
2900
3365
  const userScriptsDir = await getUserScriptsDir(pythonPath);
2901
3366
  if (userScriptsDir) {
2902
- const uvPath = (0, import_path.join)(userScriptsDir, uvExec);
2903
- if (import_fs.default.existsSync(uvPath))
3367
+ const uvPath = (0, import_path2.join)(userScriptsDir, uvExec);
3368
+ if (import_fs2.default.existsSync(uvPath))
2904
3369
  return uvPath;
2905
3370
  }
2906
3371
  } catch (err) {
2907
- (0, import_build_utils.debug)("Failed to resolve Python user scripts directory", err);
3372
+ (0, import_build_utils2.debug)("Failed to resolve Python user scripts directory", err);
2908
3373
  }
2909
3374
  try {
2910
3375
  const candidates = [];
2911
- if (!isWin) {
2912
- candidates.push((0, import_path.join)(import_os.default.homedir(), ".local", "bin", "uv"));
3376
+ if (!isWin2) {
3377
+ candidates.push((0, import_path2.join)(import_os.default.homedir(), ".local", "bin", "uv"));
2913
3378
  candidates.push("/usr/local/bin/uv");
2914
3379
  candidates.push("/opt/homebrew/bin/uv");
2915
3380
  } else {
2916
3381
  candidates.push("C:\\Users\\Public\\uv\\uv.exe");
2917
3382
  }
2918
3383
  for (const p of candidates) {
2919
- if (import_fs.default.existsSync(p))
3384
+ if (import_fs2.default.existsSync(p))
2920
3385
  return p;
2921
3386
  }
2922
3387
  } catch (err) {
2923
- (0, import_build_utils.debug)("Failed to resolve uv fallback paths", err);
3388
+ (0, import_build_utils2.debug)("Failed to resolve uv fallback paths", err);
2924
3389
  }
2925
3390
  return null;
2926
3391
  }
@@ -2930,7 +3395,7 @@ async function getUvBinaryOrInstall(pythonPath) {
2930
3395
  return uvBin;
2931
3396
  try {
2932
3397
  console.log("Installing uv...");
2933
- await (0, import_execa.default)(
3398
+ await (0, import_execa2.default)(
2934
3399
  pythonPath,
2935
3400
  [
2936
3401
  "-m",
@@ -2968,7 +3433,7 @@ async function installRequirement({
2968
3433
  }) {
2969
3434
  const actualTargetDir = targetDir || workPath;
2970
3435
  if (meta.isDev && await isInstalled(pythonPath, dependency, actualTargetDir)) {
2971
- (0, import_build_utils.debug)(
3436
+ (0, import_build_utils2.debug)(
2972
3437
  `Skipping ${dependency} dependency installation, already installed in ${actualTargetDir}`
2973
3438
  );
2974
3439
  return;
@@ -2988,7 +3453,7 @@ async function installRequirementsFile({
2988
3453
  }) {
2989
3454
  const actualTargetDir = targetDir || workPath;
2990
3455
  if (meta.isDev && await areRequirementsInstalled(pythonPath, filePath, actualTargetDir)) {
2991
- (0, import_build_utils.debug)(`Skipping requirements file installation, already installed`);
3456
+ (0, import_build_utils2.debug)(`Skipping requirements file installation, already installed`);
2992
3457
  return;
2993
3458
  }
2994
3459
  await pipInstall(
@@ -2999,30 +3464,8 @@ async function installRequirementsFile({
2999
3464
  targetDir
3000
3465
  );
3001
3466
  }
3002
- async function exportRequirementsFromUv(projectDir, uvPath, options = {}) {
3003
- const { locked = false } = options;
3004
- if (!uvPath) {
3005
- throw new Error("uv is not available to export requirements");
3006
- }
3007
- const args = ["export"];
3008
- if (locked) {
3009
- args.push("--frozen");
3010
- }
3011
- (0, import_build_utils.debug)(`Running "${uvPath} ${args.join(" ")}" in ${projectDir}...`);
3012
- let stdout;
3013
- try {
3014
- const { stdout: out } = await (0, import_execa.default)(uvPath, args, { cwd: projectDir });
3015
- stdout = out;
3016
- } catch (err) {
3017
- throw new Error(
3018
- `Failed to run "${uvPath} ${args.join(" ")}": ${err instanceof Error ? err.message : String(err)}`
3019
- );
3020
- }
3021
- const tmpDir = await import_fs.default.promises.mkdtemp((0, import_path.join)(import_os.default.tmpdir(), "vercel-uv-"));
3022
- const outPath = (0, import_path.join)(tmpDir, "requirements.uv.txt");
3023
- await import_fs.default.promises.writeFile(outPath, stdout);
3024
- (0, import_build_utils.debug)(`Exported requirements to ${outPath}`);
3025
- return outPath;
3467
+ function filterUnsafeUvPipArgs(args) {
3468
+ return args.filter((arg) => arg !== "--no-warn-script-location");
3026
3469
  }
3027
3470
  async function exportRequirementsFromPipfile({
3028
3471
  pythonPath,
@@ -3031,8 +3474,8 @@ async function exportRequirementsFromPipfile({
3031
3474
  projectDir,
3032
3475
  meta
3033
3476
  }) {
3034
- const tempDir = await import_fs.default.promises.mkdtemp(
3035
- (0, import_path.join)(import_os.default.tmpdir(), "vercel-pipenv-")
3477
+ const tempDir = await import_fs2.default.promises.mkdtemp(
3478
+ (0, import_path2.join)(import_os.default.tmpdir(), "vercel-pipenv-")
3036
3479
  );
3037
3480
  await installRequirement({
3038
3481
  pythonPath,
@@ -3044,12 +3487,12 @@ async function exportRequirementsFromPipfile({
3044
3487
  args: ["--no-warn-script-location"],
3045
3488
  uvPath
3046
3489
  });
3047
- const tempVendorDir = (0, import_path.join)(tempDir, resolveVendorDir());
3048
- const convertCmd = isWin ? (0, import_path.join)(tempVendorDir, "Scripts", "pipfile2req.exe") : (0, import_path.join)(tempVendorDir, "bin", "pipfile2req");
3049
- (0, import_build_utils.debug)(`Running "${convertCmd}" in ${projectDir}...`);
3490
+ const tempVendorDir = (0, import_path2.join)(tempDir, resolveVendorDir());
3491
+ const convertCmd = isWin2 ? (0, import_path2.join)(tempVendorDir, "Scripts", "pipfile2req.exe") : (0, import_path2.join)(tempVendorDir, "bin", "pipfile2req");
3492
+ (0, import_build_utils2.debug)(`Running "${convertCmd}" in ${projectDir}...`);
3050
3493
  let stdout;
3051
3494
  try {
3052
- const { stdout: out } = await (0, import_execa.default)(convertCmd, [], {
3495
+ const { stdout: out } = await (0, import_execa2.default)(convertCmd, [], {
3053
3496
  cwd: projectDir,
3054
3497
  env: { ...process.env, PYTHONPATH: tempVendorDir }
3055
3498
  });
@@ -3059,17 +3502,46 @@ async function exportRequirementsFromPipfile({
3059
3502
  `Failed to run "${convertCmd}": ${err instanceof Error ? err.message : String(err)}`
3060
3503
  );
3061
3504
  }
3062
- const outPath = (0, import_path.join)(tempDir, "requirements.pipenv.txt");
3063
- await import_fs.default.promises.writeFile(outPath, stdout);
3064
- (0, import_build_utils.debug)(`Exported pipfile requirements to ${outPath}`);
3505
+ const outPath = (0, import_path2.join)(tempDir, "requirements.pipenv.txt");
3506
+ await import_fs2.default.promises.writeFile(outPath, stdout);
3507
+ (0, import_build_utils2.debug)(`Exported pipfile requirements to ${outPath}`);
3065
3508
  return outPath;
3066
3509
  }
3510
+ async function mirrorSitePackagesIntoVendor({
3511
+ venvPath,
3512
+ vendorDirName
3513
+ }) {
3514
+ const vendorFiles = {};
3515
+ try {
3516
+ const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
3517
+ for (const dir of sitePackageDirs) {
3518
+ if (!import_fs2.default.existsSync(dir))
3519
+ continue;
3520
+ const dirFiles = await (0, import_build_utils2.glob)("**", dir);
3521
+ for (const relativePath of Object.keys(dirFiles)) {
3522
+ if (relativePath.endsWith(".pyc") || relativePath.includes("__pycache__")) {
3523
+ continue;
3524
+ }
3525
+ const srcFsPath = (0, import_path2.join)(dir, relativePath);
3526
+ const bundlePath = (0, import_path2.join)(vendorDirName, relativePath).replace(
3527
+ /\\/g,
3528
+ "/"
3529
+ );
3530
+ vendorFiles[bundlePath] = new import_build_utils2.FileFsRef({ fsPath: srcFsPath });
3531
+ }
3532
+ }
3533
+ } catch (err) {
3534
+ console.log("Failed to collect site-packages from virtual environment");
3535
+ throw err;
3536
+ }
3537
+ return vendorFiles;
3538
+ }
3067
3539
 
3068
3540
  // src/index.ts
3069
- var import_build_utils6 = require("@vercel/build-utils");
3541
+ var import_build_utils8 = require("@vercel/build-utils");
3070
3542
 
3071
3543
  // src/version.ts
3072
- var import_build_utils2 = require("@vercel/build-utils");
3544
+ var import_build_utils3 = require("@vercel/build-utils");
3073
3545
  var import_which2 = __toESM(require_lib());
3074
3546
  var allOptions = [
3075
3547
  {
@@ -3120,7 +3592,7 @@ function getLatestPythonVersion({
3120
3592
  }
3121
3593
  const selection = allOptions.find(isInstalled2);
3122
3594
  if (!selection) {
3123
- throw new import_build_utils2.NowBuildError({
3595
+ throw new import_build_utils3.NowBuildError({
3124
3596
  code: "PYTHON_NOT_FOUND",
3125
3597
  link: "http://vercel.link/python-version",
3126
3598
  message: `Unable to find any supported Python versions.`
@@ -3128,6 +3600,81 @@ function getLatestPythonVersion({
3128
3600
  }
3129
3601
  return selection;
3130
3602
  }
3603
+ function parseVersionTuple(input) {
3604
+ const cleaned = input.trim().replace(/\s+/g, "");
3605
+ const m = cleaned.match(/^(\d+)(?:\.(\d+))?/);
3606
+ if (!m)
3607
+ return null;
3608
+ const major = Number(m[1]);
3609
+ const minor = m[2] !== void 0 ? Number(m[2]) : 0;
3610
+ if (Number.isNaN(major) || Number.isNaN(minor))
3611
+ return null;
3612
+ return [major, minor];
3613
+ }
3614
+ function compareTuples(a, b) {
3615
+ if (a[0] !== b[0])
3616
+ return a[0] - b[0];
3617
+ return a[1] - b[1];
3618
+ }
3619
+ function parseSpecifier(spec) {
3620
+ const s = spec.trim();
3621
+ const m = s.match(/^(<=|>=|==|!=|~=|<|>)\s*([0-9]+(?:\.[0-9]+)?)(?:\.\*)?$/) || // Bare version like "3.11" -> implied ==
3622
+ s.match(/^()([0-9]+(?:\.[0-9]+)?)(?:\.\*)?$/);
3623
+ if (!m)
3624
+ return null;
3625
+ const op = m[1] || "==";
3626
+ const vt = parseVersionTuple(m[2]);
3627
+ if (!vt)
3628
+ return null;
3629
+ return { op, ver: vt };
3630
+ }
3631
+ function satisfies(candidate, spec) {
3632
+ const cmp = compareTuples(candidate, spec.ver);
3633
+ switch (spec.op) {
3634
+ case "==":
3635
+ return cmp === 0;
3636
+ case "!=":
3637
+ return cmp !== 0;
3638
+ case "<":
3639
+ return cmp < 0;
3640
+ case "<=":
3641
+ return cmp <= 0;
3642
+ case ">":
3643
+ return cmp > 0;
3644
+ case ">=":
3645
+ return cmp >= 0;
3646
+ case "~=": {
3647
+ const lowerOk = cmp >= 0;
3648
+ const upper = [spec.ver[0], spec.ver[1] + 1];
3649
+ return lowerOk && compareTuples(candidate, upper) < 0;
3650
+ }
3651
+ default:
3652
+ return false;
3653
+ }
3654
+ }
3655
+ function selectFromRequiresPython(expr) {
3656
+ const raw = expr.trim();
3657
+ if (!raw)
3658
+ return void 0;
3659
+ const parts = raw.split(",").map((p) => p.trim()).filter(Boolean);
3660
+ const specifiers = [];
3661
+ for (const p of parts) {
3662
+ const sp = parseSpecifier(p);
3663
+ if (sp)
3664
+ specifiers.push(sp);
3665
+ }
3666
+ if (specifiers.length === 0) {
3667
+ return allOptions.find((o) => o.version === raw);
3668
+ }
3669
+ const matches = allOptions.filter((opt) => {
3670
+ const vt = parseVersionTuple(opt.version);
3671
+ return specifiers.every((sp) => satisfies(vt, sp));
3672
+ });
3673
+ if (matches.length === 0)
3674
+ return void 0;
3675
+ const installedMatch = matches.find(isInstalled2);
3676
+ return installedMatch ?? matches[0];
3677
+ }
3131
3678
  function getSupportedPythonVersion({
3132
3679
  isDev,
3133
3680
  declaredPythonVersion
@@ -3138,10 +3685,15 @@ function getSupportedPythonVersion({
3138
3685
  let selection = getLatestPythonVersion({ isDev: false });
3139
3686
  if (declaredPythonVersion) {
3140
3687
  const { version: version2, source } = declaredPythonVersion;
3141
- const requested = allOptions.find((o) => o.version === version2);
3688
+ let requested;
3689
+ if (source === "pyproject.toml") {
3690
+ requested = selectFromRequiresPython(version2);
3691
+ } else {
3692
+ requested = allOptions.find((o) => o.version === version2);
3693
+ }
3142
3694
  if (requested) {
3143
3695
  if (isDiscontinued(requested)) {
3144
- throw new import_build_utils2.NowBuildError({
3696
+ throw new import_build_utils3.NowBuildError({
3145
3697
  code: "BUILD_UTILS_PYTHON_VERSION_DISCONTINUED",
3146
3698
  link: "http://vercel.link/python-version",
3147
3699
  message: `Python version "${requested.version}" detected in ${source} is discontinued and must be upgraded.`
@@ -3172,7 +3724,7 @@ function getSupportedPythonVersion({
3172
3724
  );
3173
3725
  }
3174
3726
  if (isDiscontinued(selection)) {
3175
- throw new import_build_utils2.NowBuildError({
3727
+ throw new import_build_utils3.NowBuildError({
3176
3728
  code: "BUILD_UTILS_PYTHON_VERSION_DISCONTINUED",
3177
3729
  link: "http://vercel.link/python-version",
3178
3730
  message: `Python version "${selection.version}" declared in project configuration is discontinued and must be upgraded.`
@@ -3199,18 +3751,19 @@ function isInstalled2({ pipPath, pythonPath }) {
3199
3751
  var import_child_process = require("child_process");
3200
3752
  var import_fs4 = require("fs");
3201
3753
  var import_path4 = require("path");
3202
- var import_build_utils4 = require("@vercel/build-utils");
3754
+ var import_build_utils6 = require("@vercel/build-utils");
3203
3755
 
3204
3756
  // src/entrypoint.ts
3205
- var import_fs2 = __toESM(require("fs"));
3206
- var import_path2 = require("path");
3207
- var import_build_utils3 = require("@vercel/build-utils");
3757
+ var import_fs3 = __toESM(require("fs"));
3758
+ var import_path3 = require("path");
3759
+ var import_build_utils4 = require("@vercel/build-utils");
3760
+ var import_build_utils5 = require("@vercel/build-utils");
3208
3761
  var FASTAPI_ENTRYPOINT_FILENAMES = ["app", "index", "server", "main"];
3209
- var FASTAPI_ENTRYPOINT_DIRS = ["", "src", "app"];
3762
+ var FASTAPI_ENTRYPOINT_DIRS = ["", "src", "app", "api"];
3210
3763
  var FASTAPI_CONTENT_REGEX = /(from\s+fastapi\s+import\s+FastAPI|import\s+fastapi|FastAPI\s*\()/;
3211
3764
  var FASTAPI_CANDIDATE_ENTRYPOINTS = FASTAPI_ENTRYPOINT_FILENAMES.flatMap(
3212
3765
  (filename) => FASTAPI_ENTRYPOINT_DIRS.map(
3213
- (dir) => import_path2.posix.join(dir, `${filename}.py`)
3766
+ (dir) => import_path3.posix.join(dir, `${filename}.py`)
3214
3767
  )
3215
3768
  );
3216
3769
  function isFastapiEntrypoint(file) {
@@ -3218,18 +3771,18 @@ function isFastapiEntrypoint(file) {
3218
3771
  const fsPath = file.fsPath;
3219
3772
  if (!fsPath)
3220
3773
  return false;
3221
- const contents = import_fs2.default.readFileSync(fsPath, "utf8");
3774
+ const contents = import_fs3.default.readFileSync(fsPath, "utf8");
3222
3775
  return FASTAPI_CONTENT_REGEX.test(contents);
3223
3776
  } catch {
3224
3777
  return false;
3225
3778
  }
3226
3779
  }
3227
3780
  var FLASK_ENTRYPOINT_FILENAMES = ["app", "index", "server", "main"];
3228
- var FLASK_ENTRYPOINT_DIRS = ["", "src", "app"];
3781
+ var FLASK_ENTRYPOINT_DIRS = ["", "src", "app", "api"];
3229
3782
  var FLASK_CONTENT_REGEX = /(from\s+flask\s+import\s+Flask|import\s+flask|Flask\s*\()/;
3230
3783
  var FLASK_CANDIDATE_ENTRYPOINTS = FLASK_ENTRYPOINT_FILENAMES.flatMap(
3231
3784
  (filename) => FLASK_ENTRYPOINT_DIRS.map(
3232
- (dir) => import_path2.posix.join(dir, `${filename}.py`)
3785
+ (dir) => import_path3.posix.join(dir, `${filename}.py`)
3233
3786
  )
3234
3787
  );
3235
3788
  function isFlaskEntrypoint(file) {
@@ -3237,7 +3790,7 @@ function isFlaskEntrypoint(file) {
3237
3790
  const fsPath = file.fsPath;
3238
3791
  if (!fsPath)
3239
3792
  return false;
3240
- const contents = import_fs2.default.readFileSync(fsPath, "utf8");
3793
+ const contents = import_fs3.default.readFileSync(fsPath, "utf8");
3241
3794
  return FLASK_CONTENT_REGEX.test(contents);
3242
3795
  } catch {
3243
3796
  return false;
@@ -3246,7 +3799,7 @@ function isFlaskEntrypoint(file) {
3246
3799
  async function detectFlaskEntrypoint(workPath, configuredEntrypoint) {
3247
3800
  const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
3248
3801
  try {
3249
- const fsFiles = await (0, import_build_utils3.glob)("**", workPath);
3802
+ const fsFiles = await (0, import_build_utils4.glob)("**", workPath);
3250
3803
  if (fsFiles[entry])
3251
3804
  return entry;
3252
3805
  const candidates = FLASK_CANDIDATE_ENTRYPOINTS.filter(
@@ -3256,19 +3809,19 @@ async function detectFlaskEntrypoint(workPath, configuredEntrypoint) {
3256
3809
  const flaskEntrypoint = candidates.find(
3257
3810
  (c) => isFlaskEntrypoint(fsFiles[c])
3258
3811
  ) || candidates[0];
3259
- (0, import_build_utils3.debug)(`Detected Flask entrypoint: ${flaskEntrypoint}`);
3812
+ (0, import_build_utils4.debug)(`Detected Flask entrypoint: ${flaskEntrypoint}`);
3260
3813
  return flaskEntrypoint;
3261
3814
  }
3262
3815
  return null;
3263
3816
  } catch {
3264
- (0, import_build_utils3.debug)("Failed to discover entrypoint for Flask");
3817
+ (0, import_build_utils4.debug)("Failed to discover entrypoint for Flask");
3265
3818
  return null;
3266
3819
  }
3267
3820
  }
3268
3821
  async function detectFastapiEntrypoint(workPath, configuredEntrypoint) {
3269
3822
  const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
3270
3823
  try {
3271
- const fsFiles = await (0, import_build_utils3.glob)("**", workPath);
3824
+ const fsFiles = await (0, import_build_utils4.glob)("**", workPath);
3272
3825
  if (fsFiles[entry])
3273
3826
  return entry;
3274
3827
  const candidates = FASTAPI_CANDIDATE_ENTRYPOINTS.filter(
@@ -3278,38 +3831,51 @@ async function detectFastapiEntrypoint(workPath, configuredEntrypoint) {
3278
3831
  const fastapiEntrypoint = candidates.find(
3279
3832
  (c) => isFastapiEntrypoint(fsFiles[c])
3280
3833
  ) || candidates[0];
3281
- (0, import_build_utils3.debug)(`Detected FastAPI entrypoint: ${fastapiEntrypoint}`);
3834
+ (0, import_build_utils4.debug)(`Detected FastAPI entrypoint: ${fastapiEntrypoint}`);
3282
3835
  return fastapiEntrypoint;
3283
3836
  }
3284
3837
  return null;
3285
3838
  } catch {
3286
- (0, import_build_utils3.debug)("Failed to discover entrypoint for FastAPI");
3839
+ (0, import_build_utils4.debug)("Failed to discover entrypoint for FastAPI");
3287
3840
  return null;
3288
3841
  }
3289
3842
  }
3290
-
3291
- // src/utils.ts
3292
- var import_fs3 = __toESM(require("fs"));
3293
- var import_path3 = require("path");
3294
- var isInVirtualEnv = () => {
3295
- return process.env.VIRTUAL_ENV;
3296
- };
3297
- function useVirtualEnv(workPath, env, systemPython) {
3298
- const venvDirs = [".venv", "venv"];
3299
- let pythonCmd = systemPython;
3300
- for (const venv of venvDirs) {
3301
- const venvRoot = (0, import_path3.join)(workPath, venv);
3302
- const binDir = process.platform === "win32" ? (0, import_path3.join)(venvRoot, "Scripts") : (0, import_path3.join)(venvRoot, "bin");
3303
- const candidates = process.platform === "win32" ? [(0, import_path3.join)(binDir, "python.exe"), (0, import_path3.join)(binDir, "python")] : [(0, import_path3.join)(binDir, "python3"), (0, import_path3.join)(binDir, "python")];
3304
- const found = candidates.find((p) => import_fs3.default.existsSync(p));
3305
- if (found) {
3306
- pythonCmd = found;
3307
- env.VIRTUAL_ENV = venvRoot;
3308
- env.PATH = `${binDir}${import_path3.delimiter}${env.PATH || ""}`;
3309
- return { pythonCmd, venvRoot };
3843
+ async function getPyprojectEntrypoint(workPath) {
3844
+ const pyprojectData = await (0, import_build_utils5.readConfigFile)((0, import_path3.join)(workPath, "pyproject.toml"));
3845
+ if (!pyprojectData)
3846
+ return null;
3847
+ const scripts = pyprojectData.project?.scripts;
3848
+ const appScript = scripts?.app;
3849
+ if (typeof appScript !== "string")
3850
+ return null;
3851
+ const match = appScript.match(/([A-Za-z_][\w.]*)\s*:\s*([A-Za-z_][\w]*)/);
3852
+ if (!match)
3853
+ return null;
3854
+ const modulePath = match[1];
3855
+ const relPath = modulePath.replace(/\./g, "/");
3856
+ try {
3857
+ const fsFiles = await (0, import_build_utils4.glob)("**", workPath);
3858
+ const candidates = [`${relPath}.py`, `${relPath}/__init__.py`];
3859
+ for (const candidate of candidates) {
3860
+ if (fsFiles[candidate])
3861
+ return candidate;
3310
3862
  }
3863
+ return null;
3864
+ } catch {
3865
+ (0, import_build_utils4.debug)("Failed to discover Python entrypoint from pyproject.toml");
3866
+ return null;
3311
3867
  }
3312
- return { pythonCmd };
3868
+ }
3869
+ async function detectPythonEntrypoint(framework, workPath, configuredEntrypoint) {
3870
+ let entrypoint = null;
3871
+ if (framework === "fastapi") {
3872
+ entrypoint = await detectFastapiEntrypoint(workPath, configuredEntrypoint);
3873
+ } else if (framework === "flask") {
3874
+ entrypoint = await detectFlaskEntrypoint(workPath, configuredEntrypoint);
3875
+ }
3876
+ if (entrypoint)
3877
+ return entrypoint;
3878
+ return await getPyprojectEntrypoint(workPath);
3313
3879
  }
3314
3880
 
3315
3881
  // src/start-dev-server.ts
@@ -3355,12 +3921,12 @@ function installGlobalCleanupHandlers() {
3355
3921
  try {
3356
3922
  process.kill(info.pid, "SIGTERM");
3357
3923
  } catch (err) {
3358
- (0, import_build_utils4.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
3924
+ (0, import_build_utils6.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
3359
3925
  }
3360
3926
  try {
3361
3927
  process.kill(info.pid, "SIGKILL");
3362
3928
  } catch (err) {
3363
- (0, import_build_utils4.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
3929
+ (0, import_build_utils6.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
3364
3930
  }
3365
3931
  PERSISTENT_SERVERS.delete(key);
3366
3932
  }
@@ -3368,7 +3934,7 @@ function installGlobalCleanupHandlers() {
3368
3934
  try {
3369
3935
  restoreWarnings();
3370
3936
  } catch (err) {
3371
- (0, import_build_utils4.debug)(`Error restoring warnings: ${err}`);
3937
+ (0, import_build_utils6.debug)(`Error restoring warnings: ${err}`);
3372
3938
  }
3373
3939
  restoreWarnings = null;
3374
3940
  }
@@ -3394,10 +3960,10 @@ function createDevAsgiShim(workPath, modulePath) {
3394
3960
  const template = (0, import_fs4.readFileSync)(templatePath, "utf8");
3395
3961
  const shimSource = template.replace(/__VC_DEV_MODULE_PATH__/g, modulePath);
3396
3962
  (0, import_fs4.writeFileSync)(shimPath, shimSource, "utf8");
3397
- (0, import_build_utils4.debug)(`Prepared Python dev static shim at ${shimPath}`);
3963
+ (0, import_build_utils6.debug)(`Prepared Python dev static shim at ${shimPath}`);
3398
3964
  return ASGI_SHIM_MODULE;
3399
3965
  } catch (err) {
3400
- (0, import_build_utils4.debug)(`Failed to prepare dev static shim: ${err?.message || err}`);
3966
+ (0, import_build_utils6.debug)(`Failed to prepare dev static shim: ${err?.message || err}`);
3401
3967
  return null;
3402
3968
  }
3403
3969
  }
@@ -3410,10 +3976,10 @@ function createDevWsgiShim(workPath, modulePath) {
3410
3976
  const template = (0, import_fs4.readFileSync)(templatePath, "utf8");
3411
3977
  const shimSource = template.replace(/__VC_DEV_MODULE_PATH__/g, modulePath);
3412
3978
  (0, import_fs4.writeFileSync)(shimPath, shimSource, "utf8");
3413
- (0, import_build_utils4.debug)(`Prepared Python dev WSGI shim at ${shimPath}`);
3979
+ (0, import_build_utils6.debug)(`Prepared Python dev WSGI shim at ${shimPath}`);
3414
3980
  return WSGI_SHIM_MODULE;
3415
3981
  } catch (err) {
3416
- (0, import_build_utils4.debug)(`Failed to prepare dev WSGI shim: ${err?.message || err}`);
3982
+ (0, import_build_utils6.debug)(`Failed to prepare dev WSGI shim: ${err?.message || err}`);
3417
3983
  return null;
3418
3984
  }
3419
3985
  }
@@ -3426,26 +3992,19 @@ var startDevServer = async (opts) => {
3426
3992
  if (!restoreWarnings)
3427
3993
  restoreWarnings = silenceNodeWarnings();
3428
3994
  installGlobalCleanupHandlers();
3429
- let entry = null;
3430
- if (framework === "fastapi") {
3431
- const detectedFastapi = await detectFastapiEntrypoint(
3432
- workPath,
3433
- rawEntrypoint
3434
- );
3435
- if (!detectedFastapi) {
3436
- throw new Error(
3437
- `No FastAPI entrypoint found. Searched for: ${FASTAPI_CANDIDATE_ENTRYPOINTS.join(", ")}`
3438
- );
3439
- }
3440
- entry = detectedFastapi;
3441
- } else {
3442
- const detectedFlask = await detectFlaskEntrypoint(workPath, rawEntrypoint);
3443
- if (!detectedFlask) {
3444
- throw new Error(
3445
- `No Flask entrypoint found. Searched for: ${FLASK_CANDIDATE_ENTRYPOINTS.join(", ")}`
3446
- );
3447
- }
3448
- entry = detectedFlask;
3995
+ const entry = await detectPythonEntrypoint(
3996
+ framework,
3997
+ workPath,
3998
+ rawEntrypoint
3999
+ );
4000
+ if (!entry) {
4001
+ const searched = framework === "fastapi" ? FASTAPI_CANDIDATE_ENTRYPOINTS.join(", ") : FLASK_CANDIDATE_ENTRYPOINTS.join(", ");
4002
+ throw new import_build_utils6.NowBuildError({
4003
+ code: "PYTHON_ENTRYPOINT_NOT_FOUND",
4004
+ message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searched}.`,
4005
+ link: `https://vercel.com/docs/frameworks/backend/${framework?.toLowerCase()}#exporting-the-${framework?.toLowerCase()}-application`,
4006
+ action: "Learn More"
4007
+ });
3449
4008
  }
3450
4009
  const modulePath = entry.replace(/\.py$/i, "").replace(/[\\/]/g, ".");
3451
4010
  const env = { ...process.env, ...meta.env || {} };
@@ -3477,20 +4036,20 @@ var startDevServer = async (opts) => {
3477
4036
  let resolveChildReady;
3478
4037
  let rejectChildReady;
3479
4038
  const childReady = new Promise(
3480
- (resolve, reject) => {
3481
- resolveChildReady = resolve;
4039
+ (resolve2, reject) => {
4040
+ resolveChildReady = resolve2;
3482
4041
  rejectChildReady = reject;
3483
4042
  }
3484
4043
  );
3485
4044
  PENDING_STARTS.set(serverKey, childReady);
3486
4045
  try {
3487
- await new Promise((resolve, reject) => {
4046
+ await new Promise((resolve2, reject) => {
3488
4047
  let resolved = false;
3489
4048
  const { pythonPath: systemPython } = getLatestPythonVersion(meta);
3490
4049
  let pythonCmd = systemPython;
3491
4050
  const venv = isInVirtualEnv();
3492
4051
  if (venv) {
3493
- (0, import_build_utils4.debug)(`Running in virtualenv at ${venv}`);
4052
+ (0, import_build_utils6.debug)(`Running in virtualenv at ${venv}`);
3494
4053
  } else {
3495
4054
  const { pythonCmd: venvPythonCmd, venvRoot } = useVirtualEnv(
3496
4055
  workPath,
@@ -3499,9 +4058,9 @@ var startDevServer = async (opts) => {
3499
4058
  );
3500
4059
  pythonCmd = venvPythonCmd;
3501
4060
  if (venvRoot) {
3502
- (0, import_build_utils4.debug)(`Using virtualenv at ${venvRoot}`);
4061
+ (0, import_build_utils6.debug)(`Using virtualenv at ${venvRoot}`);
3503
4062
  } else {
3504
- (0, import_build_utils4.debug)("No virtualenv found");
4063
+ (0, import_build_utils6.debug)("No virtualenv found");
3505
4064
  try {
3506
4065
  const yellow = "\x1B[33m";
3507
4066
  const reset = "\x1B[0m";
@@ -3524,7 +4083,7 @@ If you are using a virtual environment, activate it before running "vercel dev",
3524
4083
  }
3525
4084
  const moduleToRun = devShimModule || modulePath;
3526
4085
  const argv = ["-u", "-m", moduleToRun];
3527
- (0, import_build_utils4.debug)(`Starting ASGI dev server: ${pythonCmd} ${argv.join(" ")}`);
4086
+ (0, import_build_utils6.debug)(`Starting ASGI dev server: ${pythonCmd} ${argv.join(" ")}`);
3528
4087
  const child = (0, import_child_process.spawn)(pythonCmd, argv, {
3529
4088
  cwd: workPath,
3530
4089
  env,
@@ -3572,7 +4131,7 @@ If you are using a virtual environment, activate it before running "vercel dev",
3572
4131
  child.stderr?.removeListener("data", onDetect);
3573
4132
  const port2 = Number(portMatch[1]);
3574
4133
  resolveChildReady({ port: port2, pid: child.pid });
3575
- resolve();
4134
+ resolve2();
3576
4135
  }
3577
4136
  }
3578
4137
  };
@@ -3602,7 +4161,7 @@ If you are using a virtual environment, activate it before running "vercel dev",
3602
4161
  }
3603
4162
  const moduleToRun = devShimModule || modulePath;
3604
4163
  const argv = ["-u", "-m", moduleToRun];
3605
- (0, import_build_utils4.debug)(`Starting Flask dev server: ${pythonCmd} ${argv.join(" ")}`);
4164
+ (0, import_build_utils6.debug)(`Starting Flask dev server: ${pythonCmd} ${argv.join(" ")}`);
3606
4165
  const child = (0, import_child_process.spawn)(pythonCmd, argv, {
3607
4166
  cwd: workPath,
3608
4167
  env,
@@ -3649,7 +4208,7 @@ If you are using a virtual environment, activate it before running "vercel dev",
3649
4208
  child.stderr?.removeListener("data", onDetect);
3650
4209
  const port2 = Number(portMatch[1]);
3651
4210
  resolveChildReady({ port: port2, pid: child.pid });
3652
- resolve();
4211
+ resolve2();
3653
4212
  }
3654
4213
  }
3655
4214
  };
@@ -3692,44 +4251,34 @@ If you are using a virtual environment, activate it before running "vercel dev",
3692
4251
  var readFile = (0, import_util.promisify)(import_fs5.default.readFile);
3693
4252
  var writeFile = (0, import_util.promisify)(import_fs5.default.writeFile);
3694
4253
  var version = 3;
3695
- function findDir({
3696
- file,
3697
- entryDirectory,
3698
- workPath,
3699
- fsFiles
3700
- }) {
3701
- if (fsFiles[(0, import_path5.join)(entryDirectory, file)]) {
3702
- return (0, import_path5.join)(workPath, entryDirectory);
3703
- }
3704
- if (fsFiles[file]) {
3705
- return workPath;
3706
- }
3707
- return null;
3708
- }
3709
4254
  async function downloadFilesInWorkPath({
3710
4255
  entrypoint,
3711
4256
  workPath,
3712
4257
  files,
3713
4258
  meta = {}
3714
4259
  }) {
3715
- (0, import_build_utils5.debug)("Downloading user files...");
3716
- let downloadedFiles = await (0, import_build_utils5.download)(files, workPath, meta);
4260
+ (0, import_build_utils7.debug)("Downloading user files...");
4261
+ let downloadedFiles = await (0, import_build_utils7.download)(files, workPath, meta);
3717
4262
  if (meta.isDev) {
3718
4263
  const { devCacheDir = (0, import_path5.join)(workPath, ".now", "cache") } = meta;
3719
4264
  const destCache = (0, import_path5.join)(devCacheDir, (0, import_path5.basename)(entrypoint, ".py"));
3720
- await (0, import_build_utils5.download)(downloadedFiles, destCache);
3721
- downloadedFiles = await (0, import_build_utils5.glob)("**", destCache);
4265
+ await (0, import_build_utils7.download)(downloadedFiles, destCache);
4266
+ downloadedFiles = await (0, import_build_utils7.glob)("**", destCache);
3722
4267
  workPath = destCache;
3723
4268
  }
3724
4269
  return workPath;
3725
4270
  }
3726
4271
  var build = async ({
3727
4272
  workPath,
4273
+ repoRootPath,
3728
4274
  files: originalFiles,
3729
4275
  entrypoint,
3730
4276
  meta = {},
3731
4277
  config
3732
4278
  }) => {
4279
+ const framework = config?.framework;
4280
+ let spawnEnv;
4281
+ let projectInstallCommand;
3733
4282
  workPath = await downloadFilesInWorkPath({
3734
4283
  workPath,
3735
4284
  files: originalFiles,
@@ -3745,73 +4294,96 @@ var build = async ({
3745
4294
  console.log('Failed to create "setup.cfg" file');
3746
4295
  throw err;
3747
4296
  }
3748
- let fsFiles = await (0, import_build_utils5.glob)("**", workPath);
3749
- if (!fsFiles[entrypoint] && config?.framework === "fastapi") {
3750
- const detected = await detectFastapiEntrypoint(workPath, entrypoint);
3751
- if (detected) {
3752
- (0, import_build_utils5.debug)(
3753
- `Resolved Python entrypoint to "${detected}" (configured "${entrypoint}" not found).`
3754
- );
3755
- entrypoint = detected;
3756
- } else {
3757
- const searchedList = FASTAPI_CANDIDATE_ENTRYPOINTS.join(", ");
3758
- throw new import_build_utils5.NowBuildError({
3759
- code: "FASTAPI_ENTRYPOINT_NOT_FOUND",
3760
- message: `No FastAPI entrypoint found. Searched for: ${searchedList}`
4297
+ if (framework === "fastapi" || framework === "flask") {
4298
+ const {
4299
+ cliType,
4300
+ lockfileVersion,
4301
+ packageJsonPackageManager,
4302
+ turboSupportsCorepackHome
4303
+ } = await (0, import_build_utils7.scanParentDirs)(workPath, true);
4304
+ spawnEnv = (0, import_build_utils7.getEnvForPackageManager)({
4305
+ cliType,
4306
+ lockfileVersion,
4307
+ packageJsonPackageManager,
4308
+ env: process.env,
4309
+ turboSupportsCorepackHome,
4310
+ projectCreatedAt: config?.projectSettings?.createdAt
4311
+ });
4312
+ const installCommand = config?.projectSettings?.installCommand;
4313
+ if (typeof installCommand === "string") {
4314
+ const trimmed = installCommand.trim();
4315
+ if (trimmed) {
4316
+ projectInstallCommand = trimmed;
4317
+ } else {
4318
+ console.log('Skipping "install" command...');
4319
+ }
4320
+ }
4321
+ const projectBuildCommand = config?.projectSettings?.buildCommand ?? // fallback if provided directly on config (some callers set this)
4322
+ config?.buildCommand;
4323
+ if (projectBuildCommand) {
4324
+ console.log(`Running "${projectBuildCommand}"`);
4325
+ await (0, import_build_utils7.execCommand)(projectBuildCommand, {
4326
+ env: spawnEnv,
4327
+ cwd: workPath
3761
4328
  });
4329
+ } else {
4330
+ await runPyprojectScript(
4331
+ workPath,
4332
+ ["vercel-build", "now-build", "build"],
4333
+ spawnEnv
4334
+ );
3762
4335
  }
3763
- } else if (!fsFiles[entrypoint] && config?.framework === "flask") {
3764
- const detected = await detectFlaskEntrypoint(workPath, entrypoint);
4336
+ }
4337
+ let fsFiles = await (0, import_build_utils7.glob)("**", workPath);
4338
+ if ((framework === "fastapi" || framework === "flask") && (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
4339
+ const detected = await detectPythonEntrypoint(
4340
+ config.framework,
4341
+ workPath,
4342
+ entrypoint
4343
+ );
3765
4344
  if (detected) {
3766
- (0, import_build_utils5.debug)(
4345
+ (0, import_build_utils7.debug)(
3767
4346
  `Resolved Python entrypoint to "${detected}" (configured "${entrypoint}" not found).`
3768
4347
  );
3769
4348
  entrypoint = detected;
3770
4349
  } else {
3771
- const searchedList = FLASK_CANDIDATE_ENTRYPOINTS.join(", ");
3772
- throw new import_build_utils5.NowBuildError({
3773
- code: "FLASK_ENTRYPOINT_NOT_FOUND",
3774
- message: `No Flask entrypoint found. Searched for: ${searchedList}`
4350
+ const searchedList = framework === "fastapi" ? FASTAPI_CANDIDATE_ENTRYPOINTS.join(", ") : FLASK_CANDIDATE_ENTRYPOINTS.join(", ");
4351
+ throw new import_build_utils7.NowBuildError({
4352
+ code: `${framework.toUpperCase()}_ENTRYPOINT_NOT_FOUND`,
4353
+ message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searchedList}.`,
4354
+ link: `https://vercel.com/docs/frameworks/backend/${framework}#exporting-the-${framework}-application`,
4355
+ action: "Learn More"
3775
4356
  });
3776
4357
  }
3777
4358
  }
3778
4359
  const entryDirectory = (0, import_path5.dirname)(entrypoint);
3779
- const hasReqLocal = !!fsFiles[(0, import_path5.join)(entryDirectory, "requirements.txt")];
3780
- const hasReqGlobal = !!fsFiles["requirements.txt"];
3781
- const uvLockDir = findDir({
3782
- file: "uv.lock",
4360
+ const pyprojectDir = findDir({
4361
+ file: "pyproject.toml",
3783
4362
  entryDirectory,
3784
4363
  workPath,
3785
4364
  fsFiles
3786
4365
  });
3787
- const pyprojectDir = findDir({
3788
- file: "pyproject.toml",
4366
+ const pipfileLockDir = findDir({
4367
+ file: "Pipfile.lock",
3789
4368
  entryDirectory,
3790
4369
  workPath,
3791
4370
  fsFiles
3792
4371
  });
3793
- const pipfileLockDir = fsFiles[(0, import_path5.join)(entryDirectory, "Pipfile.lock")] ? (0, import_path5.join)(workPath, entryDirectory) : fsFiles["Pipfile.lock"] ? workPath : null;
3794
- const pipfileDir = fsFiles[(0, import_path5.join)(entryDirectory, "Pipfile")] ? (0, import_path5.join)(workPath, entryDirectory) : fsFiles["Pipfile"] ? workPath : null;
3795
4372
  let declaredPythonVersion;
3796
4373
  if (pyprojectDir) {
3797
4374
  let requiresPython;
3798
4375
  try {
3799
- const pyproject = await (0, import_build_utils6.readConfigFile)((0, import_path5.join)(pyprojectDir, "pyproject.toml"));
4376
+ const pyproject = await (0, import_build_utils8.readConfigFile)((0, import_path5.join)(pyprojectDir, "pyproject.toml"));
3800
4377
  requiresPython = pyproject?.project?.["requires-python"];
3801
4378
  } catch (err) {
3802
- (0, import_build_utils5.debug)("Failed to parse pyproject.toml", err);
3803
- }
3804
- const VERSION_REGEX = /\b\d+\.\d+\b/;
3805
- const exact = requiresPython?.trim().match(VERSION_REGEX)?.[0];
3806
- if (exact) {
3807
- declaredPythonVersion = { version: exact, source: "pyproject.toml" };
3808
- (0, import_build_utils5.debug)(
3809
- `Found Python version ${exact} in pyproject.toml (requires-python: "${requiresPython}")`
3810
- );
3811
- } else if (requiresPython) {
3812
- (0, import_build_utils5.debug)(
3813
- `Could not parse Python version from pyproject.toml requires-python: "${requiresPython}"`
3814
- );
4379
+ (0, import_build_utils7.debug)("Failed to parse pyproject.toml", err);
4380
+ }
4381
+ if (typeof requiresPython === "string" && requiresPython.trim()) {
4382
+ declaredPythonVersion = {
4383
+ version: requiresPython.trim(),
4384
+ source: "pyproject.toml"
4385
+ };
4386
+ (0, import_build_utils7.debug)(`Found requires-python "${requiresPython}" in pyproject.toml`);
3815
4387
  }
3816
4388
  } else if (pipfileLockDir) {
3817
4389
  let lock = {};
@@ -3819,7 +4391,7 @@ var build = async ({
3819
4391
  const json = await readFile((0, import_path5.join)(pipfileLockDir, "Pipfile.lock"), "utf8");
3820
4392
  lock = JSON.parse(json);
3821
4393
  } catch (err) {
3822
- throw new import_build_utils5.NowBuildError({
4394
+ throw new import_build_utils7.NowBuildError({
3823
4395
  code: "INVALID_PIPFILE_LOCK",
3824
4396
  message: "Unable to parse Pipfile.lock"
3825
4397
  });
@@ -3827,167 +4399,84 @@ var build = async ({
3827
4399
  const pyFromLock = lock?._meta?.requires?.python_version;
3828
4400
  if (pyFromLock) {
3829
4401
  declaredPythonVersion = { version: pyFromLock, source: "Pipfile.lock" };
3830
- (0, import_build_utils5.debug)(`Found Python version ${pyFromLock} in Pipfile.lock`);
4402
+ (0, import_build_utils7.debug)(`Found Python version ${pyFromLock} in Pipfile.lock`);
3831
4403
  }
3832
4404
  }
3833
4405
  const pythonVersion = getSupportedPythonVersion({
3834
4406
  isDev: meta.isDev,
3835
4407
  declaredPythonVersion
3836
4408
  });
3837
- fsFiles = await (0, import_build_utils5.glob)("**", workPath);
3838
- const requirementsTxt = (0, import_path5.join)(entryDirectory, "requirements.txt");
3839
- const vendorBaseDir = (0, import_path5.join)(
3840
- workPath,
3841
- ".vercel",
3842
- "python",
3843
- `py${pythonVersion.version}`,
3844
- entryDirectory
3845
- );
3846
- try {
3847
- await import_fs5.default.promises.mkdir(vendorBaseDir, { recursive: true });
3848
- } catch (err) {
3849
- console.log("Failed to create vendor cache directory");
3850
- throw err;
3851
- }
3852
- let installationSource;
3853
- if (uvLockDir && pyprojectDir) {
3854
- installationSource = "uv.lock";
3855
- } else if (pyprojectDir) {
3856
- installationSource = "pyproject.toml";
3857
- } else if (pipfileLockDir) {
3858
- installationSource = "Pipfile.lock";
3859
- } else if (pipfileDir) {
3860
- installationSource = "Pipfile";
3861
- } else if (fsFiles[requirementsTxt] || fsFiles["requirements.txt"]) {
3862
- installationSource = "requirements.txt";
3863
- }
3864
- if (installationSource) {
3865
- console.log(
3866
- `Installing required dependencies from ${installationSource}...`
3867
- );
3868
- } else {
3869
- console.log("Installing required dependencies...");
3870
- }
3871
- let uvPath = null;
3872
- try {
3873
- uvPath = await getUvBinaryOrInstall(pythonVersion.pythonPath);
3874
- console.log(`Using uv at "${uvPath}"`);
3875
- } catch (err) {
3876
- if (uvLockDir || pyprojectDir && !hasReqLocal && !hasReqGlobal) {
3877
- console.log("Failed to install uv");
3878
- throw new Error(
3879
- `uv is required for this project but failed to install: ${err instanceof Error ? err.message : String(err)}`
3880
- );
3881
- }
3882
- (0, import_build_utils5.debug)("Failed to install uv", err);
3883
- }
3884
- await installRequirement({
4409
+ fsFiles = await (0, import_build_utils7.glob)("**", workPath);
4410
+ const venvPath = (0, import_path5.join)(workPath, ".vercel", "python", ".venv");
4411
+ await ensureVenv({
3885
4412
  pythonPath: pythonVersion.pythonPath,
3886
- pipPath: pythonVersion.pipPath,
3887
- uvPath,
3888
- dependency: "werkzeug",
3889
- version: "1.0.1",
3890
- workPath,
3891
- targetDir: vendorBaseDir,
3892
- meta
4413
+ venvPath
3893
4414
  });
3894
- let installedFromProjectFiles = false;
3895
- if (uvLockDir) {
3896
- (0, import_build_utils5.debug)('Found "uv.lock"');
3897
- if (pyprojectDir) {
3898
- const exportedReq = await exportRequirementsFromUv(pyprojectDir, uvPath, {
3899
- locked: true
3900
- });
3901
- await installRequirementsFile({
3902
- pythonPath: pythonVersion.pythonPath,
3903
- pipPath: pythonVersion.pipPath,
3904
- uvPath,
3905
- filePath: exportedReq,
4415
+ const hasCustomInstallCommand = (framework === "fastapi" || framework === "flask") && !!projectInstallCommand;
4416
+ if (hasCustomInstallCommand) {
4417
+ const baseEnv = spawnEnv || process.env;
4418
+ const pythonEnv = createVenvEnv(venvPath, baseEnv);
4419
+ pythonEnv.VERCEL_PYTHON_VENV_PATH = venvPath;
4420
+ const installCommand = projectInstallCommand;
4421
+ console.log(`Running "install" command: \`${installCommand}\`...`);
4422
+ await (0, import_build_utils7.execCommand)(installCommand, {
4423
+ env: pythonEnv,
4424
+ cwd: workPath
4425
+ });
4426
+ } else {
4427
+ let ranPyprojectInstall = false;
4428
+ if (framework === "fastapi" || framework === "flask") {
4429
+ const baseEnv = spawnEnv || process.env;
4430
+ const pythonEnv = createVenvEnv(venvPath, baseEnv);
4431
+ pythonEnv.VERCEL_PYTHON_VENV_PATH = venvPath;
4432
+ ranPyprojectInstall = await runPyprojectScript(
3906
4433
  workPath,
3907
- targetDir: vendorBaseDir,
3908
- meta
3909
- });
3910
- installedFromProjectFiles = true;
3911
- } else {
3912
- (0, import_build_utils5.debug)('Skipping uv export because "pyproject.toml" was not found');
3913
- }
3914
- } else if (pyprojectDir) {
3915
- (0, import_build_utils5.debug)('Found "pyproject.toml"');
3916
- if (hasReqLocal || hasReqGlobal) {
3917
- console.log(
3918
- "Detected both pyproject.toml and requirements.txt but no lockfile; using pyproject.toml"
4434
+ ["vercel-install", "now-install", "install"],
4435
+ pythonEnv,
4436
+ /* useUserVirtualEnv */
4437
+ false
3919
4438
  );
3920
4439
  }
3921
- const exportedReq = await exportRequirementsFromUv(pyprojectDir, uvPath, {
3922
- locked: false
3923
- });
3924
- await installRequirementsFile({
3925
- pythonPath: pythonVersion.pythonPath,
3926
- pipPath: pythonVersion.pipPath,
3927
- uvPath,
3928
- filePath: exportedReq,
3929
- workPath,
3930
- targetDir: vendorBaseDir,
3931
- meta
3932
- });
3933
- installedFromProjectFiles = true;
3934
- } else if (pipfileLockDir || pipfileDir) {
3935
- (0, import_build_utils5.debug)(`Found ${pipfileLockDir ? '"Pipfile.lock"' : '"Pipfile"'}`);
3936
- if (hasReqLocal || hasReqGlobal) {
3937
- (0, import_build_utils5.debug)('Skipping Pipfile export because "requirements.txt" exists');
3938
- } else {
3939
- const exportedReq = await exportRequirementsFromPipfile({
4440
+ if (!ranPyprojectInstall) {
4441
+ let uvPath;
4442
+ try {
4443
+ uvPath = await getUvBinaryOrInstall(pythonVersion.pythonPath);
4444
+ console.log(`Using uv at "${uvPath}"`);
4445
+ } catch (err) {
4446
+ console.log("Failed to install or locate uv");
4447
+ throw new Error(
4448
+ `uv is required for this project but failed to install: ${err instanceof Error ? err.message : String(err)}`
4449
+ );
4450
+ }
4451
+ const runtimeDependencies = framework === "flask" ? ["werkzeug>=1.0.1"] : ["werkzeug>=1.0.1", "uvicorn>=0.24"];
4452
+ const { projectDir } = await ensureUvProject({
4453
+ workPath,
4454
+ entryDirectory,
4455
+ fsFiles,
4456
+ repoRootPath,
3940
4457
  pythonPath: pythonVersion.pythonPath,
3941
4458
  pipPath: pythonVersion.pipPath,
3942
4459
  uvPath,
3943
- projectDir: pipfileLockDir || pipfileDir,
3944
- meta
4460
+ venvPath,
4461
+ meta,
4462
+ runtimeDependencies
3945
4463
  });
3946
- await installRequirementsFile({
3947
- pythonPath: pythonVersion.pythonPath,
3948
- pipPath: pythonVersion.pipPath,
4464
+ await runUvSync({
3949
4465
  uvPath,
3950
- filePath: exportedReq,
3951
- workPath,
3952
- targetDir: vendorBaseDir,
3953
- meta
4466
+ venvPath,
4467
+ projectDir,
4468
+ locked: true
3954
4469
  });
3955
- installedFromProjectFiles = true;
3956
4470
  }
3957
4471
  }
3958
- if (!installedFromProjectFiles && fsFiles[requirementsTxt]) {
3959
- (0, import_build_utils5.debug)('Found local "requirements.txt"');
3960
- const requirementsTxtPath = fsFiles[requirementsTxt].fsPath;
3961
- await installRequirementsFile({
3962
- pythonPath: pythonVersion.pythonPath,
3963
- pipPath: pythonVersion.pipPath,
3964
- uvPath,
3965
- filePath: requirementsTxtPath,
3966
- workPath,
3967
- targetDir: vendorBaseDir,
3968
- meta
3969
- });
3970
- } else if (!installedFromProjectFiles && fsFiles["requirements.txt"]) {
3971
- (0, import_build_utils5.debug)('Found global "requirements.txt"');
3972
- const requirementsTxtPath = fsFiles["requirements.txt"].fsPath;
3973
- await installRequirementsFile({
3974
- pythonPath: pythonVersion.pythonPath,
3975
- pipPath: pythonVersion.pipPath,
3976
- uvPath,
3977
- filePath: requirementsTxtPath,
3978
- workPath,
3979
- targetDir: vendorBaseDir,
3980
- meta
3981
- });
3982
- }
3983
4472
  const originalPyPath = (0, import_path5.join)(__dirname, "..", "vc_init.py");
3984
4473
  const originalHandlerPyContents = await readFile(originalPyPath, "utf8");
3985
- (0, import_build_utils5.debug)("Entrypoint is", entrypoint);
4474
+ (0, import_build_utils7.debug)("Entrypoint is", entrypoint);
3986
4475
  const moduleName = entrypoint.replace(/\//g, ".").replace(/\.py$/i, "");
3987
4476
  const vendorDir = resolveVendorDir();
3988
4477
  const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
3989
4478
  const entrypointWithSuffix = `${entrypoint}${suffix}`;
3990
- (0, import_build_utils5.debug)("Entrypoint with suffix is", entrypointWithSuffix);
4479
+ (0, import_build_utils7.debug)("Entrypoint with suffix is", entrypointWithSuffix);
3991
4480
  const handlerPyContents = originalHandlerPyContents.replace(/__VC_HANDLER_MODULE_NAME/g, moduleName).replace(/__VC_HANDLER_ENTRYPOINT/g, entrypointWithSuffix).replace(/__VC_HANDLER_VENDOR_DIR/g, vendorDir);
3992
4481
  const predefinedExcludes = [
3993
4482
  ".git/**",
@@ -4000,7 +4489,12 @@ var build = async ({
4000
4489
  "**/.venv/**",
4001
4490
  "**/venv/**",
4002
4491
  "**/__pycache__/**",
4003
- "**/public/**"
4492
+ "**/.mypy_cache/**",
4493
+ "**/.ruff_cache/**",
4494
+ "**/public/**",
4495
+ "**/pnpm-lock.yaml",
4496
+ "**/yarn.lock",
4497
+ "**/package-lock.json"
4004
4498
  ];
4005
4499
  const lambdaEnv = {};
4006
4500
  lambdaEnv.PYTHONPATH = vendorDir;
@@ -4008,26 +4502,21 @@ var build = async ({
4008
4502
  cwd: workPath,
4009
4503
  ignore: config && typeof config.excludeFiles === "string" ? [...predefinedExcludes, config.excludeFiles] : predefinedExcludes
4010
4504
  };
4011
- const files = await (0, import_build_utils5.glob)("**", globOptions);
4012
- try {
4013
- const cachedVendorAbs = (0, import_path5.join)(vendorBaseDir, resolveVendorDir());
4014
- if (import_fs5.default.existsSync(cachedVendorAbs)) {
4015
- const vendorFiles = await (0, import_build_utils5.glob)("**", cachedVendorAbs, resolveVendorDir());
4016
- for (const [p, f] of Object.entries(vendorFiles)) {
4017
- files[p] = f;
4018
- }
4019
- }
4020
- } catch (err) {
4021
- console.log("Failed to include cached vendor directory");
4022
- throw err;
4505
+ const files = await (0, import_build_utils7.glob)("**", globOptions);
4506
+ const vendorFiles = await mirrorSitePackagesIntoVendor({
4507
+ venvPath,
4508
+ vendorDirName: vendorDir
4509
+ });
4510
+ for (const [p, f] of Object.entries(vendorFiles)) {
4511
+ files[p] = f;
4023
4512
  }
4024
4513
  const handlerPyFilename = "vc__handler__python";
4025
- files[`${handlerPyFilename}.py`] = new import_build_utils5.FileBlob({ data: handlerPyContents });
4514
+ files[`${handlerPyFilename}.py`] = new import_build_utils7.FileBlob({ data: handlerPyContents });
4026
4515
  if (config.framework === "fasthtml") {
4027
4516
  const { SESSKEY = "" } = process.env;
4028
- files[".sesskey"] = new import_build_utils5.FileBlob({ data: `"${SESSKEY}"` });
4517
+ files[".sesskey"] = new import_build_utils7.FileBlob({ data: `"${SESSKEY}"` });
4029
4518
  }
4030
- const output = new import_build_utils5.Lambda({
4519
+ const output = new import_build_utils7.Lambda({
4031
4520
  files,
4032
4521
  handler: `${handlerPyFilename}.vc_handler`,
4033
4522
  runtime: pythonVersion.runtime,