@vercel/python 6.14.1 → 6.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -48,7 +48,7 @@ var require_windows = __commonJS({
48
48
  "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js"(exports, module2) {
49
49
  module2.exports = isexe;
50
50
  isexe.sync = sync;
51
- var fs5 = require("fs");
51
+ var fs6 = require("fs");
52
52
  function checkPathExt(path, options) {
53
53
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
54
54
  if (!pathext) {
@@ -73,12 +73,12 @@ var require_windows = __commonJS({
73
73
  return checkPathExt(path, options);
74
74
  }
75
75
  function isexe(path, options, cb) {
76
- fs5.stat(path, function(er, stat) {
76
+ fs6.stat(path, function(er, stat) {
77
77
  cb(er, er ? false : checkStat(stat, path, options));
78
78
  });
79
79
  }
80
80
  function sync(path, options) {
81
- return checkStat(fs5.statSync(path), path, options);
81
+ return checkStat(fs6.statSync(path), path, options);
82
82
  }
83
83
  }
84
84
  });
@@ -88,14 +88,14 @@ var require_mode = __commonJS({
88
88
  "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js"(exports, module2) {
89
89
  module2.exports = isexe;
90
90
  isexe.sync = sync;
91
- var fs5 = require("fs");
91
+ var fs6 = require("fs");
92
92
  function isexe(path, options, cb) {
93
- fs5.stat(path, function(er, stat) {
93
+ fs6.stat(path, function(er, stat) {
94
94
  cb(er, er ? false : checkStat(stat, options));
95
95
  });
96
96
  }
97
97
  function sync(path, options) {
98
- return checkStat(fs5.statSync(path), options);
98
+ return checkStat(fs6.statSync(path), options);
99
99
  }
100
100
  function checkStat(stat, options) {
101
101
  return stat.isFile() && checkMode(stat, options);
@@ -119,7 +119,7 @@ var require_mode = __commonJS({
119
119
  // ../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js
120
120
  var require_isexe = __commonJS({
121
121
  "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js"(exports, module2) {
122
- var fs5 = require("fs");
122
+ var fs6 = require("fs");
123
123
  var core;
124
124
  if (process.platform === "win32" || global.TESTING_WINDOWS) {
125
125
  core = require_windows();
@@ -395,7 +395,7 @@ var require_shebang_command = __commonJS({
395
395
  var require_readShebang = __commonJS({
396
396
  "../../node_modules/.pnpm/cross-spawn@6.0.5/node_modules/cross-spawn/lib/util/readShebang.js"(exports, module2) {
397
397
  "use strict";
398
- var fs5 = require("fs");
398
+ var fs6 = require("fs");
399
399
  var shebangCommand = require_shebang_command();
400
400
  function readShebang(command) {
401
401
  const size = 150;
@@ -408,9 +408,9 @@ var require_readShebang = __commonJS({
408
408
  }
409
409
  let fd;
410
410
  try {
411
- fd = fs5.openSync(command, "r");
412
- fs5.readSync(fd, buffer, 0, size, 0);
413
- fs5.closeSync(fd);
411
+ fd = fs6.openSync(command, "r");
412
+ fs6.readSync(fd, buffer, 0, size, 0);
413
+ fs6.closeSync(fd);
414
414
  } catch (e) {
415
415
  }
416
416
  return shebangCommand(buffer.toString());
@@ -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 debug6;
426
+ var debug7;
427
427
  if (typeof process === "object" && process.env && process.env.NODE_DEBUG && /\bsemver\b/i.test(process.env.NODE_DEBUG)) {
428
- debug6 = function() {
428
+ debug7 = 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
- debug6 = function() {
434
+ debug7 = 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
- debug6(i, src[i]);
543
+ debug7(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
- debug6("SemVer", version2, options);
610
+ debug7("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
- debug6("SemVer.compare", this.version, this.options, other);
657
+ debug7("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
- debug6("prerelease compare", i2, a, b);
684
+ debug7("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
- debug6("comparator", comp, options);
938
+ debug7("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
- debug6("comp", this);
947
+ debug7("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
- debug6("Comparator.test", version2, this.options.loose);
970
+ debug7("Comparator.test", version2, this.options.loose);
971
971
  if (this.semver === ANY) {
972
972
  return true;
973
973
  }
@@ -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
- debug6("hyphen replace", range);
1053
+ debug7("hyphen replace", range);
1054
1054
  range = range.replace(safeRe[COMPARATORTRIM], comparatorTrimReplace);
1055
- debug6("comparator trim", range, safeRe[COMPARATORTRIM]);
1055
+ debug7("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
- debug6("comp", comp, options);
1095
+ debug7("comp", comp, options);
1096
1096
  comp = replaceCarets(comp, options);
1097
- debug6("caret", comp);
1097
+ debug7("caret", comp);
1098
1098
  comp = replaceTildes(comp, options);
1099
- debug6("tildes", comp);
1099
+ debug7("tildes", comp);
1100
1100
  comp = replaceXRanges(comp, options);
1101
- debug6("xrange", comp);
1101
+ debug7("xrange", comp);
1102
1102
  comp = replaceStars(comp, options);
1103
- debug6("stars", comp);
1103
+ debug7("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
- debug6("tilde", comp, _, M, m, p, pr);
1117
+ debug7("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
- debug6("replaceTilde pr", pr);
1126
+ debug7("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
- debug6("tilde return", ret);
1131
+ debug7("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
- debug6("caret", comp, options);
1141
+ debug7("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
- debug6("caret", comp, _, M, m, p, pr);
1144
+ debug7("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
- debug6("replaceCaret pr", pr);
1157
+ debug7("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
- debug6("no pr");
1168
+ debug7("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
- debug6("caret return", ret);
1179
+ debug7("caret return", ret);
1180
1180
  return ret;
1181
1181
  });
1182
1182
  }
1183
1183
  function replaceXRanges(comp, options) {
1184
- debug6("replaceXRanges", comp, options);
1184
+ debug7("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
- debug6("xRange", comp, ret, gtlt, M, m, p, pr);
1193
+ debug7("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
- debug6("xRange return", ret);
1236
+ debug7("xRange return", ret);
1237
1237
  return ret;
1238
1238
  });
1239
1239
  }
1240
1240
  function replaceStars(comp, options) {
1241
- debug6("replaceStars", comp, options);
1241
+ debug7("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
- debug6(set[i2].semver);
1289
+ debug7(set[i2].semver);
1290
1290
  if (set[i2].semver === ANY) {
1291
1291
  continue;
1292
1292
  }
@@ -1895,9 +1895,9 @@ var require_pump = __commonJS({
1895
1895
  "../../node_modules/.pnpm/pump@3.0.2/node_modules/pump/index.js"(exports, module2) {
1896
1896
  var once = require_once();
1897
1897
  var eos = require_end_of_stream();
1898
- var fs5;
1898
+ var fs6;
1899
1899
  try {
1900
- fs5 = require("fs");
1900
+ fs6 = require("fs");
1901
1901
  } catch (e) {
1902
1902
  }
1903
1903
  var noop = function() {
@@ -1909,9 +1909,9 @@ var require_pump = __commonJS({
1909
1909
  var isFS = function(stream) {
1910
1910
  if (!ancient)
1911
1911
  return false;
1912
- if (!fs5)
1912
+ if (!fs6)
1913
1913
  return false;
1914
- return (stream instanceof (fs5.ReadStream || noop) || stream instanceof (fs5.WriteStream || noop)) && isFn(stream.close);
1914
+ return (stream instanceof (fs6.ReadStream || noop) || stream instanceof (fs6.WriteStream || noop)) && isFn(stream.close);
1915
1915
  };
1916
1916
  var isRequest = function(stream) {
1917
1917
  return stream.setHeader && isFn(stream.abort);
@@ -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: join7, delimiter: delimiter2, sep: sep2, posix } = require("path");
2654
+ var { join: join8, delimiter: delimiter2, sep: sep2, posix } = require("path");
2655
2655
  var isWindows = process.platform === "win32";
2656
2656
  var rSlash = new RegExp(`[${posix.sep}${sep2 === posix.sep ? "" : sep2}]`.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 + join7(pathPart, cmd);
2683
+ return prefix + join8(pathPart, cmd);
2684
2684
  };
2685
2685
  var which2 = async (cmd, opt = {}) => {
2686
2686
  const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
@@ -2743,21 +2743,20 @@ __export(src_exports, {
2743
2743
  downloadFilesInWorkPath: () => downloadFilesInWorkPath,
2744
2744
  installRequirement: () => installRequirement,
2745
2745
  installRequirementsFile: () => installRequirementsFile,
2746
- shouldEnableRuntimeInstall: () => shouldEnableRuntimeInstall,
2747
2746
  shouldServe: () => shouldServe,
2748
2747
  startDevServer: () => startDevServer,
2749
2748
  version: () => version
2750
2749
  });
2751
2750
  module.exports = __toCommonJS(src_exports);
2752
- var import_fs5 = __toESM(require("fs"));
2753
- var import_util = require("util");
2754
- var import_path7 = require("path");
2751
+ var import_fs6 = __toESM(require("fs"));
2752
+ var import_util2 = require("util");
2753
+ var import_path8 = require("path");
2755
2754
 
2756
2755
  // src/runtime-version.ts
2757
- var VERCEL_RUNTIME_VERSION = "0.4.1";
2756
+ var VERCEL_RUNTIME_VERSION = "0.5.0";
2758
2757
 
2759
2758
  // src/index.ts
2760
- var import_build_utils8 = require("@vercel/build-utils");
2759
+ var import_build_utils9 = require("@vercel/build-utils");
2761
2760
 
2762
2761
  // src/install.ts
2763
2762
  var import_execa3 = __toESM(require_execa());
@@ -3418,8 +3417,6 @@ function isInstalled({ version: version2 }) {
3418
3417
  }
3419
3418
 
3420
3419
  // src/install.ts
3421
- var LAMBDA_SIZE_THRESHOLD_BYTES = 249 * 1024 * 1024;
3422
- var LAMBDA_EPHEMERAL_STORAGE_BYTES = 500 * 1024 * 1024;
3423
3420
  var makeDependencyCheckCode = (dependency) => `
3424
3421
  from importlib import util
3425
3422
  dep = '${dependency}'.replace('-', '_')
@@ -3739,38 +3736,302 @@ async function installRequirementsFile({
3739
3736
  targetDir
3740
3737
  );
3741
3738
  }
3742
- async function mirrorSitePackagesIntoVendor({
3739
+
3740
+ // src/dependency-externalizer.ts
3741
+ var import_fs4 = __toESM(require("fs"));
3742
+ var import_util = require("util");
3743
+ var import_path5 = require("path");
3744
+ var import_build_utils5 = require("@vercel/build-utils");
3745
+ var import_python_analysis2 = require("@vercel/python-analysis");
3746
+ var readFile = (0, import_util.promisify)(import_fs4.default.readFile);
3747
+ var LAMBDA_SIZE_THRESHOLD_BYTES = 249 * 1024 * 1024;
3748
+ var LAMBDA_PACKING_TARGET_BYTES = 245 * 1024 * 1024;
3749
+ var LAMBDA_EPHEMERAL_STORAGE_BYTES = 500 * 1024 * 1024;
3750
+ var PythonDependencyExternalizer = class {
3751
+ constructor(options) {
3752
+ // Populated by analyze()
3753
+ this.allVendorFiles = {};
3754
+ this.totalBundleSize = 0;
3755
+ this.analyzed = false;
3756
+ this.venvPath = options.venvPath;
3757
+ this.vendorDir = options.vendorDir;
3758
+ this.workPath = options.workPath;
3759
+ this.uvLockPath = options.uvLockPath;
3760
+ this.uvProjectDir = options.uvProjectDir;
3761
+ this.projectName = options.projectName;
3762
+ this.noBuildCheckFailed = options.noBuildCheckFailed;
3763
+ this.pythonPath = options.pythonPath;
3764
+ }
3765
+ /**
3766
+ * Analyze the bundle: mirror all vendor files, calculate total size,
3767
+ * and determine whether runtime installation is needed.
3768
+ * Must be called before generateBundle().
3769
+ */
3770
+ async analyze(files) {
3771
+ this.allVendorFiles = await mirrorPackagesIntoVendor({
3772
+ venvPath: this.venvPath,
3773
+ vendorDirName: this.vendorDir
3774
+ });
3775
+ const tempFilesForSizing = { ...files };
3776
+ for (const [p, f] of Object.entries(this.allVendorFiles)) {
3777
+ tempFilesForSizing[p] = f;
3778
+ }
3779
+ this.totalBundleSize = await calculateBundleSize(tempFilesForSizing);
3780
+ this.analyzed = true;
3781
+ const totalBundleSizeMB = (this.totalBundleSize / (1024 * 1024)).toFixed(2);
3782
+ (0, import_build_utils5.debug)(`Total bundle size: ${totalBundleSizeMB} MB`);
3783
+ const overLambdaLimit = shouldEnableRuntimeInstall({
3784
+ totalBundleSize: this.totalBundleSize,
3785
+ uvLockPath: this.uvLockPath
3786
+ });
3787
+ return { overLambdaLimit, allVendorFiles: this.allVendorFiles };
3788
+ }
3789
+ /**
3790
+ * Generate the optimally-packed Lambda bundle.
3791
+ * Mutates `files` in place: adds vendor files (private + knapsack-selected
3792
+ * public), runtime config, and uv binary.
3793
+ * Must be called after analyze().
3794
+ */
3795
+ async generateBundle(files) {
3796
+ if (!this.analyzed) {
3797
+ throw new Error(
3798
+ "PythonDependencyExternalizer.analyze() must be called before generateBundle()"
3799
+ );
3800
+ }
3801
+ if (!this.uvLockPath || !this.uvProjectDir) {
3802
+ throw new import_build_utils5.NowBuildError({
3803
+ code: "RUNTIME_DEPENDENCY_INSTALLATION_FAILED",
3804
+ message: "Runtime dependency installation requires a uv.lock file and project directory."
3805
+ });
3806
+ }
3807
+ const totalBundleSizeMB = (this.totalBundleSize / (1024 * 1024)).toFixed(2);
3808
+ console.log(
3809
+ `Bundle size (${totalBundleSizeMB} MB) exceeds limit. Enabling runtime dependency installation.`
3810
+ );
3811
+ if (this.totalBundleSize > LAMBDA_EPHEMERAL_STORAGE_BYTES) {
3812
+ const ephemeralLimitMB = (LAMBDA_EPHEMERAL_STORAGE_BYTES / (1024 * 1024)).toFixed(0);
3813
+ throw new import_build_utils5.NowBuildError({
3814
+ code: "LAMBDA_SIZE_EXCEEDED",
3815
+ message: `Total dependency size (${totalBundleSizeMB} MB) exceeds Lambda ephemeral storage limit (${ephemeralLimitMB} MB). Even with runtime dependency installation, all packages must fit within the ${ephemeralLimitMB} MB ephemeral storage available to Lambda functions. Consider removing unused dependencies or splitting your application into smaller functions.`
3816
+ });
3817
+ }
3818
+ if (this.noBuildCheckFailed) {
3819
+ throw new import_build_utils5.NowBuildError({
3820
+ code: "RUNTIME_DEPENDENCY_INSTALLATION_FAILED",
3821
+ message: `Bundle size exceeds the Lambda limit and requires runtime dependency installation, but some packages in your uv.lock file do not have pre-built binary wheels available.
3822
+ Runtime dependency installation requires all public packages to have binary wheels.
3823
+
3824
+ To fix this, either:
3825
+ 1. Regenerate your lock file with: uv lock --upgrade --no-build, or
3826
+ 2. Switch the problematic packages to ones that have pre-built wheels available`
3827
+ });
3828
+ }
3829
+ let lockContent;
3830
+ try {
3831
+ lockContent = await readFile(this.uvLockPath, "utf8");
3832
+ } catch (error) {
3833
+ if (error instanceof Error) {
3834
+ console.log(
3835
+ `Failed to read uv.lock file at "${this.uvLockPath}": ${error.message}`
3836
+ );
3837
+ } else {
3838
+ console.log(
3839
+ `Failed to read uv.lock file at "${this.uvLockPath}": ${String(error)}`
3840
+ );
3841
+ }
3842
+ throw new import_build_utils5.NowBuildError({
3843
+ code: "RUNTIME_DEPENDENCY_INSTALLATION_FAILED",
3844
+ message: `Failed to read uv.lock file at "${this.uvLockPath}"`
3845
+ });
3846
+ }
3847
+ let lockFile;
3848
+ try {
3849
+ lockFile = (0, import_python_analysis2.parseUvLock)(lockContent, this.uvLockPath);
3850
+ } catch (error) {
3851
+ if (error instanceof import_python_analysis2.PythonAnalysisError) {
3852
+ if (error.fileContent) {
3853
+ console.log(
3854
+ `Failed to parse "${error.path}". File content:
3855
+ ${error.fileContent}`
3856
+ );
3857
+ }
3858
+ throw new import_build_utils5.NowBuildError({
3859
+ code: error.code,
3860
+ message: error.message
3861
+ });
3862
+ }
3863
+ throw error;
3864
+ }
3865
+ const excludePackages = [];
3866
+ if (this.projectName) {
3867
+ excludePackages.push(this.projectName);
3868
+ (0, import_build_utils5.debug)(
3869
+ `Excluding project package "${this.projectName}" from runtime installation`
3870
+ );
3871
+ }
3872
+ const classification = (0, import_python_analysis2.classifyPackages)({
3873
+ lockFile,
3874
+ excludePackages
3875
+ });
3876
+ (0, import_build_utils5.debug)(
3877
+ `Package classification: ${classification.privatePackages.length} private, ${classification.publicPackages.length} public`
3878
+ );
3879
+ if (classification.publicPackages.length === 0) {
3880
+ throw new import_build_utils5.NowBuildError({
3881
+ code: "RUNTIME_DEPENDENCY_INSTALLATION_FAILED",
3882
+ message: "Bundle size exceeds limit but no public packages found for runtime installation."
3883
+ });
3884
+ }
3885
+ const packageSizes = await calculatePerPackageSizes(this.venvPath);
3886
+ const alwaysBundled = [
3887
+ ...classification.privatePackages,
3888
+ "vercel-runtime",
3889
+ "vercel_runtime"
3890
+ ];
3891
+ const alwaysBundledFiles = await mirrorPackagesIntoVendor({
3892
+ venvPath: this.venvPath,
3893
+ vendorDirName: this.vendorDir,
3894
+ includePackages: alwaysBundled
3895
+ });
3896
+ const baseFiles = { ...files };
3897
+ for (const [p, f] of Object.entries(alwaysBundledFiles)) {
3898
+ baseFiles[p] = f;
3899
+ }
3900
+ const fixedOverhead = await calculateBundleSize(baseFiles);
3901
+ let runtimeToolingOverhead = 0;
3902
+ if (process.env.VERCEL_BUILD_IMAGE) {
3903
+ try {
3904
+ const uvBinaryPath = await getUvBinaryForBundling(this.pythonPath);
3905
+ const uvStats = await import_fs4.default.promises.stat(uvBinaryPath);
3906
+ runtimeToolingOverhead = uvStats.size;
3907
+ } catch {
3908
+ runtimeToolingOverhead = 50 * 1024 * 1024;
3909
+ }
3910
+ }
3911
+ const remainingCapacity = LAMBDA_PACKING_TARGET_BYTES - fixedOverhead - runtimeToolingOverhead;
3912
+ (0, import_build_utils5.debug)(
3913
+ `Fixed overhead: ${(fixedOverhead / (1024 * 1024)).toFixed(2)} MB, runtime tooling: ${(runtimeToolingOverhead / (1024 * 1024)).toFixed(2)} MB, remaining capacity for public packages: ${(remainingCapacity / (1024 * 1024)).toFixed(2)} MB`
3914
+ );
3915
+ const publicPackageSizes = new Map(
3916
+ [...packageSizes].filter(
3917
+ ([name]) => classification.publicPackages.includes(name)
3918
+ )
3919
+ );
3920
+ const bundledPublic = lambdaKnapsack(publicPackageSizes, remainingCapacity);
3921
+ const allBundledPackages = [...alwaysBundled, ...bundledPublic];
3922
+ const selectedVendorFiles = await mirrorPackagesIntoVendor({
3923
+ venvPath: this.venvPath,
3924
+ vendorDirName: this.vendorDir,
3925
+ includePackages: allBundledPackages
3926
+ });
3927
+ for (const [p, f] of Object.entries(selectedVendorFiles)) {
3928
+ files[p] = f;
3929
+ }
3930
+ const bundledPackagesForConfig = [
3931
+ ...classification.privatePackages,
3932
+ ...bundledPublic
3933
+ ];
3934
+ const projectDirRel = (0, import_path5.relative)(this.workPath, this.uvProjectDir);
3935
+ const uvLockRel = (0, import_path5.relative)(this.workPath, this.uvLockPath);
3936
+ const isOutsideWorkPath = projectDirRel.startsWith("..") || uvLockRel.startsWith("..");
3937
+ if (isOutsideWorkPath) {
3938
+ const srcPyproject = (0, import_path5.join)(this.uvProjectDir, "pyproject.toml");
3939
+ files[`${UV_BUNDLE_DIR}/pyproject.toml`] = new import_build_utils5.FileFsRef({
3940
+ fsPath: srcPyproject
3941
+ });
3942
+ files[`${UV_BUNDLE_DIR}/uv.lock`] = new import_build_utils5.FileFsRef({
3943
+ fsPath: this.uvLockPath
3944
+ });
3945
+ }
3946
+ const runtimeConfigData = JSON.stringify({
3947
+ projectDir: isOutsideWorkPath ? UV_BUNDLE_DIR : projectDirRel,
3948
+ bundledPackages: bundledPackagesForConfig
3949
+ });
3950
+ files[`${UV_BUNDLE_DIR}/_runtime_config.json`] = new import_build_utils5.FileBlob({
3951
+ data: runtimeConfigData
3952
+ });
3953
+ if (process.env.VERCEL_BUILD_IMAGE) {
3954
+ try {
3955
+ const uvBinaryPath = await getUvBinaryForBundling(this.pythonPath);
3956
+ const uvBundleDir = (0, import_path5.join)(this.workPath, UV_BUNDLE_DIR);
3957
+ const uvLocalPath = (0, import_path5.join)(uvBundleDir, "uv");
3958
+ await import_fs4.default.promises.mkdir(uvBundleDir, { recursive: true });
3959
+ await import_fs4.default.promises.copyFile(uvBinaryPath, uvLocalPath);
3960
+ await import_fs4.default.promises.chmod(uvLocalPath, 493);
3961
+ const uvBundlePath = `${UV_BUNDLE_DIR}/uv`;
3962
+ files[uvBundlePath] = new import_build_utils5.FileFsRef({
3963
+ fsPath: uvLocalPath,
3964
+ mode: 33261
3965
+ // Regular file + executable
3966
+ });
3967
+ (0, import_build_utils5.debug)(`Bundled uv binary from ${uvBinaryPath} to ${uvLocalPath}`);
3968
+ } catch (err) {
3969
+ throw new import_build_utils5.NowBuildError({
3970
+ code: "RUNTIME_DEPENDENCY_INSTALLATION_FAILED",
3971
+ message: `Failed to bundle uv binary for runtime installation: ${err instanceof Error ? err.message : String(err)}`
3972
+ });
3973
+ }
3974
+ }
3975
+ const finalBundleSize = await calculateBundleSize(files);
3976
+ if (finalBundleSize > LAMBDA_SIZE_THRESHOLD_BYTES) {
3977
+ const finalSizeMB = (finalBundleSize / (1024 * 1024)).toFixed(2);
3978
+ const limitMB = (LAMBDA_SIZE_THRESHOLD_BYTES / (1024 * 1024)).toFixed(0);
3979
+ throw new import_build_utils5.NowBuildError({
3980
+ code: "LAMBDA_SIZE_EXCEEDED",
3981
+ message: `Bundle size (${finalSizeMB} MB) exceeds Lambda limit (${limitMB} MB) even after deferring public packages to runtime installation. This usually means your private packages or source code are too large. Consider reducing the size of private dependencies or splitting your application.`
3982
+ });
3983
+ }
3984
+ }
3985
+ };
3986
+ function shouldEnableRuntimeInstall({
3987
+ totalBundleSize,
3988
+ uvLockPath
3989
+ }) {
3990
+ const pythonOnHiveEnabled = process.env.VERCEL_PYTHON_ON_HIVE === "1" || process.env.VERCEL_PYTHON_ON_HIVE === "true";
3991
+ if (pythonOnHiveEnabled) {
3992
+ return false;
3993
+ } else if (totalBundleSize > LAMBDA_SIZE_THRESHOLD_BYTES && uvLockPath !== null) {
3994
+ return true;
3995
+ }
3996
+ return false;
3997
+ }
3998
+ async function mirrorPackagesIntoVendor({
3743
3999
  venvPath,
3744
- vendorDirName
4000
+ vendorDirName,
4001
+ includePackages
3745
4002
  }) {
3746
4003
  const vendorFiles = {};
3747
- try {
3748
- const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
3749
- for (const dir of sitePackageDirs) {
3750
- if (!import_fs3.default.existsSync(dir))
4004
+ if (includePackages && includePackages.length === 0) {
4005
+ return vendorFiles;
4006
+ }
4007
+ const includeSet = includePackages ? new Set(includePackages.map(import_python_analysis2.normalizePackageName)) : null;
4008
+ const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
4009
+ for (const dir of sitePackageDirs) {
4010
+ if (!import_fs4.default.existsSync(dir))
4011
+ continue;
4012
+ const resolvedDir = (0, import_path5.resolve)(dir);
4013
+ const dirPrefix = resolvedDir + import_path5.sep;
4014
+ const distributions = await (0, import_python_analysis2.scanDistributions)(dir);
4015
+ for (const [name, dist] of distributions) {
4016
+ if (includeSet && !includeSet.has(name))
3751
4017
  continue;
3752
- const resolvedDir = (0, import_path4.resolve)(dir);
3753
- const dirPrefix = resolvedDir + import_path4.sep;
3754
- const distributions = await (0, import_python_analysis.scanDistributions)(dir);
3755
- for (const dist of distributions.values()) {
3756
- for (const { path: rawPath } of dist.files) {
3757
- const filePath = rawPath.replaceAll("/", import_path4.sep);
3758
- if (!(0, import_path4.resolve)(resolvedDir, filePath).startsWith(dirPrefix)) {
3759
- continue;
3760
- }
3761
- if (filePath.endsWith(".pyc") || filePath.split(import_path4.sep).includes("__pycache__")) {
3762
- continue;
3763
- }
3764
- const srcFsPath = (0, import_path4.join)(dir, filePath);
3765
- const bundlePath = (0, import_path4.join)(vendorDirName, filePath).replace(/\\/g, "/");
3766
- vendorFiles[bundlePath] = new import_build_utils4.FileFsRef({ fsPath: srcFsPath });
4018
+ for (const { path: rawPath } of dist.files) {
4019
+ const filePath = rawPath.replaceAll("/", import_path5.sep);
4020
+ if (!(0, import_path5.resolve)(resolvedDir, filePath).startsWith(dirPrefix)) {
4021
+ continue;
3767
4022
  }
4023
+ if (filePath.endsWith(".pyc") || filePath.split(import_path5.sep).includes("__pycache__")) {
4024
+ continue;
4025
+ }
4026
+ const srcFsPath = (0, import_path5.join)(dir, filePath);
4027
+ const bundlePath = (0, import_path5.join)(vendorDirName, filePath).replace(/\\/g, "/");
4028
+ vendorFiles[bundlePath] = new import_build_utils5.FileFsRef({ fsPath: srcFsPath });
3768
4029
  }
3769
4030
  }
3770
- } catch (err) {
3771
- console.log("Failed to collect site-packages from virtual environment");
3772
- throw err;
3773
4031
  }
4032
+ (0, import_build_utils5.debug)(
4033
+ `Mirrored ${Object.keys(vendorFiles).length} files` + (includePackages ? ` from ${includePackages.length} packages` : "")
4034
+ );
3774
4035
  return vendorFiles;
3775
4036
  }
3776
4037
  async function calculateBundleSize(files) {
@@ -3779,7 +4040,7 @@ async function calculateBundleSize(files) {
3779
4040
  const file = files[filePath];
3780
4041
  if ("fsPath" in file && file.fsPath) {
3781
4042
  try {
3782
- const stats = await import_fs3.default.promises.stat(file.fsPath);
4043
+ const stats = await import_fs4.default.promises.stat(file.fsPath);
3783
4044
  totalSize += stats.size;
3784
4045
  } catch (err) {
3785
4046
  console.warn(
@@ -3793,66 +4054,65 @@ async function calculateBundleSize(files) {
3793
4054
  }
3794
4055
  return totalSize;
3795
4056
  }
3796
- async function mirrorPrivatePackagesIntoVendor({
3797
- venvPath,
3798
- vendorDirName,
3799
- privatePackages
3800
- }) {
3801
- const vendorFiles = {};
3802
- if (privatePackages.length === 0) {
3803
- (0, import_build_utils4.debug)("No private packages to bundle");
3804
- return vendorFiles;
4057
+ function lambdaKnapsack(packages, capacity) {
4058
+ if (capacity <= 0) {
4059
+ return [];
3805
4060
  }
3806
- const privatePackageSet = new Set(privatePackages.map(import_python_analysis.normalizePackageName));
3807
- try {
3808
- const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
3809
- for (const dir of sitePackageDirs) {
3810
- if (!import_fs3.default.existsSync(dir))
3811
- continue;
3812
- const resolvedDir = (0, import_path4.resolve)(dir);
3813
- const dirPrefix = resolvedDir + import_path4.sep;
3814
- const distributions = await (0, import_python_analysis.scanDistributions)(dir);
3815
- for (const [name, dist] of distributions) {
3816
- if (!privatePackageSet.has(name))
4061
+ const sorted = [...packages.entries()].sort(([, a], [, b]) => b - a);
4062
+ const bundled = [];
4063
+ let remaining = capacity;
4064
+ for (const [name, size] of sorted) {
4065
+ if (size <= remaining) {
4066
+ bundled.push(name);
4067
+ remaining -= size;
4068
+ }
4069
+ }
4070
+ return bundled;
4071
+ }
4072
+ async function calculatePerPackageSizes(venvPath) {
4073
+ const sizes = /* @__PURE__ */ new Map();
4074
+ const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
4075
+ for (const dir of sitePackageDirs) {
4076
+ if (!import_fs4.default.existsSync(dir))
4077
+ continue;
4078
+ const resolvedDir = (0, import_path5.resolve)(dir);
4079
+ const dirPrefix = resolvedDir + import_path5.sep;
4080
+ const distributions = await (0, import_python_analysis2.scanDistributions)(dir);
4081
+ for (const [name, dist] of distributions) {
4082
+ let totalSize = 0;
4083
+ for (const { path: rawPath } of dist.files) {
4084
+ const filePath = rawPath.replaceAll("/", import_path5.sep);
4085
+ if (!(0, import_path5.resolve)(resolvedDir, filePath).startsWith(dirPrefix)) {
3817
4086
  continue;
3818
- for (const { path: rawPath } of dist.files) {
3819
- const filePath = rawPath.replaceAll("/", import_path4.sep);
3820
- if (!(0, import_path4.resolve)(resolvedDir, filePath).startsWith(dirPrefix)) {
3821
- continue;
3822
- }
3823
- if (filePath.endsWith(".pyc") || filePath.split(import_path4.sep).includes("__pycache__")) {
3824
- continue;
3825
- }
3826
- const srcFsPath = (0, import_path4.join)(dir, filePath);
3827
- const bundlePath = (0, import_path4.join)(vendorDirName, filePath).replace(/\\/g, "/");
3828
- vendorFiles[bundlePath] = new import_build_utils4.FileFsRef({ fsPath: srcFsPath });
4087
+ }
4088
+ if (filePath.endsWith(".pyc") || filePath.split(import_path5.sep).includes("__pycache__")) {
4089
+ continue;
4090
+ }
4091
+ try {
4092
+ const stats = await import_fs4.default.promises.stat((0, import_path5.join)(dir, filePath));
4093
+ totalSize += stats.size;
4094
+ } catch {
3829
4095
  }
3830
4096
  }
4097
+ sizes.set(name, totalSize);
3831
4098
  }
3832
- (0, import_build_utils4.debug)(
3833
- `Bundled ${Object.keys(vendorFiles).length} files from private packages`
3834
- );
3835
- } catch (err) {
3836
- console.log("Failed to collect private packages from virtual environment");
3837
- throw err;
3838
4099
  }
3839
- return vendorFiles;
4100
+ return sizes;
3840
4101
  }
3841
4102
 
3842
4103
  // src/index.ts
3843
- var import_python_analysis3 = require("@vercel/python-analysis");
3844
- var import_build_utils9 = require("@vercel/build-utils");
4104
+ var import_build_utils10 = require("@vercel/build-utils");
3845
4105
 
3846
4106
  // src/start-dev-server.ts
3847
4107
  var import_child_process2 = require("child_process");
3848
- var import_fs4 = require("fs");
3849
- var import_path6 = require("path");
3850
- var import_build_utils7 = require("@vercel/build-utils");
4108
+ var import_fs5 = require("fs");
4109
+ var import_path7 = require("path");
4110
+ var import_build_utils8 = require("@vercel/build-utils");
3851
4111
 
3852
4112
  // src/entrypoint.ts
3853
- var import_path5 = require("path");
3854
- var import_build_utils5 = require("@vercel/build-utils");
4113
+ var import_path6 = require("path");
3855
4114
  var import_build_utils6 = require("@vercel/build-utils");
4115
+ var import_build_utils7 = require("@vercel/build-utils");
3856
4116
  var PYTHON_ENTRYPOINT_FILENAMES = [
3857
4117
  "app",
3858
4118
  "index",
@@ -3864,11 +4124,11 @@ var PYTHON_ENTRYPOINT_FILENAMES = [
3864
4124
  var PYTHON_ENTRYPOINT_DIRS = ["", "src", "app", "api"];
3865
4125
  var PYTHON_CANDIDATE_ENTRYPOINTS = PYTHON_ENTRYPOINT_FILENAMES.flatMap(
3866
4126
  (filename) => PYTHON_ENTRYPOINT_DIRS.map(
3867
- (dir) => import_path5.posix.join(dir, `${filename}.py`)
4127
+ (dir) => import_path6.posix.join(dir, `${filename}.py`)
3868
4128
  )
3869
4129
  );
3870
4130
  async function getPyprojectEntrypoint(workPath) {
3871
- const pyprojectData = await (0, import_build_utils6.readConfigFile)((0, import_path5.join)(workPath, "pyproject.toml"));
4131
+ const pyprojectData = await (0, import_build_utils7.readConfigFile)((0, import_path6.join)(workPath, "pyproject.toml"));
3872
4132
  if (!pyprojectData)
3873
4133
  return null;
3874
4134
  const scripts = pyprojectData.project?.scripts;
@@ -3881,7 +4141,7 @@ async function getPyprojectEntrypoint(workPath) {
3881
4141
  const modulePath = match[1];
3882
4142
  const relPath = modulePath.replace(/\./g, "/");
3883
4143
  try {
3884
- const fsFiles = await (0, import_build_utils5.glob)("**", workPath);
4144
+ const fsFiles = await (0, import_build_utils6.glob)("**", workPath);
3885
4145
  const candidates = [`${relPath}.py`, `${relPath}/__init__.py`];
3886
4146
  for (const candidate of candidates) {
3887
4147
  if (fsFiles[candidate])
@@ -3889,18 +4149,18 @@ async function getPyprojectEntrypoint(workPath) {
3889
4149
  }
3890
4150
  return null;
3891
4151
  } catch {
3892
- (0, import_build_utils5.debug)("Failed to discover Python entrypoint from pyproject.toml");
4152
+ (0, import_build_utils6.debug)("Failed to discover Python entrypoint from pyproject.toml");
3893
4153
  return null;
3894
4154
  }
3895
4155
  }
3896
4156
  async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
3897
4157
  const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
3898
4158
  try {
3899
- const fsFiles = await (0, import_build_utils5.glob)("**", workPath);
4159
+ const fsFiles = await (0, import_build_utils6.glob)("**", workPath);
3900
4160
  if (fsFiles[entry]) {
3901
- const isValid = await (0, import_build_utils5.isPythonEntrypoint)(fsFiles[entry]);
4161
+ const isValid = await (0, import_build_utils6.isPythonEntrypoint)(fsFiles[entry]);
3902
4162
  if (isValid) {
3903
- (0, import_build_utils5.debug)(`Using configured Python entrypoint: ${entry}`);
4163
+ (0, import_build_utils6.debug)(`Using configured Python entrypoint: ${entry}`);
3904
4164
  return entry;
3905
4165
  }
3906
4166
  }
@@ -3908,15 +4168,15 @@ async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
3908
4168
  (c) => !!fsFiles[c]
3909
4169
  );
3910
4170
  for (const candidate of candidates) {
3911
- const isValid = await (0, import_build_utils5.isPythonEntrypoint)(fsFiles[candidate]);
4171
+ const isValid = await (0, import_build_utils6.isPythonEntrypoint)(fsFiles[candidate]);
3912
4172
  if (isValid) {
3913
- (0, import_build_utils5.debug)(`Detected Python entrypoint: ${candidate}`);
4173
+ (0, import_build_utils6.debug)(`Detected Python entrypoint: ${candidate}`);
3914
4174
  return candidate;
3915
4175
  }
3916
4176
  }
3917
4177
  return null;
3918
4178
  } catch {
3919
- (0, import_build_utils5.debug)("Failed to discover Python entrypoint");
4179
+ (0, import_build_utils6.debug)("Failed to discover Python entrypoint");
3920
4180
  return null;
3921
4181
  }
3922
4182
  }
@@ -3931,7 +4191,7 @@ async function detectPythonEntrypoint(_framework, workPath, configuredEntrypoint
3931
4191
  }
3932
4192
 
3933
4193
  // src/start-dev-server.ts
3934
- var import_python_analysis2 = require("@vercel/python-analysis");
4194
+ var import_python_analysis3 = require("@vercel/python-analysis");
3935
4195
  function silenceNodeWarnings() {
3936
4196
  const original = process.emitWarning.bind(
3937
4197
  process
@@ -3990,17 +4250,17 @@ async function syncDependencies({
3990
4250
  let { manifestType, manifestPath } = installInfo;
3991
4251
  const manifest = installInfo.pythonPackage?.manifest;
3992
4252
  if (!manifestType || !manifestPath) {
3993
- (0, import_build_utils7.debug)("No Python project manifest found, skipping dependency sync");
4253
+ (0, import_build_utils8.debug)("No Python project manifest found, skipping dependency sync");
3994
4254
  return;
3995
4255
  }
3996
4256
  if (manifest?.origin && manifestType === "pyproject.toml") {
3997
- const syncDir = (0, import_path6.join)(workPath, ".vercel", "python", "sync");
3998
- (0, import_fs4.mkdirSync)(syncDir, { recursive: true });
3999
- const tempPyproject = (0, import_path6.join)(syncDir, "pyproject.toml");
4000
- const content = (0, import_python_analysis2.stringifyManifest)(manifest.data);
4001
- (0, import_fs4.writeFileSync)(tempPyproject, content, "utf8");
4257
+ const syncDir = (0, import_path7.join)(workPath, ".vercel", "python", "sync");
4258
+ (0, import_fs5.mkdirSync)(syncDir, { recursive: true });
4259
+ const tempPyproject = (0, import_path7.join)(syncDir, "pyproject.toml");
4260
+ const content = (0, import_python_analysis3.stringifyManifest)(manifest.data);
4261
+ (0, import_fs5.writeFileSync)(tempPyproject, content, "utf8");
4002
4262
  manifestPath = tempPyproject;
4003
- (0, import_build_utils7.debug)(
4263
+ (0, import_build_utils8.debug)(
4004
4264
  `Wrote converted ${manifest.origin.kind} manifest to ${tempPyproject}`
4005
4265
  );
4006
4266
  }
@@ -4033,7 +4293,7 @@ async function syncDependencies({
4033
4293
  for (const [channel, chunk] of captured) {
4034
4294
  (channel === "stdout" ? writeOut : writeErr)(chunk.toString());
4035
4295
  }
4036
- throw new import_build_utils7.NowBuildError({
4296
+ throw new import_build_utils8.NowBuildError({
4037
4297
  code: "PYTHON_DEPENDENCY_SYNC_FAILED",
4038
4298
  message: `Failed to install Python dependencies from ${manifestType}: ${err instanceof Error ? err.message : String(err)}`
4039
4299
  });
@@ -4048,14 +4308,14 @@ async function runSync({
4048
4308
  onStdout,
4049
4309
  onStderr
4050
4310
  }) {
4051
- const projectDir = (0, import_path6.dirname)(manifestPath);
4311
+ const projectDir = (0, import_path7.dirname)(manifestPath);
4052
4312
  const pip = uvPath ? { cmd: uvPath, prefix: ["pip", "install"] } : { cmd: pythonBin, prefix: ["-m", "pip", "install"] };
4053
4313
  let spawnCmd;
4054
4314
  let spawnArgs;
4055
4315
  switch (manifestType) {
4056
4316
  case "uv.lock": {
4057
4317
  if (!uvPath) {
4058
- throw new import_build_utils7.NowBuildError({
4318
+ throw new import_build_utils8.NowBuildError({
4059
4319
  code: "PYTHON_DEPENDENCY_SYNC_FAILED",
4060
4320
  message: "uv is required to install dependencies from uv.lock.",
4061
4321
  link: "https://docs.astral.sh/uv/getting-started/installation/",
@@ -4077,11 +4337,11 @@ async function runSync({
4077
4337
  break;
4078
4338
  }
4079
4339
  default:
4080
- (0, import_build_utils7.debug)(`Unknown manifest type: ${manifestType}`);
4340
+ (0, import_build_utils8.debug)(`Unknown manifest type: ${manifestType}`);
4081
4341
  return;
4082
4342
  }
4083
4343
  await new Promise((resolve2, reject) => {
4084
- (0, import_build_utils7.debug)(`Running "${spawnCmd} ${spawnArgs.join(" ")}" in ${projectDir}...`);
4344
+ (0, import_build_utils8.debug)(`Running "${spawnCmd} ${spawnArgs.join(" ")}" in ${projectDir}...`);
4085
4345
  const child = (0, import_child_process2.spawn)(spawnCmd, spawnArgs, {
4086
4346
  cwd: projectDir,
4087
4347
  env: getProtectedUvEnv(env),
@@ -4128,12 +4388,12 @@ function installGlobalCleanupHandlers() {
4128
4388
  try {
4129
4389
  process.kill(info.pid, "SIGTERM");
4130
4390
  } catch (err) {
4131
- (0, import_build_utils7.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
4391
+ (0, import_build_utils8.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
4132
4392
  }
4133
4393
  try {
4134
4394
  process.kill(info.pid, "SIGKILL");
4135
4395
  } catch (err) {
4136
- (0, import_build_utils7.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
4396
+ (0, import_build_utils8.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
4137
4397
  }
4138
4398
  PERSISTENT_SERVERS.delete(key);
4139
4399
  }
@@ -4141,7 +4401,7 @@ function installGlobalCleanupHandlers() {
4141
4401
  try {
4142
4402
  restoreWarnings();
4143
4403
  } catch (err) {
4144
- (0, import_build_utils7.debug)(`Error restoring warnings: ${err}`);
4404
+ (0, import_build_utils8.debug)(`Error restoring warnings: ${err}`);
4145
4405
  }
4146
4406
  restoreWarnings = null;
4147
4407
  }
@@ -4158,49 +4418,49 @@ function installGlobalCleanupHandlers() {
4158
4418
  }
4159
4419
  function createDevAsgiShim(workPath, modulePath) {
4160
4420
  try {
4161
- const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4162
- (0, import_fs4.mkdirSync)(vercelPythonDir, { recursive: true });
4163
- const shimPath = (0, import_path6.join)(vercelPythonDir, `${ASGI_SHIM_MODULE}.py`);
4164
- const templatePath = (0, import_path6.join)(__dirname, "..", `${ASGI_SHIM_MODULE}.py`);
4165
- const template = (0, import_fs4.readFileSync)(templatePath, "utf8");
4421
+ const vercelPythonDir = (0, import_path7.join)(workPath, ".vercel", "python");
4422
+ (0, import_fs5.mkdirSync)(vercelPythonDir, { recursive: true });
4423
+ const shimPath = (0, import_path7.join)(vercelPythonDir, `${ASGI_SHIM_MODULE}.py`);
4424
+ const templatePath = (0, import_path7.join)(__dirname, "..", `${ASGI_SHIM_MODULE}.py`);
4425
+ const template = (0, import_fs5.readFileSync)(templatePath, "utf8");
4166
4426
  const shimSource = template.replace(/__VC_DEV_MODULE_PATH__/g, modulePath);
4167
- (0, import_fs4.writeFileSync)(shimPath, shimSource, "utf8");
4168
- (0, import_build_utils7.debug)(`Prepared Python dev static shim at ${shimPath}`);
4427
+ (0, import_fs5.writeFileSync)(shimPath, shimSource, "utf8");
4428
+ (0, import_build_utils8.debug)(`Prepared Python dev static shim at ${shimPath}`);
4169
4429
  return ASGI_SHIM_MODULE;
4170
4430
  } catch (err) {
4171
- (0, import_build_utils7.debug)(`Failed to prepare dev static shim: ${err?.message || err}`);
4431
+ (0, import_build_utils8.debug)(`Failed to prepare dev static shim: ${err?.message || err}`);
4172
4432
  return null;
4173
4433
  }
4174
4434
  }
4175
4435
  function createDevWsgiShim(workPath, modulePath) {
4176
4436
  try {
4177
- const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4178
- (0, import_fs4.mkdirSync)(vercelPythonDir, { recursive: true });
4179
- const shimPath = (0, import_path6.join)(vercelPythonDir, `${WSGI_SHIM_MODULE}.py`);
4180
- const templatePath = (0, import_path6.join)(__dirname, "..", `${WSGI_SHIM_MODULE}.py`);
4181
- const template = (0, import_fs4.readFileSync)(templatePath, "utf8");
4437
+ const vercelPythonDir = (0, import_path7.join)(workPath, ".vercel", "python");
4438
+ (0, import_fs5.mkdirSync)(vercelPythonDir, { recursive: true });
4439
+ const shimPath = (0, import_path7.join)(vercelPythonDir, `${WSGI_SHIM_MODULE}.py`);
4440
+ const templatePath = (0, import_path7.join)(__dirname, "..", `${WSGI_SHIM_MODULE}.py`);
4441
+ const template = (0, import_fs5.readFileSync)(templatePath, "utf8");
4182
4442
  const shimSource = template.replace(/__VC_DEV_MODULE_PATH__/g, modulePath);
4183
- (0, import_fs4.writeFileSync)(shimPath, shimSource, "utf8");
4184
- (0, import_build_utils7.debug)(`Prepared Python dev WSGI shim at ${shimPath}`);
4443
+ (0, import_fs5.writeFileSync)(shimPath, shimSource, "utf8");
4444
+ (0, import_build_utils8.debug)(`Prepared Python dev WSGI shim at ${shimPath}`);
4185
4445
  return WSGI_SHIM_MODULE;
4186
4446
  } catch (err) {
4187
- (0, import_build_utils7.debug)(`Failed to prepare dev WSGI shim: ${err?.message || err}`);
4447
+ (0, import_build_utils8.debug)(`Failed to prepare dev WSGI shim: ${err?.message || err}`);
4188
4448
  return null;
4189
4449
  }
4190
4450
  }
4191
4451
  async function getMultiServicePythonRunner(workPath, env, systemPython, uvPath) {
4192
4452
  const { pythonCmd, venvRoot } = useVirtualEnv(workPath, env, systemPython);
4193
4453
  if (venvRoot) {
4194
- (0, import_build_utils7.debug)(`Using existing virtualenv at ${venvRoot} for multi-service dev`);
4454
+ (0, import_build_utils8.debug)(`Using existing virtualenv at ${venvRoot} for multi-service dev`);
4195
4455
  return { command: pythonCmd, args: [] };
4196
4456
  }
4197
- const venvPath = (0, import_path6.join)(workPath, ".venv");
4457
+ const venvPath = (0, import_path7.join)(workPath, ".venv");
4198
4458
  await ensureVenv({ pythonPath: systemPython, venvPath, uvPath, quiet: true });
4199
- (0, import_build_utils7.debug)(`Created virtualenv at ${venvPath} for multi-service dev`);
4459
+ (0, import_build_utils8.debug)(`Created virtualenv at ${venvPath} for multi-service dev`);
4200
4460
  const pythonBin = getVenvPythonBin(venvPath);
4201
4461
  const binDir = getVenvBinDir(venvPath);
4202
4462
  env.VIRTUAL_ENV = venvPath;
4203
- env.PATH = `${binDir}${import_path6.delimiter}${env.PATH || ""}`;
4463
+ env.PATH = `${binDir}${import_path7.delimiter}${env.PATH || ""}`;
4204
4464
  return { command: pythonBin, args: [] };
4205
4465
  }
4206
4466
  var startDevServer = async (opts) => {
@@ -4226,7 +4486,7 @@ var startDevServer = async (opts) => {
4226
4486
  );
4227
4487
  if (!entry) {
4228
4488
  const searched = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
4229
- throw new import_build_utils7.NowBuildError({
4489
+ throw new import_build_utils8.NowBuildError({
4230
4490
  code: "PYTHON_ENTRYPOINT_NOT_FOUND",
4231
4491
  message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searched}.`,
4232
4492
  link: `https://vercel.com/docs/frameworks/backend/${framework?.toLowerCase()}#exporting-the-${framework?.toLowerCase()}-application`,
@@ -4279,7 +4539,7 @@ var startDevServer = async (opts) => {
4279
4539
  const yellow = "\x1B[33m";
4280
4540
  const white = "\x1B[1m";
4281
4541
  const reset = "\x1B[0m";
4282
- throw new import_build_utils7.NowBuildError({
4542
+ throw new import_build_utils8.NowBuildError({
4283
4543
  code: "PYTHON_EXTERNAL_VENV_DETECTED",
4284
4544
  message: `Detected activated venv at ${yellow}${venv}${reset}, ${white}vercel dev${reset} manages virtual environments automatically.
4285
4545
  Run ${white}deactivate${reset} and try again.`
@@ -4296,11 +4556,11 @@ Run ${white}deactivate${reset} and try again.`
4296
4556
  );
4297
4557
  spawnCommand = runner.command;
4298
4558
  spawnArgsPrefix = runner.args;
4299
- (0, import_build_utils7.debug)(
4559
+ (0, import_build_utils8.debug)(
4300
4560
  `Multi-service Python runner: ${spawnCommand} ${spawnArgsPrefix.join(" ")}`
4301
4561
  );
4302
4562
  } else if (venv) {
4303
- (0, import_build_utils7.debug)(`Running in virtualenv at ${venv}`);
4563
+ (0, import_build_utils8.debug)(`Running in virtualenv at ${venv}`);
4304
4564
  } else {
4305
4565
  const { pythonCmd: venvPythonCmd, venvRoot } = useVirtualEnv(
4306
4566
  workPath,
@@ -4309,9 +4569,9 @@ Run ${white}deactivate${reset} and try again.`
4309
4569
  );
4310
4570
  spawnCommand = venvPythonCmd;
4311
4571
  if (venvRoot) {
4312
- (0, import_build_utils7.debug)(`Using virtualenv at ${venvRoot}`);
4572
+ (0, import_build_utils8.debug)(`Using virtualenv at ${venvRoot}`);
4313
4573
  } else {
4314
- (0, import_build_utils7.debug)("No virtualenv found");
4574
+ (0, import_build_utils8.debug)("No virtualenv found");
4315
4575
  try {
4316
4576
  const yellow = "\x1B[33m";
4317
4577
  const reset = "\x1B[0m";
@@ -4349,14 +4609,14 @@ If you are using a virtual environment, activate it before running "vercel dev",
4349
4609
  if (framework !== "flask") {
4350
4610
  const devShimModule = createDevAsgiShim(workPath, modulePath);
4351
4611
  if (devShimModule) {
4352
- const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4612
+ const vercelPythonDir = (0, import_path7.join)(workPath, ".vercel", "python");
4353
4613
  const existingPythonPath = env.PYTHONPATH || "";
4354
4614
  env.PYTHONPATH = existingPythonPath ? `${vercelPythonDir}:${existingPythonPath}` : vercelPythonDir;
4355
4615
  }
4356
4616
  const moduleToRun = devShimModule || modulePath;
4357
4617
  const pythonArgs = ["-u", "-m", moduleToRun];
4358
4618
  const argv = [...spawnArgsPrefix, ...pythonArgs];
4359
- (0, import_build_utils7.debug)(
4619
+ (0, import_build_utils8.debug)(
4360
4620
  `Starting ASGI dev server (${framework}): ${spawnCommand} ${argv.join(" ")}`
4361
4621
  );
4362
4622
  const child = (0, import_child_process2.spawn)(spawnCommand, argv, {
@@ -4416,14 +4676,14 @@ If you are using a virtual environment, activate it before running "vercel dev",
4416
4676
  } else {
4417
4677
  const devShimModule = createDevWsgiShim(workPath, modulePath);
4418
4678
  if (devShimModule) {
4419
- const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4679
+ const vercelPythonDir = (0, import_path7.join)(workPath, ".vercel", "python");
4420
4680
  const existingPythonPath = env.PYTHONPATH || "";
4421
4681
  env.PYTHONPATH = existingPythonPath ? `${vercelPythonDir}:${existingPythonPath}` : vercelPythonDir;
4422
4682
  }
4423
4683
  const moduleToRun = devShimModule || modulePath;
4424
4684
  const pythonArgs = ["-u", "-m", moduleToRun];
4425
4685
  const argv = [...spawnArgsPrefix, ...pythonArgs];
4426
- (0, import_build_utils7.debug)(`Starting Flask dev server: ${spawnCommand} ${argv.join(" ")}`);
4686
+ (0, import_build_utils8.debug)(`Starting Flask dev server: ${spawnCommand} ${argv.join(" ")}`);
4427
4687
  const child = (0, import_child_process2.spawn)(spawnCommand, argv, {
4428
4688
  cwd: workPath,
4429
4689
  env,
@@ -4496,20 +4756,8 @@ If you are using a virtual environment, activate it before running "vercel dev",
4496
4756
  };
4497
4757
 
4498
4758
  // src/index.ts
4499
- var readFile = (0, import_util.promisify)(import_fs5.default.readFile);
4500
- var writeFile = (0, import_util.promisify)(import_fs5.default.writeFile);
4501
- function shouldEnableRuntimeInstall({
4502
- totalBundleSize,
4503
- uvLockPath
4504
- }) {
4505
- const pythonOnHiveEnabled = process.env.VERCEL_PYTHON_ON_HIVE === "1" || process.env.VERCEL_PYTHON_ON_HIVE === "true";
4506
- if (pythonOnHiveEnabled) {
4507
- return false;
4508
- } else if (totalBundleSize > LAMBDA_SIZE_THRESHOLD_BYTES && uvLockPath !== null) {
4509
- return true;
4510
- }
4511
- return false;
4512
- }
4759
+ var readFile2 = (0, import_util2.promisify)(import_fs6.default.readFile);
4760
+ var writeFile = (0, import_util2.promisify)(import_fs6.default.writeFile);
4513
4761
  var version = 3;
4514
4762
  async function downloadFilesInWorkPath({
4515
4763
  entrypoint,
@@ -4517,13 +4765,13 @@ async function downloadFilesInWorkPath({
4517
4765
  files,
4518
4766
  meta = {}
4519
4767
  }) {
4520
- (0, import_build_utils8.debug)("Downloading user files...");
4521
- let downloadedFiles = await (0, import_build_utils8.download)(files, workPath, meta);
4768
+ (0, import_build_utils9.debug)("Downloading user files...");
4769
+ let downloadedFiles = await (0, import_build_utils9.download)(files, workPath, meta);
4522
4770
  if (meta.isDev) {
4523
- const { devCacheDir = (0, import_path7.join)(workPath, ".now", "cache") } = meta;
4524
- const destCache = (0, import_path7.join)(devCacheDir, (0, import_path7.basename)(entrypoint, ".py"));
4525
- await (0, import_build_utils8.download)(downloadedFiles, destCache);
4526
- downloadedFiles = await (0, import_build_utils8.glob)("**", destCache);
4771
+ const { devCacheDir = (0, import_path8.join)(workPath, ".now", "cache") } = meta;
4772
+ const destCache = (0, import_path8.join)(devCacheDir, (0, import_path8.basename)(entrypoint, ".py"));
4773
+ await (0, import_build_utils9.download)(downloadedFiles, destCache);
4774
+ downloadedFiles = await (0, import_build_utils9.glob)("**", destCache);
4527
4775
  workPath = destCache;
4528
4776
  }
4529
4777
  return workPath;
@@ -4539,7 +4787,7 @@ var build = async ({
4539
4787
  const framework = config?.framework;
4540
4788
  let spawnEnv;
4541
4789
  let projectInstallCommand;
4542
- (0, import_build_utils8.debug)(`workPath: ${workPath}`);
4790
+ (0, import_build_utils9.debug)(`workPath: ${workPath}`);
4543
4791
  workPath = await downloadFilesInWorkPath({
4544
4792
  workPath,
4545
4793
  files: originalFiles,
@@ -4548,21 +4796,21 @@ var build = async ({
4548
4796
  });
4549
4797
  try {
4550
4798
  if (meta.isDev) {
4551
- const setupCfg = (0, import_path7.join)(workPath, "setup.cfg");
4799
+ const setupCfg = (0, import_path8.join)(workPath, "setup.cfg");
4552
4800
  await writeFile(setupCfg, "[install]\nprefix=\n");
4553
4801
  }
4554
4802
  } catch (err) {
4555
4803
  console.log('Failed to create "setup.cfg" file');
4556
4804
  throw err;
4557
4805
  }
4558
- if ((0, import_build_utils8.isPythonFramework)(framework)) {
4806
+ if ((0, import_build_utils9.isPythonFramework)(framework)) {
4559
4807
  const {
4560
4808
  cliType,
4561
4809
  lockfileVersion,
4562
4810
  packageJsonPackageManager,
4563
4811
  turboSupportsCorepackHome
4564
- } = await (0, import_build_utils8.scanParentDirs)(workPath, true);
4565
- spawnEnv = (0, import_build_utils8.getEnvForPackageManager)({
4812
+ } = await (0, import_build_utils9.scanParentDirs)(workPath, true);
4813
+ spawnEnv = (0, import_build_utils9.getEnvForPackageManager)({
4566
4814
  cliType,
4567
4815
  lockfileVersion,
4568
4816
  packageJsonPackageManager,
@@ -4583,7 +4831,7 @@ var build = async ({
4583
4831
  config?.buildCommand;
4584
4832
  if (projectBuildCommand) {
4585
4833
  console.log(`Running "${projectBuildCommand}"`);
4586
- await (0, import_build_utils8.execCommand)(projectBuildCommand, {
4834
+ await (0, import_build_utils9.execCommand)(projectBuildCommand, {
4587
4835
  env: spawnEnv,
4588
4836
  cwd: workPath
4589
4837
  });
@@ -4595,21 +4843,21 @@ var build = async ({
4595
4843
  );
4596
4844
  }
4597
4845
  }
4598
- let fsFiles = await (0, import_build_utils8.glob)("**", workPath);
4599
- if ((0, import_build_utils8.isPythonFramework)(framework) && (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
4846
+ let fsFiles = await (0, import_build_utils9.glob)("**", workPath);
4847
+ if ((0, import_build_utils9.isPythonFramework)(framework) && (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
4600
4848
  const detected = await detectPythonEntrypoint(
4601
4849
  config.framework,
4602
4850
  workPath,
4603
4851
  entrypoint
4604
4852
  );
4605
4853
  if (detected) {
4606
- (0, import_build_utils8.debug)(
4854
+ (0, import_build_utils9.debug)(
4607
4855
  `Resolved Python entrypoint to "${detected}" (configured "${entrypoint}" not found).`
4608
4856
  );
4609
4857
  entrypoint = detected;
4610
4858
  } else {
4611
4859
  const searchedList = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
4612
- throw new import_build_utils8.NowBuildError({
4860
+ throw new import_build_utils9.NowBuildError({
4613
4861
  code: `${framework.toUpperCase()}_ENTRYPOINT_NOT_FOUND`,
4614
4862
  message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searchedList}.`,
4615
4863
  link: `https://vercel.com/docs/frameworks/backend/${framework}#exporting-the-${framework}-application`,
@@ -4617,7 +4865,7 @@ var build = async ({
4617
4865
  });
4618
4866
  }
4619
4867
  }
4620
- const entryDirectory = (0, import_path7.dirname)(entrypoint);
4868
+ const entryDirectory = (0, import_path8.dirname)(entrypoint);
4621
4869
  const pyprojectDir = findDir({
4622
4870
  file: "pyproject.toml",
4623
4871
  entryDirectory,
@@ -4639,40 +4887,40 @@ var build = async ({
4639
4887
  let declaredPythonVersion;
4640
4888
  if (pythonVersionFileDir) {
4641
4889
  try {
4642
- const content = await readFile(
4643
- (0, import_path7.join)(pythonVersionFileDir, ".python-version"),
4890
+ const content = await readFile2(
4891
+ (0, import_path8.join)(pythonVersionFileDir, ".python-version"),
4644
4892
  "utf8"
4645
4893
  );
4646
4894
  const version2 = parsePythonVersionFile(content);
4647
4895
  if (version2) {
4648
4896
  declaredPythonVersion = { version: version2, source: ".python-version" };
4649
- (0, import_build_utils8.debug)(`Found Python version ${version2} in .python-version`);
4897
+ (0, import_build_utils9.debug)(`Found Python version ${version2} in .python-version`);
4650
4898
  }
4651
4899
  } catch (err) {
4652
- (0, import_build_utils8.debug)("Failed to read .python-version file", err);
4900
+ (0, import_build_utils9.debug)("Failed to read .python-version file", err);
4653
4901
  }
4654
4902
  }
4655
4903
  if (!declaredPythonVersion && pyprojectDir) {
4656
4904
  let requiresPython;
4657
4905
  try {
4658
- const pyproject = await (0, import_build_utils9.readConfigFile)((0, import_path7.join)(pyprojectDir, "pyproject.toml"));
4906
+ const pyproject = await (0, import_build_utils10.readConfigFile)((0, import_path8.join)(pyprojectDir, "pyproject.toml"));
4659
4907
  requiresPython = pyproject?.project?.["requires-python"];
4660
4908
  } catch (err) {
4661
- (0, import_build_utils8.debug)("Failed to parse pyproject.toml", err);
4909
+ (0, import_build_utils9.debug)("Failed to parse pyproject.toml", err);
4662
4910
  }
4663
4911
  if (typeof requiresPython === "string" && requiresPython.trim()) {
4664
4912
  declaredPythonVersion = {
4665
4913
  version: requiresPython.trim(),
4666
4914
  source: "pyproject.toml"
4667
4915
  };
4668
- (0, import_build_utils8.debug)(`Found requires-python "${requiresPython}" in pyproject.toml`);
4916
+ (0, import_build_utils9.debug)(`Found requires-python "${requiresPython}" in pyproject.toml`);
4669
4917
  }
4670
4918
  }
4671
4919
  if (!declaredPythonVersion && pipfileLockDir) {
4672
4920
  let lock = {};
4673
- const pipfileLockPath = (0, import_path7.join)(pipfileLockDir, "Pipfile.lock");
4921
+ const pipfileLockPath = (0, import_path8.join)(pipfileLockDir, "Pipfile.lock");
4674
4922
  try {
4675
- const pipfileLockContent = await readFile(pipfileLockPath, "utf8");
4923
+ const pipfileLockContent = await readFile2(pipfileLockPath, "utf8");
4676
4924
  try {
4677
4925
  lock = JSON.parse(pipfileLockContent);
4678
4926
  } catch (err) {
@@ -4683,7 +4931,7 @@ ${pipfileLockContent}`
4683
4931
  throw err;
4684
4932
  }
4685
4933
  } catch (err) {
4686
- throw new import_build_utils8.NowBuildError({
4934
+ throw new import_build_utils9.NowBuildError({
4687
4935
  code: "INVALID_PIPFILE_LOCK",
4688
4936
  message: "Unable to parse Pipfile.lock"
4689
4937
  });
@@ -4691,7 +4939,7 @@ ${pipfileLockContent}`
4691
4939
  const pyFromLock = lock?._meta?.requires?.python_version;
4692
4940
  if (pyFromLock) {
4693
4941
  declaredPythonVersion = { version: pyFromLock, source: "Pipfile.lock" };
4694
- (0, import_build_utils8.debug)(`Found Python version ${pyFromLock} in Pipfile.lock`);
4942
+ (0, import_build_utils9.debug)(`Found Python version ${pyFromLock} in Pipfile.lock`);
4695
4943
  }
4696
4944
  }
4697
4945
  const pythonVersion = getSupportedPythonVersion({
@@ -4701,15 +4949,15 @@ ${pipfileLockContent}`
4701
4949
  const selectedVersionTuple = parseVersionTuple(pythonVersion.version);
4702
4950
  const defaultVersionTuple = parseVersionTuple(DEFAULT_PYTHON_VERSION);
4703
4951
  if (!pythonVersionFileDir && pyprojectDir && declaredPythonVersion?.source === "pyproject.toml" && selectedVersionTuple && defaultVersionTuple && compareTuples(selectedVersionTuple, defaultVersionTuple) <= 0) {
4704
- const pythonVersionFilePath = (0, import_path7.join)(pyprojectDir, ".python-version");
4952
+ const pythonVersionFilePath = (0, import_path8.join)(pyprojectDir, ".python-version");
4705
4953
  await writeFile(pythonVersionFilePath, `${pythonVersion.version}
4706
4954
  `);
4707
4955
  console.log(
4708
4956
  `Writing .python-version file with version ${pythonVersion.version}`
4709
4957
  );
4710
4958
  }
4711
- fsFiles = await (0, import_build_utils8.glob)("**", workPath);
4712
- const venvPath = (0, import_path7.join)(workPath, ".vercel", "python", ".venv");
4959
+ fsFiles = await (0, import_build_utils9.glob)("**", workPath);
4960
+ const venvPath = (0, import_path8.join)(workPath, ".vercel", "python", ".venv");
4713
4961
  await ensureVenv({
4714
4962
  pythonPath: pythonVersion.pythonPath,
4715
4963
  venvPath
@@ -4720,7 +4968,7 @@ ${pipfileLockContent}`
4720
4968
  let assumeDepsInstalled = false;
4721
4969
  if (projectInstallCommand) {
4722
4970
  console.log(`Running "install" command: \`${projectInstallCommand}\`...`);
4723
- await (0, import_build_utils8.execCommand)(projectInstallCommand, {
4971
+ await (0, import_build_utils9.execCommand)(projectInstallCommand, {
4724
4972
  env: pythonEnv,
4725
4973
  cwd: workPath
4726
4974
  });
@@ -4777,7 +5025,7 @@ ${pipfileLockContent}`
4777
5025
  });
4778
5026
  } catch (err) {
4779
5027
  noBuildCheckFailed = true;
4780
- (0, import_build_utils8.debug)(
5028
+ (0, import_build_utils9.debug)(
4781
5029
  `--no-build check failed: ${err instanceof Error ? err.message : String(err)}`
4782
5030
  );
4783
5031
  }
@@ -4790,18 +5038,18 @@ ${pipfileLockContent}`
4790
5038
  });
4791
5039
  }
4792
5040
  const runtimeDep = baseEnv.VERCEL_RUNTIME_PYTHON || `vercel-runtime==${VERCEL_RUNTIME_VERSION}`;
4793
- (0, import_build_utils8.debug)(`Installing ${runtimeDep}`);
5041
+ (0, import_build_utils9.debug)(`Installing ${runtimeDep}`);
4794
5042
  await uv.pip({
4795
5043
  venvPath,
4796
- projectDir: (0, import_path7.join)(workPath, entryDirectory),
5044
+ projectDir: (0, import_path8.join)(workPath, entryDirectory),
4797
5045
  args: ["install", runtimeDep]
4798
5046
  });
4799
- (0, import_build_utils8.debug)("Entrypoint is", entrypoint);
5047
+ (0, import_build_utils9.debug)("Entrypoint is", entrypoint);
4800
5048
  const moduleName = entrypoint.replace(/\//g, ".").replace(/\.py$/i, "");
4801
5049
  const vendorDir = resolveVendorDir();
4802
5050
  const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
4803
5051
  const entrypointWithSuffix = `${entrypoint}${suffix}`;
4804
- (0, import_build_utils8.debug)("Entrypoint with suffix is", entrypointWithSuffix);
5052
+ (0, import_build_utils9.debug)("Entrypoint with suffix is", entrypointWithSuffix);
4805
5053
  const runtimeTrampoline = `
4806
5054
  import importlib
4807
5055
  import os
@@ -4864,166 +5112,32 @@ from vercel_runtime.vc_init import vc_handler
4864
5112
  cwd: workPath,
4865
5113
  ignore: config && typeof config.excludeFiles === "string" ? [...predefinedExcludes, config.excludeFiles] : predefinedExcludes
4866
5114
  };
4867
- const files = await (0, import_build_utils8.glob)("**", globOptions);
4868
- const allVendorFiles = await mirrorSitePackagesIntoVendor({
5115
+ const files = await (0, import_build_utils9.glob)("**", globOptions);
5116
+ const depExternalizer = new PythonDependencyExternalizer({
4869
5117
  venvPath,
4870
- vendorDirName: vendorDir
4871
- });
4872
- const tempFilesForSizing = { ...files };
4873
- for (const [p, f] of Object.entries(allVendorFiles)) {
4874
- tempFilesForSizing[p] = f;
4875
- }
4876
- const totalBundleSize = await calculateBundleSize(tempFilesForSizing);
4877
- const totalBundleSizeMB = (totalBundleSize / (1024 * 1024)).toFixed(2);
4878
- (0, import_build_utils8.debug)(`Total bundle size: ${totalBundleSizeMB} MB`);
4879
- const runtimeInstallEnabled = shouldEnableRuntimeInstall({
4880
- totalBundleSize,
4881
- uvLockPath
5118
+ vendorDir,
5119
+ workPath,
5120
+ uvLockPath,
5121
+ uvProjectDir,
5122
+ projectName,
5123
+ noBuildCheckFailed,
5124
+ pythonPath: pythonVersion.pythonPath
4882
5125
  });
4883
- if (runtimeInstallEnabled && uvLockPath && uvProjectDir) {
4884
- console.log(
4885
- `Bundle size (${totalBundleSizeMB} MB) exceeds limit. Enabling runtime dependency installation.`
4886
- );
4887
- if (totalBundleSize > LAMBDA_EPHEMERAL_STORAGE_BYTES) {
4888
- const ephemeralLimitMB = (LAMBDA_EPHEMERAL_STORAGE_BYTES / (1024 * 1024)).toFixed(0);
4889
- throw new import_build_utils8.NowBuildError({
4890
- code: "LAMBDA_SIZE_EXCEEDED",
4891
- message: `Total dependency size (${totalBundleSizeMB} MB) exceeds Lambda ephemeral storage limit (${ephemeralLimitMB} MB). Even with runtime dependency installation, all packages must fit within the ${ephemeralLimitMB} MB ephemeral storage available to Lambda functions. Consider removing unused dependencies or splitting your application into smaller functions.`
4892
- });
4893
- }
4894
- if (noBuildCheckFailed) {
4895
- throw new import_build_utils8.NowBuildError({
4896
- code: "RUNTIME_DEPENDENCY_INSTALLATION_FAILED",
4897
- message: `Bundle size exceeds the Lambda limit and requires runtime dependency installation, but some packages in your uv.lock file do not have pre-built binary wheels available.
4898
- Runtime dependency installation requires all public packages to have binary wheels.
4899
-
4900
- To fix this, either:
4901
- 1. Regenerate your lock file with: uv lock --upgrade --no-build, or
4902
- 2. Switch the problematic packages to ones that have pre-built wheels available`
4903
- });
4904
- }
4905
- let lockContent;
4906
- try {
4907
- lockContent = await readFile(uvLockPath, "utf8");
4908
- } catch (error) {
4909
- if (error instanceof Error) {
4910
- console.log(
4911
- `Failed to read uv.lock file at "${uvLockPath}": ${error.message}`
4912
- );
4913
- } else {
4914
- console.log(
4915
- `Failed to read uv.lock file at "${uvLockPath}": ${String(error)}`
4916
- );
4917
- }
4918
- throw new import_build_utils8.NowBuildError({
4919
- code: "RUNTIME_DEPENDENCY_INSTALLATION_FAILED",
4920
- message: `Failed to read uv.lock file at "${uvLockPath}"`
4921
- });
4922
- }
4923
- let lockFile;
4924
- try {
4925
- lockFile = (0, import_python_analysis3.parseUvLock)(lockContent, uvLockPath);
4926
- } catch (error) {
4927
- if (error instanceof import_python_analysis3.PythonAnalysisError) {
4928
- if (error.fileContent) {
4929
- console.log(
4930
- `Failed to parse "${error.path}". File content:
4931
- ${error.fileContent}`
4932
- );
4933
- }
4934
- throw new import_build_utils8.NowBuildError({
4935
- code: error.code,
4936
- message: error.message
4937
- });
4938
- }
4939
- throw error;
4940
- }
4941
- const excludePackages = [];
4942
- if (projectName) {
4943
- excludePackages.push(projectName);
4944
- (0, import_build_utils8.debug)(
4945
- `Excluding project package "${projectName}" from runtime installation`
4946
- );
4947
- }
4948
- const classification = (0, import_python_analysis3.classifyPackages)({
4949
- lockFile,
4950
- excludePackages
4951
- });
4952
- (0, import_build_utils8.debug)(
4953
- `Package classification: ${classification.privatePackages.length} private, ${classification.publicPackages.length} public`
4954
- );
4955
- if (classification.publicPackages.length > 0) {
4956
- const privatePackagesWithRuntime = [
4957
- ...classification.privatePackages,
4958
- "vercel-runtime",
4959
- "vercel_runtime"
4960
- ];
4961
- const privateVendorFiles = await mirrorPrivatePackagesIntoVendor({
4962
- venvPath,
4963
- vendorDirName: vendorDir,
4964
- privatePackages: privatePackagesWithRuntime
4965
- });
4966
- for (const [p, f] of Object.entries(privateVendorFiles)) {
4967
- files[p] = f;
4968
- }
4969
- const runtimeRequirementsContent = (0, import_python_analysis3.generateRuntimeRequirements)(classification);
4970
- const runtimeRequirementsPath = `${UV_BUNDLE_DIR}/_runtime_requirements.txt`;
4971
- files[runtimeRequirementsPath] = new import_build_utils8.FileBlob({
4972
- data: runtimeRequirementsContent
4973
- });
4974
- if (process.env.VERCEL_BUILD_IMAGE) {
4975
- try {
4976
- const uvBinaryPath = await getUvBinaryForBundling(
4977
- pythonVersion.pythonPath
4978
- );
4979
- const uvBundleDir = (0, import_path7.join)(workPath, UV_BUNDLE_DIR);
4980
- const uvLocalPath = (0, import_path7.join)(uvBundleDir, "uv");
4981
- await import_fs5.default.promises.mkdir(uvBundleDir, { recursive: true });
4982
- await import_fs5.default.promises.copyFile(uvBinaryPath, uvLocalPath);
4983
- await import_fs5.default.promises.chmod(uvLocalPath, 493);
4984
- const uvBundlePath = `${UV_BUNDLE_DIR}/uv`;
4985
- files[uvBundlePath] = new import_build_utils8.FileFsRef({
4986
- fsPath: uvLocalPath,
4987
- mode: 33261
4988
- // Regular file + executable
4989
- });
4990
- (0, import_build_utils8.debug)(`Bundled uv binary from ${uvBinaryPath} to ${uvLocalPath}`);
4991
- } catch (err) {
4992
- throw new import_build_utils8.NowBuildError({
4993
- code: "RUNTIME_DEPENDENCY_INSTALLATION_FAILED",
4994
- message: `Failed to bundle uv binary for runtime installation: ${err instanceof Error ? err.message : String(err)}`
4995
- });
4996
- }
4997
- }
4998
- } else {
4999
- throw new import_build_utils8.NowBuildError({
5000
- code: "RUNTIME_DEPENDENCY_INSTALLATION_FAILED",
5001
- message: "Bundle size exceeds limit but no public packages found for runtime installation."
5002
- });
5003
- }
5126
+ const { overLambdaLimit, allVendorFiles } = await depExternalizer.analyze(files);
5127
+ if (overLambdaLimit) {
5128
+ await depExternalizer.generateBundle(files);
5004
5129
  } else {
5005
5130
  for (const [p, f] of Object.entries(allVendorFiles)) {
5006
5131
  files[p] = f;
5007
5132
  }
5008
5133
  }
5009
5134
  const handlerPyFilename = "vc__handler__python";
5010
- files[`${handlerPyFilename}.py`] = new import_build_utils8.FileBlob({ data: runtimeTrampoline });
5135
+ files[`${handlerPyFilename}.py`] = new import_build_utils9.FileBlob({ data: runtimeTrampoline });
5011
5136
  if (config.framework === "fasthtml") {
5012
5137
  const { SESSKEY = "" } = process.env;
5013
- files[".sesskey"] = new import_build_utils8.FileBlob({ data: `"${SESSKEY}"` });
5014
- }
5015
- if (runtimeInstallEnabled) {
5016
- const finalBundleSize = await calculateBundleSize(files);
5017
- if (finalBundleSize > LAMBDA_SIZE_THRESHOLD_BYTES) {
5018
- const finalSizeMB = (finalBundleSize / (1024 * 1024)).toFixed(2);
5019
- const limitMB = (LAMBDA_SIZE_THRESHOLD_BYTES / (1024 * 1024)).toFixed(0);
5020
- throw new import_build_utils8.NowBuildError({
5021
- code: "LAMBDA_SIZE_EXCEEDED",
5022
- message: `Bundle size (${finalSizeMB} MB) exceeds Lambda limit (${limitMB} MB) even after deferring public packages to runtime installation. This usually means your private packages or source code are too large. Consider reducing the size of private dependencies or splitting your application.`
5023
- });
5024
- }
5138
+ files[".sesskey"] = new import_build_utils9.FileBlob({ data: `"${SESSKEY}"` });
5025
5139
  }
5026
- const output = new import_build_utils8.Lambda({
5140
+ const output = new import_build_utils9.Lambda({
5027
5141
  files,
5028
5142
  handler: `${handlerPyFilename}.vc_handler`,
5029
5143
  runtime: pythonVersion.runtime,
@@ -5059,7 +5173,7 @@ var defaultShouldServe = ({
5059
5173
  if (entrypoint === requestPath && hasProp(files, entrypoint)) {
5060
5174
  return true;
5061
5175
  }
5062
- const { dir, name } = (0, import_path7.parse)(entrypoint);
5176
+ const { dir, name } = (0, import_path8.parse)(entrypoint);
5063
5177
  if (name === "index" && dir === requestPath && hasProp(files, entrypoint)) {
5064
5178
  return true;
5065
5179
  }
@@ -5085,7 +5199,6 @@ function parsePythonVersionFile(content) {
5085
5199
  downloadFilesInWorkPath,
5086
5200
  installRequirement,
5087
5201
  installRequirementsFile,
5088
- shouldEnableRuntimeInstall,
5089
5202
  shouldServe,
5090
5203
  startDevServer,
5091
5204
  version