@vercel/python 6.20.2 → 6.21.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 fs8 = require("fs");
51
+ var fs9 = 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
- fs8.stat(path, function(er, stat) {
76
+ fs9.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(fs8.statSync(path), path, options);
81
+ return checkStat(fs9.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 fs8 = require("fs");
91
+ var fs9 = require("fs");
92
92
  function isexe(path, options, cb) {
93
- fs8.stat(path, function(er, stat) {
93
+ fs9.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(fs8.statSync(path), options);
98
+ return checkStat(fs9.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 fs8 = require("fs");
122
+ var fs9 = 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 fs8 = require("fs");
398
+ var fs9 = 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 = fs8.openSync(command, "r");
412
- fs8.readSync(fd, buffer, 0, size, 0);
413
- fs8.closeSync(fd);
411
+ fd = fs9.openSync(command, "r");
412
+ fs9.readSync(fd, buffer, 0, size, 0);
413
+ fs9.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 debug10;
426
+ var debug11;
427
427
  if (typeof process === "object" && process.env && process.env.NODE_DEBUG && /\bsemver\b/i.test(process.env.NODE_DEBUG)) {
428
- debug10 = function() {
428
+ debug11 = 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
- debug10 = function() {
434
+ debug11 = 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
- debug10(i, src[i]);
543
+ debug11(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
- debug10("SemVer", version2, options);
610
+ debug11("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
- debug10("SemVer.compare", this.version, this.options, other);
657
+ debug11("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
- debug10("prerelease compare", i2, a, b);
684
+ debug11("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
- debug10("comparator", comp, options);
938
+ debug11("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
- debug10("comp", this);
947
+ debug11("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
- debug10("Comparator.test", version2, this.options.loose);
970
+ debug11("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
- debug10("hyphen replace", range);
1053
+ debug11("hyphen replace", range);
1054
1054
  range = range.replace(safeRe[COMPARATORTRIM], comparatorTrimReplace);
1055
- debug10("comparator trim", range, safeRe[COMPARATORTRIM]);
1055
+ debug11("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
- debug10("comp", comp, options);
1095
+ debug11("comp", comp, options);
1096
1096
  comp = replaceCarets(comp, options);
1097
- debug10("caret", comp);
1097
+ debug11("caret", comp);
1098
1098
  comp = replaceTildes(comp, options);
1099
- debug10("tildes", comp);
1099
+ debug11("tildes", comp);
1100
1100
  comp = replaceXRanges(comp, options);
1101
- debug10("xrange", comp);
1101
+ debug11("xrange", comp);
1102
1102
  comp = replaceStars(comp, options);
1103
- debug10("stars", comp);
1103
+ debug11("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
- debug10("tilde", comp, _, M, m, p, pr);
1117
+ debug11("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
- debug10("replaceTilde pr", pr);
1126
+ debug11("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
- debug10("tilde return", ret);
1131
+ debug11("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
- debug10("caret", comp, options);
1141
+ debug11("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
- debug10("caret", comp, _, M, m, p, pr);
1144
+ debug11("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
- debug10("replaceCaret pr", pr);
1157
+ debug11("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
- debug10("no pr");
1168
+ debug11("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
- debug10("caret return", ret);
1179
+ debug11("caret return", ret);
1180
1180
  return ret;
1181
1181
  });
1182
1182
  }
1183
1183
  function replaceXRanges(comp, options) {
1184
- debug10("replaceXRanges", comp, options);
1184
+ debug11("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
- debug10("xRange", comp, ret, gtlt, M, m, p, pr);
1193
+ debug11("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
- debug10("xRange return", ret);
1236
+ debug11("xRange return", ret);
1237
1237
  return ret;
1238
1238
  });
1239
1239
  }
1240
1240
  function replaceStars(comp, options) {
1241
- debug10("replaceStars", comp, options);
1241
+ debug11("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
- debug10(set[i2].semver);
1289
+ debug11(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 fs8;
1898
+ var fs9;
1899
1899
  try {
1900
- fs8 = require("fs");
1900
+ fs9 = 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 (!fs8)
1912
+ if (!fs9)
1913
1913
  return false;
1914
- return (stream instanceof (fs8.ReadStream || noop) || stream instanceof (fs8.WriteStream || noop)) && isFn(stream.close);
1914
+ return (stream instanceof (fs9.ReadStream || noop) || stream instanceof (fs9.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: join11, delimiter: delimiter2, sep: sep2, posix } = require("path");
2654
+ var { join: join12, 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 + join11(pathPart, cmd);
2683
+ return prefix + join12(pathPart, cmd);
2684
2684
  };
2685
2685
  var which2 = async (cmd, opt = {}) => {
2686
2686
  const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
@@ -2862,20 +2862,22 @@ __export(src_exports, {
2862
2862
  downloadFilesInWorkPath: () => downloadFilesInWorkPath,
2863
2863
  installRequirement: () => installRequirement,
2864
2864
  installRequirementsFile: () => installRequirementsFile,
2865
+ prepareCache: () => prepareCache,
2866
+ runFrameworkHook: () => runFrameworkHook,
2865
2867
  shouldServe: () => shouldServe,
2866
2868
  startDevServer: () => startDevServer,
2867
2869
  version: () => version
2868
2870
  });
2869
2871
  module.exports = __toCommonJS(src_exports);
2870
- var import_fs8 = __toESM(require("fs"));
2871
- var import_path11 = require("path");
2872
+ var import_fs10 = __toESM(require("fs"));
2873
+ var import_path12 = require("path");
2872
2874
 
2873
2875
  // src/package-versions.ts
2874
- var VERCEL_RUNTIME_VERSION = "0.5.6";
2876
+ var VERCEL_RUNTIME_VERSION = "0.6.0";
2875
2877
  var VERCEL_WORKERS_VERSION = "0.0.12";
2876
2878
 
2877
2879
  // src/index.ts
2878
- var import_build_utils12 = require("@vercel/build-utils");
2880
+ var import_build_utils13 = require("@vercel/build-utils");
2879
2881
 
2880
2882
  // src/install.ts
2881
2883
  var import_execa3 = __toESM(require_execa());
@@ -2902,14 +2904,19 @@ var import_build_utils = require("@vercel/build-utils");
2902
2904
  var UV_VERSION = "0.9.22";
2903
2905
  var UV_PYTHON_PATH_PREFIX = "/uv/python/";
2904
2906
  var UV_PYTHON_DOWNLOADS_MODE = "automatic";
2907
+ var UV_CACHE_DIR_SUBPATH = [".vercel", "python", "cache", "uv"];
2905
2908
  var isWin = process.platform === "win32";
2906
2909
  var uvExec = isWin ? "uv.exe" : "uv";
2907
2910
  function findUvInPath() {
2908
2911
  return import_which.default.sync("uv", { nothrow: true });
2909
2912
  }
2913
+ function getUvCacheDir(workPath) {
2914
+ return (0, import_path.join)(workPath, ...UV_CACHE_DIR_SUBPATH);
2915
+ }
2910
2916
  var UvRunner = class {
2911
- constructor(uvPath) {
2917
+ constructor(uvPath, uvCacheDir) {
2912
2918
  this.uvPath = uvPath;
2919
+ this.uvCacheDir = uvCacheDir;
2913
2920
  }
2914
2921
  getPath() {
2915
2922
  return this.uvPath;
@@ -2986,7 +2993,7 @@ var UvRunner = class {
2986
2993
  try {
2987
2994
  await (0, import_execa.default)(this.uvPath, args, {
2988
2995
  cwd: projectDir,
2989
- env: getProtectedUvEnv(process.env)
2996
+ env: getProtectedUvEnv(process.env, this.uvCacheDir)
2990
2997
  });
2991
2998
  } catch (err) {
2992
2999
  const error = new Error(
@@ -3051,7 +3058,7 @@ var UvRunner = class {
3051
3058
  const binDir = isWin ? (0, import_path.join)(venvPath, "Scripts") : (0, import_path.join)(venvPath, "bin");
3052
3059
  const existingPath = process.env.PATH || "";
3053
3060
  return {
3054
- ...getProtectedUvEnv(process.env),
3061
+ ...getProtectedUvEnv(process.env, this.uvCacheDir),
3055
3062
  VIRTUAL_ENV: venvPath,
3056
3063
  PATH: existingPath ? `${binDir}${import_path2.delimiter}${existingPath}` : binDir
3057
3064
  };
@@ -3158,11 +3165,15 @@ async function getUvBinaryOrInstall(pythonPath) {
3158
3165
  function filterUnsafeUvPipArgs(args) {
3159
3166
  return args.filter((arg) => arg !== "--no-warn-script-location");
3160
3167
  }
3161
- function getProtectedUvEnv(baseEnv = process.env) {
3162
- return {
3168
+ function getProtectedUvEnv(baseEnv = process.env, uvCacheDir) {
3169
+ const env = {
3163
3170
  ...baseEnv,
3164
3171
  UV_PYTHON_DOWNLOADS: UV_PYTHON_DOWNLOADS_MODE
3165
3172
  };
3173
+ if (uvCacheDir) {
3174
+ env.UV_CACHE_DIR = uvCacheDir;
3175
+ }
3176
+ return env;
3166
3177
  }
3167
3178
  var UV_BUNDLE_DIR = "_uv";
3168
3179
  async function getUvBinaryForBundling(pythonPath) {
@@ -3201,9 +3212,9 @@ function useVirtualEnv(workPath, env, systemPython) {
3201
3212
  }
3202
3213
  return { pythonCmd };
3203
3214
  }
3204
- function createVenvEnv(venvPath, baseEnv = process.env) {
3215
+ function createVenvEnv(venvPath, baseEnv = process.env, uvCacheDir) {
3205
3216
  const env = {
3206
- ...getProtectedUvEnv(baseEnv),
3217
+ ...getProtectedUvEnv(baseEnv, uvCacheDir),
3207
3218
  VIRTUAL_ENV: venvPath
3208
3219
  };
3209
3220
  const binDir = getVenvBinDir(venvPath);
@@ -3215,6 +3226,7 @@ async function ensureVenv({
3215
3226
  pythonPath,
3216
3227
  venvPath,
3217
3228
  uvPath,
3229
+ uvCacheDir,
3218
3230
  quiet
3219
3231
  }) {
3220
3232
  const marker = (0, import_path3.join)(venvPath, "pyvenv.cfg");
@@ -3228,7 +3240,9 @@ async function ensureVenv({
3228
3240
  console.log(`Creating virtual environment at "${venvPath}"...`);
3229
3241
  }
3230
3242
  if (uvPath) {
3231
- await (0, import_execa2.default)(uvPath, ["venv", venvPath]);
3243
+ await (0, import_execa2.default)(uvPath, ["venv", venvPath], {
3244
+ env: getProtectedUvEnv(process.env, uvCacheDir)
3245
+ });
3232
3246
  } else {
3233
3247
  await (0, import_execa2.default)(pythonPath, ["-m", "venv", venvPath]);
3234
3248
  }
@@ -3735,7 +3749,7 @@ async function pipInstall(pipPath, uvPath, workPath, args, targetDir) {
3735
3749
  try {
3736
3750
  await (0, import_execa3.default)(uvPath, uvArgs, {
3737
3751
  cwd: workPath,
3738
- env: getProtectedUvEnv()
3752
+ env: getProtectedUvEnv(process.env, getUvCacheDir(workPath))
3739
3753
  });
3740
3754
  return;
3741
3755
  } catch (err) {
@@ -4202,13 +4216,14 @@ async function calculatePerPackageSizes(venvPath) {
4202
4216
 
4203
4217
  // src/start-dev-server.ts
4204
4218
  var import_child_process2 = require("child_process");
4205
- var import_fs5 = require("fs");
4219
+ var import_fs6 = require("fs");
4206
4220
  var import_path8 = require("path");
4207
4221
  var import_build_utils8 = require("@vercel/build-utils");
4208
4222
  var import_get_port = __toESM(require_get_port());
4209
4223
  var import_is_port_reachable = __toESM(require_is_port_reachable());
4210
4224
 
4211
4225
  // src/entrypoint.ts
4226
+ var import_fs5 = __toESM(require("fs"));
4212
4227
  var import_path7 = require("path");
4213
4228
  var import_build_utils6 = require("@vercel/build-utils");
4214
4229
  var import_build_utils7 = require("@vercel/build-utils");
@@ -4231,6 +4246,20 @@ function getCandidateEntrypointsInDirs(dirs) {
4231
4246
  )
4232
4247
  );
4233
4248
  }
4249
+ async function fileExists(filePath) {
4250
+ try {
4251
+ const stat = await import_fs5.default.promises.stat(filePath);
4252
+ return stat.isFile();
4253
+ } catch {
4254
+ return false;
4255
+ }
4256
+ }
4257
+ async function checkEntrypoint(workPath, relPath) {
4258
+ const absPath = (0, import_path7.join)(workPath, relPath);
4259
+ if (!await fileExists(absPath))
4260
+ return false;
4261
+ return (0, import_build_utils6.isPythonEntrypoint)({ fsPath: absPath });
4262
+ }
4234
4263
  async function getPyprojectEntrypoint(workPath) {
4235
4264
  const pyprojectData = await (0, import_build_utils7.readConfigFile)((0, import_path7.join)(workPath, "pyproject.toml"));
4236
4265
  if (!pyprojectData)
@@ -4244,46 +4273,56 @@ async function getPyprojectEntrypoint(workPath) {
4244
4273
  return null;
4245
4274
  const modulePath = match[1];
4246
4275
  const relPath = modulePath.replace(/\./g, "/");
4247
- try {
4248
- const fsFiles = await (0, import_build_utils6.glob)("**", workPath);
4249
- const candidates = [`${relPath}.py`, `${relPath}/__init__.py`];
4250
- for (const candidate of candidates) {
4251
- if (fsFiles[candidate])
4252
- return candidate;
4253
- }
4254
- return null;
4255
- } catch {
4256
- (0, import_build_utils6.debug)("Failed to discover Python entrypoint from pyproject.toml");
4257
- return null;
4276
+ const candidates = [`${relPath}.py`, `${relPath}/__init__.py`];
4277
+ for (const candidate of candidates) {
4278
+ if (await fileExists((0, import_path7.join)(workPath, candidate)))
4279
+ return candidate;
4258
4280
  }
4281
+ return null;
4259
4282
  }
4260
- async function findValidEntrypoint(fsFiles, candidates) {
4283
+ async function findValidEntrypoint(workPath, candidates) {
4261
4284
  for (const candidate of candidates) {
4262
- if (fsFiles[candidate]) {
4263
- const isValid = await (0, import_build_utils6.isPythonEntrypoint)(fsFiles[candidate]);
4264
- if (isValid) {
4265
- (0, import_build_utils6.debug)(`Detected Python entrypoint: ${candidate}`);
4266
- return candidate;
4267
- }
4285
+ if (await checkEntrypoint(workPath, candidate)) {
4286
+ (0, import_build_utils6.debug)(`Detected Python entrypoint: ${candidate}`);
4287
+ return candidate;
4268
4288
  }
4269
4289
  }
4270
4290
  return null;
4271
4291
  }
4292
+ async function checkDjangoManage(workPath) {
4293
+ const managePath = (0, import_path7.join)(workPath, "manage.py");
4294
+ try {
4295
+ const content = await import_fs5.default.promises.readFile(managePath, "utf-8");
4296
+ if (!content.includes("DJANGO_SETTINGS_MODULE"))
4297
+ return false;
4298
+ (0, import_build_utils6.debug)(`Found Django manage.py with DJANGO_SETTINGS_MODULE at ${workPath}`);
4299
+ return true;
4300
+ } catch {
4301
+ return false;
4302
+ }
4303
+ }
4304
+ async function getSubdirectories(workPath) {
4305
+ try {
4306
+ const entries = await import_fs5.default.promises.readdir(workPath, {
4307
+ withFileTypes: true
4308
+ });
4309
+ return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).sort();
4310
+ } catch {
4311
+ return [];
4312
+ }
4313
+ }
4272
4314
  async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
4273
4315
  const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
4274
4316
  try {
4275
- const fsFiles = await (0, import_build_utils6.glob)("**", workPath);
4276
- if (fsFiles[entry]) {
4277
- const isValid = await (0, import_build_utils6.isPythonEntrypoint)(fsFiles[entry]);
4278
- if (isValid) {
4279
- (0, import_build_utils6.debug)(`Using configured Python entrypoint: ${entry}`);
4280
- return entry;
4281
- }
4317
+ if (await checkEntrypoint(workPath, entry)) {
4318
+ (0, import_build_utils6.debug)(`Using configured Python entrypoint: ${entry}`);
4319
+ return { entrypoint: entry };
4282
4320
  }
4283
- const candidates = PYTHON_CANDIDATE_ENTRYPOINTS.filter(
4284
- (c) => !!fsFiles[c]
4321
+ const found = await findValidEntrypoint(
4322
+ workPath,
4323
+ PYTHON_CANDIDATE_ENTRYPOINTS
4285
4324
  );
4286
- return findValidEntrypoint(fsFiles, candidates);
4325
+ return found ? { entrypoint: found } : null;
4287
4326
  } catch {
4288
4327
  (0, import_build_utils6.debug)("Failed to discover Python entrypoint");
4289
4328
  return null;
@@ -4292,48 +4331,33 @@ async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
4292
4331
  async function detectDjangoPythonEntrypoint(workPath, configuredEntrypoint) {
4293
4332
  const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
4294
4333
  try {
4295
- const fsFiles = await (0, import_build_utils6.glob)("**", workPath);
4296
- if (fsFiles[entry]) {
4297
- const isValid = await (0, import_build_utils6.isPythonEntrypoint)(fsFiles[entry]);
4298
- if (isValid) {
4299
- (0, import_build_utils6.debug)(`Using configured Python entrypoint: ${entry}`);
4300
- return entry;
4301
- }
4334
+ if (await checkEntrypoint(workPath, entry)) {
4335
+ (0, import_build_utils6.debug)(`Using configured Python entrypoint: ${entry}`);
4336
+ return { entrypoint: entry };
4302
4337
  }
4303
- const rootGlobs = await (0, import_build_utils6.glob)("*", {
4304
- cwd: workPath,
4305
- includeDirectories: true
4306
- });
4307
- const rootDirs = [
4308
- "",
4309
- ...Object.keys(rootGlobs).filter(
4310
- (name) => !name.startsWith(".") && rootGlobs[name].mode != null && (0, import_build_utils6.isDirectory)(rootGlobs[name].mode)
4311
- )
4312
- ];
4338
+ const subdirs = await getSubdirectories(workPath);
4339
+ const rootDirs = ["", ...subdirs];
4313
4340
  for (const rootDir of rootDirs) {
4314
4341
  const currPath = (0, import_path7.join)(workPath, rootDir);
4315
- const wsgiEntry = await (0, import_build_utils6.getDjangoEntrypoint)(currPath);
4316
- if (wsgiEntry) {
4317
- const fullWsgiEntry = import_path7.posix.join(rootDir, wsgiEntry);
4318
- if (fsFiles[fullWsgiEntry]) {
4319
- (0, import_build_utils6.debug)(`Using Django WSGI entrypoint: ${fullWsgiEntry}`);
4320
- return fullWsgiEntry;
4321
- }
4342
+ const isDjango = await checkDjangoManage(currPath);
4343
+ if (isDjango) {
4344
+ return { baseDir: rootDir };
4322
4345
  }
4323
4346
  }
4324
- const baseCandidates = getCandidateEntrypointsInDirs(rootDirs);
4325
- const candidates = baseCandidates.filter((c) => !!fsFiles[c]);
4326
- return findValidEntrypoint(fsFiles, candidates);
4347
+ const candidates = getCandidateEntrypointsInDirs(rootDirs);
4348
+ const found = await findValidEntrypoint(workPath, candidates);
4349
+ return found ? { entrypoint: found } : null;
4327
4350
  } catch {
4328
4351
  (0, import_build_utils6.debug)("Failed to discover Django Python entrypoint");
4329
4352
  return null;
4330
4353
  }
4331
4354
  }
4332
4355
  async function detectPythonEntrypoint(framework, workPath, configuredEntrypoint) {
4333
- const entrypoint = framework === "django" ? await detectDjangoPythonEntrypoint(workPath, configuredEntrypoint) : await detectGenericPythonEntrypoint(workPath, configuredEntrypoint);
4334
- if (entrypoint)
4335
- return entrypoint;
4336
- return await getPyprojectEntrypoint(workPath);
4356
+ const result = framework === "django" ? await detectDjangoPythonEntrypoint(workPath, configuredEntrypoint) : await detectGenericPythonEntrypoint(workPath, configuredEntrypoint);
4357
+ if (result)
4358
+ return result;
4359
+ const pyprojectEntry = await getPyprojectEntrypoint(workPath);
4360
+ return pyprojectEntry ? { entrypoint: pyprojectEntry } : null;
4337
4361
  }
4338
4362
 
4339
4363
  // src/start-dev-server.ts
@@ -4424,10 +4448,10 @@ async function syncDependencies({
4424
4448
  }
4425
4449
  if (manifest?.origin && manifestType === "pyproject.toml") {
4426
4450
  const syncDir = (0, import_path8.join)(workPath, ".vercel", "python", "sync");
4427
- (0, import_fs5.mkdirSync)(syncDir, { recursive: true });
4451
+ (0, import_fs6.mkdirSync)(syncDir, { recursive: true });
4428
4452
  const tempPyproject = (0, import_path8.join)(syncDir, "pyproject.toml");
4429
4453
  const content = (0, import_python_analysis4.stringifyManifest)(manifest.data);
4430
- (0, import_fs5.writeFileSync)(tempPyproject, content, "utf8");
4454
+ (0, import_fs6.writeFileSync)(tempPyproject, content, "utf8");
4431
4455
  manifestPath = tempPyproject;
4432
4456
  (0, import_build_utils8.debug)(
4433
4457
  `Wrote converted ${manifest.origin.kind} manifest to ${tempPyproject}`
@@ -4588,20 +4612,25 @@ function installGlobalCleanupHandlers() {
4588
4612
  function createDevShim(workPath, entry, modulePath) {
4589
4613
  try {
4590
4614
  const vercelPythonDir = (0, import_path8.join)(workPath, ".vercel", "python");
4591
- (0, import_fs5.mkdirSync)(vercelPythonDir, { recursive: true });
4615
+ (0, import_fs6.mkdirSync)(vercelPythonDir, { recursive: true });
4592
4616
  let qualifiedModule = modulePath;
4593
4617
  let extraPythonPath;
4594
- if ((0, import_fs5.existsSync)((0, import_path8.join)(workPath, "__init__.py"))) {
4618
+ if ((0, import_fs6.existsSync)((0, import_path8.join)(workPath, "__init__.py"))) {
4595
4619
  const pkgName = (0, import_path8.basename)(workPath);
4596
4620
  qualifiedModule = `${pkgName}.${modulePath}`;
4597
4621
  extraPythonPath = (0, import_path8.dirname)(workPath);
4598
4622
  }
4599
4623
  const entryAbs = (0, import_path8.join)(workPath, entry);
4600
4624
  const shimPath = (0, import_path8.join)(vercelPythonDir, `${DEV_SHIM_MODULE}.py`);
4601
- const templatePath = (0, import_path8.join)(__dirname, "..", `${DEV_SHIM_MODULE}.py`);
4602
- const template = (0, import_fs5.readFileSync)(templatePath, "utf8");
4625
+ const templatePath = (0, import_path8.join)(
4626
+ __dirname,
4627
+ "..",
4628
+ "templates",
4629
+ `${DEV_SHIM_MODULE}.py`
4630
+ );
4631
+ const template = (0, import_fs6.readFileSync)(templatePath, "utf8");
4603
4632
  const shimSource = template.replace(/__VC_DEV_MODULE_NAME__/g, qualifiedModule).replace(/__VC_DEV_ENTRY_ABS__/g, entryAbs);
4604
- (0, import_fs5.writeFileSync)(shimPath, shimSource, "utf8");
4633
+ (0, import_fs6.writeFileSync)(shimPath, shimSource, "utf8");
4605
4634
  (0, import_build_utils8.debug)(`Prepared Python dev shim at ${shimPath}`);
4606
4635
  return { module: DEV_SHIM_MODULE, extraPythonPath };
4607
4636
  } catch (err) {
@@ -4616,7 +4645,12 @@ async function getMultiServicePythonRunner(workPath, env, systemPython, uvPath)
4616
4645
  return { command: pythonCmd, args: [] };
4617
4646
  }
4618
4647
  const venvPath = (0, import_path8.join)(workPath, ".venv");
4619
- await ensureVenv({ pythonPath: systemPython, venvPath, uvPath, quiet: true });
4648
+ await ensureVenv({
4649
+ pythonPath: systemPython,
4650
+ venvPath,
4651
+ uvPath,
4652
+ quiet: true
4653
+ });
4620
4654
  (0, import_build_utils8.debug)(`Created virtualenv at ${venvPath} for multi-service dev`);
4621
4655
  const pythonBin = getVenvPythonBin(venvPath);
4622
4656
  const binDir = getVenvBinDir(venvPath);
@@ -4634,29 +4668,7 @@ var startDevServer = async (opts) => {
4634
4668
  onStderr
4635
4669
  } = opts;
4636
4670
  const framework = config?.framework;
4637
- if (!framework) {
4638
- return null;
4639
- }
4640
- if (!restoreWarnings)
4641
- restoreWarnings = silenceNodeWarnings();
4642
- installGlobalCleanupHandlers();
4643
- const entry = await detectPythonEntrypoint(
4644
- framework,
4645
- workPath,
4646
- rawEntrypoint
4647
- );
4648
- if (!entry) {
4649
- const searched = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
4650
- throw new import_build_utils8.NowBuildError({
4651
- code: "PYTHON_ENTRYPOINT_NOT_FOUND",
4652
- message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searched}.`,
4653
- link: `https://vercel.com/docs/frameworks/backend/${framework?.toLowerCase()}#exporting-the-${framework?.toLowerCase()}-application`,
4654
- action: "Learn More"
4655
- });
4656
- }
4657
- const modulePath = entry.replace(/\.py$/i, "").replace(/[\\/]/g, ".");
4658
- const env = { ...process.env, ...meta.env || {} };
4659
- const serverKey = `${workPath}::${entry}::${framework}`;
4671
+ const serverKey = `${workPath}::${framework}`;
4660
4672
  const existing = PERSISTENT_SERVERS.get(serverKey);
4661
4673
  if (existing) {
4662
4674
  return {
@@ -4678,6 +4690,38 @@ var startDevServer = async (opts) => {
4678
4690
  };
4679
4691
  }
4680
4692
  }
4693
+ if (!framework) {
4694
+ return null;
4695
+ }
4696
+ if (!restoreWarnings)
4697
+ restoreWarnings = silenceNodeWarnings();
4698
+ installGlobalCleanupHandlers();
4699
+ const detected = await detectPythonEntrypoint(
4700
+ framework,
4701
+ workPath,
4702
+ rawEntrypoint
4703
+ );
4704
+ const env = { ...process.env, ...meta.env || {} };
4705
+ let entry = detected?.entrypoint;
4706
+ if (!entry) {
4707
+ const hookResult = await runFrameworkHook(framework, {
4708
+ pythonEnv: env,
4709
+ projectDir: (0, import_path8.join)(workPath, detected?.baseDir ?? ""),
4710
+ entrypoint: rawEntrypoint,
4711
+ detected: detected ?? void 0
4712
+ });
4713
+ entry = hookResult?.entrypoint;
4714
+ }
4715
+ if (!entry) {
4716
+ const searched = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
4717
+ throw new import_build_utils8.NowBuildError({
4718
+ code: "PYTHON_ENTRYPOINT_NOT_FOUND",
4719
+ message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searched}.`,
4720
+ link: `https://vercel.com/docs/frameworks/backend/${framework?.toLowerCase()}#exporting-the-${framework?.toLowerCase()}-application`,
4721
+ action: "Learn More"
4722
+ });
4723
+ }
4724
+ const modulePath = entry.replace(/\.py$/i, "").replace(/[\\/]/g, ".");
4681
4725
  let childProcess = null;
4682
4726
  let stdoutLogListener = null;
4683
4727
  let stderrLogListener = null;
@@ -4851,7 +4895,7 @@ var matplotlibQuirk = {
4851
4895
  };
4852
4896
 
4853
4897
  // src/quirks/litellm.ts
4854
- var import_fs6 = __toESM(require("fs"));
4898
+ var import_fs7 = __toESM(require("fs"));
4855
4899
  var import_path9 = require("path");
4856
4900
  var import_build_utils9 = require("@vercel/build-utils");
4857
4901
  var LAMBDA_ROOT = "/var/task";
@@ -4865,7 +4909,7 @@ async function findConfigFile(workPath) {
4865
4909
  for (const name of CONFIG_CANDIDATES) {
4866
4910
  const candidate = (0, import_path9.join)(workPath, name);
4867
4911
  try {
4868
- await import_fs6.default.promises.access(candidate);
4912
+ await import_fs7.default.promises.access(candidate);
4869
4913
  return name;
4870
4914
  } catch {
4871
4915
  }
@@ -4887,7 +4931,7 @@ var litellmQuirk = {
4887
4931
  "schema.prisma"
4888
4932
  );
4889
4933
  try {
4890
- await import_fs6.default.promises.access(schemaPath);
4934
+ await import_fs7.default.promises.access(schemaPath);
4891
4935
  (0, import_build_utils9.debug)(`LiteLLM quirk: found schema at ${schemaPath}`);
4892
4936
  buildEnv.PRISMA_SCHEMA_PATH = schemaPath;
4893
4937
  break;
@@ -4914,7 +4958,7 @@ var litellmQuirk = {
4914
4958
  };
4915
4959
 
4916
4960
  // src/quirks/prisma.ts
4917
- var import_fs7 = __toESM(require("fs"));
4961
+ var import_fs8 = __toESM(require("fs"));
4918
4962
  var import_path10 = require("path");
4919
4963
  var import_execa4 = __toESM(require_execa());
4920
4964
  var import_build_utils10 = require("@vercel/build-utils");
@@ -4956,7 +5000,7 @@ async function findUserSchema(workPath) {
4956
5000
  if (envPath) {
4957
5001
  const resolved = (0, import_path10.isAbsolute)(envPath) ? envPath : (0, import_path10.join)(workPath, envPath);
4958
5002
  try {
4959
- await import_fs7.default.promises.access(resolved);
5003
+ await import_fs8.default.promises.access(resolved);
4960
5004
  return resolved;
4961
5005
  } catch {
4962
5006
  (0, import_build_utils10.debug)(`PRISMA_SCHEMA_PATH=${envPath} not found at ${resolved}`);
@@ -4969,7 +5013,7 @@ async function findUserSchema(workPath) {
4969
5013
  ];
4970
5014
  for (const candidate of candidates) {
4971
5015
  try {
4972
- await import_fs7.default.promises.access(candidate);
5016
+ await import_fs8.default.promises.access(candidate);
4973
5017
  return candidate;
4974
5018
  } catch {
4975
5019
  }
@@ -4980,7 +5024,7 @@ async function collectFiles(dir, base) {
4980
5024
  const result = [];
4981
5025
  let entries;
4982
5026
  try {
4983
- entries = await import_fs7.default.promises.readdir(dir, { withFileTypes: true });
5027
+ entries = await import_fs8.default.promises.readdir(dir, { withFileTypes: true });
4984
5028
  } catch {
4985
5029
  return result;
4986
5030
  }
@@ -5005,7 +5049,7 @@ async function cleanCacheArtifacts(cacheDir, extras = []) {
5005
5049
  ];
5006
5050
  for (const p of paths) {
5007
5051
  try {
5008
- await import_fs7.default.promises.rm(p, { recursive: true, force: true });
5052
+ await import_fs8.default.promises.rm(p, { recursive: true, force: true });
5009
5053
  } catch (err) {
5010
5054
  console.warn(
5011
5055
  `could not clean up ${p}: ${err instanceof Error ? err.message : String(err)}`
@@ -5039,7 +5083,7 @@ var prismaQuirk = {
5039
5083
  let sitePackages;
5040
5084
  for (const dir of sitePackagesDirs) {
5041
5085
  try {
5042
- await import_fs7.default.promises.access((0, import_path10.join)(dir, "prisma"));
5086
+ await import_fs8.default.promises.access((0, import_path10.join)(dir, "prisma"));
5043
5087
  sitePackages = dir;
5044
5088
  break;
5045
5089
  } catch {
@@ -5052,14 +5096,14 @@ var prismaQuirk = {
5052
5096
  return {};
5053
5097
  }
5054
5098
  const cacheDir = (0, import_path10.join)(sitePackages, "prisma", "__bincache__");
5055
- await import_fs7.default.promises.mkdir(cacheDir, { recursive: true });
5099
+ await import_fs8.default.promises.mkdir(cacheDir, { recursive: true });
5056
5100
  const generateEnv = {
5057
5101
  ...pythonEnv,
5058
5102
  PRISMA_BINARY_CACHE_DIR: cacheDir
5059
5103
  };
5060
5104
  const generatedDir = (0, import_path10.join)(workPath, "_prisma_generated");
5061
5105
  const dummySchemaPath = (0, import_path10.join)(workPath, DUMMY_SCHEMA_NAME);
5062
- await import_fs7.default.promises.writeFile(
5106
+ await import_fs8.default.promises.writeFile(
5063
5107
  dummySchemaPath,
5064
5108
  buildDummySchema(generatedDir)
5065
5109
  );
@@ -5090,18 +5134,18 @@ var prismaQuirk = {
5090
5134
  const nodeModulesDir = (0, import_path10.join)(cacheDir, "node_modules", "prisma");
5091
5135
  let engineCopied = false;
5092
5136
  try {
5093
- const entries = await import_fs7.default.promises.readdir(nodeModulesDir);
5137
+ const entries = await import_fs8.default.promises.readdir(nodeModulesDir);
5094
5138
  for (const entry of entries) {
5095
5139
  if (!entry.startsWith(srcBinaryPrefix))
5096
5140
  continue;
5097
5141
  const srcPath = (0, import_path10.join)(nodeModulesDir, entry);
5098
5142
  const destPath = (0, import_path10.join)(cacheDir, runtimeName);
5099
5143
  try {
5100
- await import_fs7.default.promises.access(destPath);
5144
+ await import_fs8.default.promises.access(destPath);
5101
5145
  (0, import_build_utils10.debug)(`Engine binary: ${runtimeName} already exists, skipping`);
5102
5146
  } catch {
5103
5147
  (0, import_build_utils10.debug)(`Engine binary: copying ${entry} -> ${runtimeName}`);
5104
- await import_fs7.default.promises.copyFile(srcPath, destPath);
5148
+ await import_fs8.default.promises.copyFile(srcPath, destPath);
5105
5149
  }
5106
5150
  engineCopied = true;
5107
5151
  }
@@ -5119,15 +5163,15 @@ var prismaQuirk = {
5119
5163
  });
5120
5164
  }
5121
5165
  const shimPath = (0, import_path10.join)(cacheDir, "openssl");
5122
- await import_fs7.default.promises.writeFile(
5166
+ await import_fs8.default.promises.writeFile(
5123
5167
  shimPath,
5124
5168
  `#!/bin/sh
5125
5169
  echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIME_OPENSSL_VERSION}.0)"
5126
5170
  `
5127
5171
  );
5128
- await import_fs7.default.promises.chmod(shimPath, 493);
5172
+ await import_fs8.default.promises.chmod(shimPath, 493);
5129
5173
  for (const p of [generatedDir, dummySchemaPath]) {
5130
- await import_fs7.default.promises.rm(p, { recursive: true, force: true });
5174
+ await import_fs8.default.promises.rm(p, { recursive: true, force: true });
5131
5175
  }
5132
5176
  await cleanCacheArtifacts(cacheDir);
5133
5177
  const generateMode = (process.env.VERCEL_PRISMA_GENERATE_CLIENT ?? "auto").toLowerCase();
@@ -5299,22 +5343,74 @@ async function runQuirks(ctx) {
5299
5343
  };
5300
5344
  }
5301
5345
 
5346
+ // src/django.ts
5347
+ var import_fs9 = require("fs");
5348
+ var import_path11 = require("path");
5349
+ var import_execa5 = __toESM(require_execa());
5350
+ var import_build_utils12 = require("@vercel/build-utils");
5351
+ var scriptPath = (0, import_path11.join)(__dirname, "..", "templates", "vc_django_settings.py");
5352
+ var script = (0, import_fs9.readFileSync)(scriptPath, "utf-8");
5353
+ async function getDjangoSettings(projectDir, env) {
5354
+ try {
5355
+ const { stdout } = await (0, import_execa5.default)("python", ["-c", script], {
5356
+ env,
5357
+ cwd: projectDir
5358
+ });
5359
+ return JSON.parse(stdout);
5360
+ } catch (err) {
5361
+ (0, import_build_utils12.debug)(`Django hook: failed to discover settings from manage.py: ${err}`);
5362
+ return null;
5363
+ }
5364
+ }
5365
+
5302
5366
  // src/index.ts
5303
- var writeFile = import_fs8.default.promises.writeFile;
5367
+ var import_python_analysis7 = require("@vercel/python-analysis");
5368
+ var writeFile = import_fs10.default.promises.writeFile;
5304
5369
  var version = 3;
5370
+ async function runFrameworkHook(framework, ctx) {
5371
+ const hook = framework ? frameworkHooks[framework] : void 0;
5372
+ return hook?.(ctx);
5373
+ }
5374
+ var frameworkHooks = {
5375
+ django: async ({ pythonEnv, projectDir, detected }) => {
5376
+ if (detected?.baseDir === void 0) {
5377
+ (0, import_build_utils13.debug)("Django hook: no manage.py detected, skipping");
5378
+ return;
5379
+ }
5380
+ const settings = await getDjangoSettings(projectDir, pythonEnv);
5381
+ (0, import_build_utils13.debug)(`Django settings: ${JSON.stringify(settings)}`);
5382
+ if (!settings)
5383
+ return;
5384
+ const baseDir = detected?.baseDir ?? "";
5385
+ const asgiApp = settings["ASGI_APPLICATION"];
5386
+ if (typeof asgiApp === "string") {
5387
+ const rel = `${asgiApp.split(".").slice(0, -1).join("/")}.py`;
5388
+ const entrypoint = baseDir ? `${baseDir}/${rel}` : rel;
5389
+ (0, import_build_utils13.debug)(`Django hook: ASGI entrypoint: ${entrypoint}`);
5390
+ return { entrypoint };
5391
+ }
5392
+ const wsgiApp = settings["WSGI_APPLICATION"];
5393
+ if (typeof wsgiApp === "string") {
5394
+ const rel = `${wsgiApp.split(".").slice(0, -1).join("/")}.py`;
5395
+ const entrypoint = baseDir ? `${baseDir}/${rel}` : rel;
5396
+ (0, import_build_utils13.debug)(`Django hook: WSGI entrypoint: ${entrypoint}`);
5397
+ return { entrypoint };
5398
+ }
5399
+ }
5400
+ };
5305
5401
  async function downloadFilesInWorkPath({
5306
5402
  entrypoint,
5307
5403
  workPath,
5308
5404
  files,
5309
5405
  meta = {}
5310
5406
  }) {
5311
- (0, import_build_utils12.debug)("Downloading user files...");
5312
- let downloadedFiles = await (0, import_build_utils12.download)(files, workPath, meta);
5407
+ (0, import_build_utils13.debug)("Downloading user files...");
5408
+ let downloadedFiles = await (0, import_build_utils13.download)(files, workPath, meta);
5313
5409
  if (meta.isDev) {
5314
- const { devCacheDir = (0, import_path11.join)(workPath, ".now", "cache") } = meta;
5315
- const destCache = (0, import_path11.join)(devCacheDir, (0, import_path11.basename)(entrypoint, ".py"));
5316
- await (0, import_build_utils12.download)(downloadedFiles, destCache);
5317
- downloadedFiles = await (0, import_build_utils12.glob)("**", destCache);
5410
+ const { devCacheDir = (0, import_path12.join)(workPath, ".now", "cache") } = meta;
5411
+ const destCache = (0, import_path12.join)(devCacheDir, (0, import_path12.basename)(entrypoint, ".py"));
5412
+ await (0, import_build_utils13.download)(downloadedFiles, destCache);
5413
+ downloadedFiles = await (0, import_build_utils13.glob)("**", destCache);
5318
5414
  workPath = destCache;
5319
5415
  }
5320
5416
  return workPath;
@@ -5328,13 +5424,13 @@ var build = async ({
5328
5424
  config,
5329
5425
  span: parentSpan
5330
5426
  }) => {
5331
- const builderSpan = parentSpan ?? new import_build_utils12.Span({ name: "vc.builder" });
5427
+ const builderSpan = parentSpan ?? new import_build_utils13.Span({ name: "vc.builder" });
5332
5428
  const framework = config?.framework;
5333
5429
  const shouldInstallVercelWorkers = config?.hasWorkerServices === true;
5334
5430
  let spawnEnv;
5335
5431
  let projectInstallCommand;
5336
5432
  let hasCustomCommand = false;
5337
- (0, import_build_utils12.debug)(`workPath: ${workPath}`);
5433
+ (0, import_build_utils13.debug)(`workPath: ${workPath}`);
5338
5434
  workPath = await downloadFilesInWorkPath({
5339
5435
  workPath,
5340
5436
  files: originalFiles,
@@ -5343,28 +5439,31 @@ var build = async ({
5343
5439
  });
5344
5440
  try {
5345
5441
  if (meta.isDev) {
5346
- const setupCfg = (0, import_path11.join)(workPath, "setup.cfg");
5442
+ const setupCfg = (0, import_path12.join)(workPath, "setup.cfg");
5347
5443
  await writeFile(setupCfg, "[install]\nprefix=\n");
5348
5444
  }
5349
5445
  } catch (err) {
5350
5446
  console.log('Failed to create "setup.cfg" file');
5351
5447
  throw err;
5352
5448
  }
5353
- let fsFiles = await (0, import_build_utils12.glob)("**", workPath);
5354
- if ((0, import_build_utils12.isPythonFramework)(framework) && (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
5355
- const detected = await detectPythonEntrypoint(
5449
+ let fsFiles = await (0, import_build_utils13.glob)("**", workPath);
5450
+ let detected;
5451
+ let entrypointNotFound;
5452
+ if ((0, import_build_utils13.isPythonFramework)(framework) && // XXX: we might want to detect anyway for django!
5453
+ (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
5454
+ detected = await detectPythonEntrypoint(
5356
5455
  config.framework,
5357
5456
  workPath,
5358
5457
  entrypoint
5359
- );
5360
- if (detected) {
5361
- (0, import_build_utils12.debug)(
5362
- `Resolved Python entrypoint to "${detected}" (configured "${entrypoint}" not found).`
5458
+ ) ?? void 0;
5459
+ if (detected?.entrypoint) {
5460
+ (0, import_build_utils13.debug)(
5461
+ `Resolved Python entrypoint to "${detected.entrypoint}" (configured "${entrypoint}" not found).`
5363
5462
  );
5364
- entrypoint = detected;
5463
+ entrypoint = detected.entrypoint;
5365
5464
  } else {
5366
5465
  const searchedList = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
5367
- throw new import_build_utils12.NowBuildError({
5466
+ entrypointNotFound = new import_build_utils13.NowBuildError({
5368
5467
  code: `${framework.toUpperCase()}_ENTRYPOINT_NOT_FOUND`,
5369
5468
  message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searchedList}.`,
5370
5469
  link: `https://vercel.com/docs/frameworks/backend/${framework}#exporting-the-${framework}-application`,
@@ -5372,8 +5471,11 @@ var build = async ({
5372
5471
  });
5373
5472
  }
5374
5473
  }
5375
- const entryDirectory = (0, import_path11.dirname)(entrypoint);
5376
- const entrypointAbsDir = (0, import_path11.join)(workPath, entryDirectory);
5474
+ if (entrypointNotFound && detected?.baseDir === void 0) {
5475
+ throw entrypointNotFound;
5476
+ }
5477
+ const entryDirectory = detected?.baseDir ?? (0, import_path12.dirname)(entrypoint);
5478
+ const entrypointAbsDir = (0, import_path12.join)(workPath, entryDirectory);
5377
5479
  const rootDir = repoRootPath ?? workPath;
5378
5480
  const pythonPackage = await builderSpan.child("vc.builder.python.discover").trace(
5379
5481
  () => discoverPackage({
@@ -5403,22 +5505,24 @@ var build = async ({
5403
5505
  `
5404
5506
  );
5405
5507
  }
5406
- fsFiles = await (0, import_build_utils12.glob)("**", workPath);
5407
- const venvPath = (0, import_path11.join)(workPath, ".vercel", "python", ".venv");
5508
+ fsFiles = await (0, import_build_utils13.glob)("**", workPath);
5509
+ const venvPath = (0, import_path12.join)(workPath, ".vercel", "python", ".venv");
5510
+ const uvCacheDir = getUvCacheDir(workPath);
5408
5511
  await builderSpan.child("vc.builder.python.venv").trace(async () => {
5409
5512
  await ensureVenv({
5410
5513
  pythonPath: pythonVersion.pythonPath,
5411
- venvPath
5514
+ venvPath,
5515
+ uvCacheDir
5412
5516
  });
5413
5517
  });
5414
- if ((0, import_build_utils12.isPythonFramework)(framework)) {
5518
+ if ((0, import_build_utils13.isPythonFramework)(framework)) {
5415
5519
  const {
5416
5520
  cliType,
5417
5521
  lockfileVersion,
5418
5522
  packageJsonPackageManager,
5419
5523
  turboSupportsCorepackHome
5420
- } = await (0, import_build_utils12.scanParentDirs)(workPath, true);
5421
- spawnEnv = (0, import_build_utils12.getEnvForPackageManager)({
5524
+ } = await (0, import_build_utils13.scanParentDirs)(workPath, true);
5525
+ spawnEnv = (0, import_build_utils13.getEnvForPackageManager)({
5422
5526
  cliType,
5423
5527
  lockfileVersion,
5424
5528
  packageJsonPackageManager,
@@ -5437,14 +5541,14 @@ var build = async ({
5437
5541
  }
5438
5542
  }
5439
5543
  const baseEnv = spawnEnv || process.env;
5440
- const pythonEnv = createVenvEnv(venvPath, baseEnv);
5544
+ const pythonEnv = createVenvEnv(venvPath, baseEnv, uvCacheDir);
5441
5545
  pythonEnv.VERCEL_PYTHON_VENV_PATH = venvPath;
5442
5546
  let assumeDepsInstalled = false;
5443
5547
  let uv;
5444
5548
  try {
5445
5549
  const uvPath = await getUvBinaryOrInstall(pythonVersion.pythonPath);
5446
5550
  console.log(`Using uv at "${uvPath}"`);
5447
- uv = new UvRunner(uvPath);
5551
+ uv = new UvRunner(uvPath, uvCacheDir);
5448
5552
  } catch (err) {
5449
5553
  console.log("Failed to install or locate uv");
5450
5554
  throw new Error(
@@ -5455,14 +5559,14 @@ var build = async ({
5455
5559
  let uvProjectDir = null;
5456
5560
  let projectName;
5457
5561
  let noBuildCheckFailed = false;
5458
- await builderSpan.child(import_build_utils12.BUILDER_INSTALLER_STEP, {
5562
+ await builderSpan.child(import_build_utils13.BUILDER_INSTALLER_STEP, {
5459
5563
  installCommand: projectInstallCommand || void 0
5460
5564
  }).trace(async () => {
5461
5565
  if (projectInstallCommand) {
5462
5566
  console.log(
5463
5567
  `Running "install" command: \`${projectInstallCommand}\`...`
5464
5568
  );
5465
- await (0, import_build_utils12.execCommand)(projectInstallCommand, {
5569
+ await (0, import_build_utils13.execCommand)(projectInstallCommand, {
5466
5570
  env: pythonEnv,
5467
5571
  cwd: workPath
5468
5572
  });
@@ -5504,7 +5608,7 @@ var build = async ({
5504
5608
  });
5505
5609
  } catch (err) {
5506
5610
  noBuildCheckFailed = true;
5507
- (0, import_build_utils12.debug)(
5611
+ (0, import_build_utils13.debug)(
5508
5612
  `--no-build check failed: ${err instanceof Error ? err.message : String(err)}`
5509
5613
  );
5510
5614
  }
@@ -5517,15 +5621,15 @@ var build = async ({
5517
5621
  });
5518
5622
  }
5519
5623
  });
5520
- if ((0, import_build_utils12.isPythonFramework)(framework)) {
5624
+ if ((0, import_build_utils13.isPythonFramework)(framework)) {
5521
5625
  const projectBuildCommand = config?.projectSettings?.buildCommand ?? // fallback if provided directly on config (some callers set this)
5522
5626
  config?.buildCommand;
5523
- await builderSpan.child(import_build_utils12.BUILDER_COMPILE_STEP, {
5627
+ await builderSpan.child(import_build_utils13.BUILDER_COMPILE_STEP, {
5524
5628
  buildCommand: projectBuildCommand || void 0
5525
5629
  }).trace(async () => {
5526
5630
  if (projectBuildCommand) {
5527
5631
  console.log(`Running "${projectBuildCommand}"`);
5528
- await (0, import_build_utils12.execCommand)(projectBuildCommand, {
5632
+ await (0, import_build_utils13.execCommand)(projectBuildCommand, {
5529
5633
  env: pythonEnv,
5530
5634
  cwd: workPath
5531
5635
  });
@@ -5538,19 +5642,32 @@ var build = async ({
5538
5642
  }
5539
5643
  });
5540
5644
  }
5645
+ const hookResult = await runFrameworkHook(framework, {
5646
+ pythonEnv,
5647
+ projectDir: (0, import_path12.join)(workPath, entryDirectory),
5648
+ entrypoint,
5649
+ detected
5650
+ });
5651
+ if (entrypointNotFound && hookResult?.entrypoint) {
5652
+ entrypoint = hookResult.entrypoint;
5653
+ entrypointNotFound = void 0;
5654
+ }
5655
+ if (entrypointNotFound) {
5656
+ throw entrypointNotFound;
5657
+ }
5541
5658
  const runtimeDep = baseEnv.VERCEL_RUNTIME_PYTHON || `vercel-runtime==${VERCEL_RUNTIME_VERSION}`;
5542
- (0, import_build_utils12.debug)(`Installing ${runtimeDep}`);
5659
+ (0, import_build_utils13.debug)(`Installing ${runtimeDep}`);
5543
5660
  await uv.pip({
5544
5661
  venvPath,
5545
- projectDir: (0, import_path11.join)(workPath, entryDirectory),
5662
+ projectDir: (0, import_path12.join)(workPath, entryDirectory),
5546
5663
  args: ["install", runtimeDep]
5547
5664
  });
5548
5665
  if (shouldInstallVercelWorkers) {
5549
5666
  const workersDep = baseEnv.VERCEL_WORKERS_PYTHON || `vercel-workers==${VERCEL_WORKERS_VERSION}`;
5550
- (0, import_build_utils12.debug)(`Installing ${workersDep}`);
5667
+ (0, import_build_utils13.debug)(`Installing ${workersDep}`);
5551
5668
  await uv.pip({
5552
5669
  venvPath,
5553
- projectDir: (0, import_path11.join)(workPath, entryDirectory),
5670
+ projectDir: (0, import_path12.join)(workPath, entryDirectory),
5554
5671
  args: ["install", workersDep]
5555
5672
  });
5556
5673
  }
@@ -5558,12 +5675,26 @@ var build = async ({
5558
5675
  if (quirksResult.buildEnv) {
5559
5676
  Object.assign(pythonEnv, quirksResult.buildEnv);
5560
5677
  }
5561
- (0, import_build_utils12.debug)("Entrypoint is", entrypoint);
5678
+ (0, import_build_utils13.debug)("Entrypoint is", entrypoint);
5562
5679
  const moduleName = entrypoint.replace(/\//g, ".").replace(/\.py$/i, "");
5680
+ const handlerFunction = typeof config?.handlerFunction === "string" ? config.handlerFunction : void 0;
5681
+ if (handlerFunction) {
5682
+ const entrypointPath = (0, import_path12.join)(workPath, entrypoint);
5683
+ const source = await import_fs10.default.promises.readFile(entrypointPath, "utf-8");
5684
+ const found = await (0, import_python_analysis7.containsTopLevelCallable)(source, handlerFunction);
5685
+ if (!found) {
5686
+ throw new import_build_utils13.NowBuildError({
5687
+ code: "PYTHON_HANDLER_NOT_FOUND",
5688
+ message: `Handler function "${handlerFunction}" not found in ${entrypoint}. Ensure it is defined at the module's top level.`
5689
+ });
5690
+ }
5691
+ }
5563
5692
  const vendorDir = resolveVendorDir();
5564
5693
  const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
5565
5694
  const entrypointWithSuffix = `${entrypoint}${suffix}`;
5566
- (0, import_build_utils12.debug)("Entrypoint with suffix is", entrypointWithSuffix);
5695
+ (0, import_build_utils13.debug)("Entrypoint with suffix is", entrypointWithSuffix);
5696
+ const handlerFuncEnvLine = handlerFunction ? `
5697
+ "__VC_HANDLER_FUNC_NAME": "${handlerFunction}",` : "";
5567
5698
  const runtimeTrampoline = `
5568
5699
  import importlib
5569
5700
  import os
@@ -5577,7 +5708,7 @@ os.environ.update({
5577
5708
  "__VC_HANDLER_MODULE_NAME": "${moduleName}",
5578
5709
  "__VC_HANDLER_ENTRYPOINT": "${entrypointWithSuffix}",
5579
5710
  "__VC_HANDLER_ENTRYPOINT_ABS": os.path.join(_here, "${entrypointWithSuffix}"),
5580
- "__VC_HANDLER_VENDOR_DIR": "${vendorDir}",
5711
+ "__VC_HANDLER_VENDOR_DIR": "${vendorDir}",${handlerFuncEnvLine}
5581
5712
  })
5582
5713
 
5583
5714
  _vendor_rel = '${vendorDir}'
@@ -5627,7 +5758,7 @@ from vercel_runtime.vc_init import vc_handler
5627
5758
  cwd: workPath,
5628
5759
  ignore: config && typeof config.excludeFiles === "string" ? [...predefinedExcludes, config.excludeFiles] : predefinedExcludes
5629
5760
  };
5630
- const files = await (0, import_build_utils12.glob)("**", globOptions);
5761
+ const files = await (0, import_build_utils13.glob)("**", globOptions);
5631
5762
  const depExternalizer = new PythonDependencyExternalizer({
5632
5763
  venvPath,
5633
5764
  vendorDir,
@@ -5660,12 +5791,12 @@ from vercel_runtime.vc_init import vc_handler
5660
5791
  }
5661
5792
  });
5662
5793
  const handlerPyFilename = "vc__handler__python";
5663
- files[`${handlerPyFilename}.py`] = new import_build_utils12.FileBlob({ data: runtimeTrampoline });
5794
+ files[`${handlerPyFilename}.py`] = new import_build_utils13.FileBlob({ data: runtimeTrampoline });
5664
5795
  if (config.framework === "fasthtml") {
5665
5796
  const { SESSKEY = "" } = process.env;
5666
- files[".sesskey"] = new import_build_utils12.FileBlob({ data: `"${SESSKEY}"` });
5797
+ files[".sesskey"] = new import_build_utils13.FileBlob({ data: `"${SESSKEY}"` });
5667
5798
  }
5668
- const output = new import_build_utils12.Lambda({
5799
+ const output = new import_build_utils13.Lambda({
5669
5800
  files,
5670
5801
  handler: `${handlerPyFilename}.vc_handler`,
5671
5802
  runtime: pythonVersion.runtime,
@@ -5674,9 +5805,44 @@ from vercel_runtime.vc_init import vc_handler
5674
5805
  });
5675
5806
  return { output };
5676
5807
  };
5808
+ async function readBuildOutputV3Config(workPath) {
5809
+ try {
5810
+ const configPath = (0, import_path12.join)(workPath, ".vercel", "output", "config.json");
5811
+ return JSON.parse(await import_fs10.default.promises.readFile(configPath, "utf8"));
5812
+ } catch (err) {
5813
+ if (err.code !== "ENOENT") {
5814
+ throw err;
5815
+ }
5816
+ }
5817
+ return void 0;
5818
+ }
5819
+ var prepareCache = async ({
5820
+ repoRootPath,
5821
+ workPath
5822
+ }) => {
5823
+ const cacheFiles = {};
5824
+ const root = repoRootPath || workPath;
5825
+ const ignore = ["**/*.pyc", "**/__pycache__/**"];
5826
+ const configV3 = await readBuildOutputV3Config(workPath);
5827
+ if (configV3?.cache && Array.isArray(configV3.cache)) {
5828
+ for (const cacheGlob of configV3.cache) {
5829
+ Object.assign(cacheFiles, await (0, import_build_utils13.glob)(cacheGlob, workPath));
5830
+ }
5831
+ return cacheFiles;
5832
+ }
5833
+ Object.assign(
5834
+ cacheFiles,
5835
+ await (0, import_build_utils13.glob)("**/.vercel/python/.venv/**", { cwd: root, ignore })
5836
+ );
5837
+ Object.assign(
5838
+ cacheFiles,
5839
+ await (0, import_build_utils13.glob)("**/.vercel/python/cache/uv/**", { cwd: root, ignore })
5840
+ );
5841
+ return cacheFiles;
5842
+ };
5677
5843
  var shouldServe = (opts) => {
5678
5844
  const framework = opts.config.framework;
5679
- if ((0, import_build_utils12.isPythonFramework)(framework)) {
5845
+ if ((0, import_build_utils13.isPythonFramework)(framework)) {
5680
5846
  const requestPath = opts.requestPath.replace(/\/$/, "");
5681
5847
  if (requestPath.startsWith("api") && opts.hasMatched) {
5682
5848
  return false;
@@ -5695,7 +5861,7 @@ var defaultShouldServe = ({
5695
5861
  if (entrypoint === requestPath && hasProp(files, entrypoint)) {
5696
5862
  return true;
5697
5863
  }
5698
- const { dir, name } = (0, import_path11.parse)(entrypoint);
5864
+ const { dir, name } = (0, import_path12.parse)(entrypoint);
5699
5865
  if (name === "index" && dir === requestPath && hasProp(files, entrypoint)) {
5700
5866
  return true;
5701
5867
  }
@@ -5711,6 +5877,8 @@ function hasProp(obj, key) {
5711
5877
  downloadFilesInWorkPath,
5712
5878
  installRequirement,
5713
5879
  installRequirementsFile,
5880
+ prepareCache,
5881
+ runFrameworkHook,
5714
5882
  shouldServe,
5715
5883
  startDevServer,
5716
5884
  version