@vercel/python 6.26.0 → 6.29.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
@@ -3223,15 +3223,16 @@ __export(src_exports, {
3223
3223
  version: () => version
3224
3224
  });
3225
3225
  module.exports = __toCommonJS(src_exports);
3226
+ var import_child_process3 = require("child_process");
3226
3227
  var import_fs11 = __toESM(require("fs"));
3227
3228
  var import_path13 = require("path");
3228
3229
 
3229
3230
  // src/package-versions.ts
3230
- var VERCEL_RUNTIME_VERSION = "0.10.1";
3231
+ var VERCEL_RUNTIME_VERSION = "0.12.0";
3231
3232
  var VERCEL_WORKERS_VERSION = "0.0.13";
3232
3233
 
3233
3234
  // src/index.ts
3234
- var import_build_utils14 = require("@vercel/build-utils");
3235
+ var import_build_utils15 = require("@vercel/build-utils");
3235
3236
 
3236
3237
  // src/install.ts
3237
3238
  var import_execa3 = __toESM(require_execa());
@@ -3257,7 +3258,7 @@ var import_fs = __toESM(require("fs"));
3257
3258
  var import_os = __toESM(require("os"));
3258
3259
  var import_which = __toESM(require_lib());
3259
3260
  var import_build_utils = require("@vercel/build-utils");
3260
- var UV_VERSION = "0.9.22";
3261
+ var UV_VERSION = "0.10.11";
3261
3262
  var UV_PYTHON_PATH_PREFIX = "/uv/python/";
3262
3263
  var UV_PYTHON_DOWNLOADS_MODE = "automatic";
3263
3264
  var isWin = process.platform === "win32";
@@ -3641,7 +3642,27 @@ function detectPlatform() {
3641
3642
  osMinor = 17;
3642
3643
  }
3643
3644
  const libc = libcFamily === detectLibc.MUSL ? "musl" : "gnu";
3644
- return { osName, archName, osMajor, osMinor, os: "linux", libc };
3645
+ const SYS_PLATFORM_MAP = {
3646
+ linux: "linux",
3647
+ win32: "win32",
3648
+ darwin: "darwin"
3649
+ };
3650
+ const sysPlatform = SYS_PLATFORM_MAP[process.platform] || "linux";
3651
+ const OS_MAP = {
3652
+ linux: "linux",
3653
+ win32: "windows",
3654
+ darwin: "macos"
3655
+ };
3656
+ const detectedOs = OS_MAP[process.platform] || "linux";
3657
+ return {
3658
+ osName,
3659
+ archName,
3660
+ osMajor,
3661
+ osMinor,
3662
+ os: detectedOs,
3663
+ sysPlatform,
3664
+ libc
3665
+ };
3645
3666
  }
3646
3667
 
3647
3668
  // src/version.ts
@@ -4499,10 +4520,31 @@ To fix this, either:
4499
4520
  * Identify public packages that have no compatible wheel for the Lambda platform.
4500
4521
  * These packages must be force-bundled because `uv sync --no-build` at cold start
4501
4522
  * will refuse to build from source.
4523
+ *
4524
+ * Packages that are not reachable on the target platform (e.g. pywin32 which is
4525
+ * only a dependency when `sys_platform == 'win32'`) are excluded -- they will
4526
+ * never be installed by `uv sync` on Lambda, so their wheel compatibility is
4527
+ * irrelevant.
4502
4528
  */
4503
4529
  async findPackagesWithoutCompatibleWheels(lockFile, publicPackageNames) {
4504
4530
  const platform = detectPlatform();
4505
- const publicSet = new Set(publicPackageNames.map(import_python_analysis3.normalizePackageName));
4531
+ const reachable = await getPackagesReachableOnPlatform(
4532
+ lockFile,
4533
+ this.projectName,
4534
+ this.pythonMajor,
4535
+ this.pythonMinor,
4536
+ platform.sysPlatform,
4537
+ platform.archName
4538
+ );
4539
+ const relevantPackages = reachable ? publicPackageNames.filter(
4540
+ (name) => reachable.has((0, import_python_analysis3.normalizePackageName)(name))
4541
+ ) : publicPackageNames;
4542
+ if (relevantPackages.length < publicPackageNames.length) {
4543
+ (0, import_build_utils5.debug)(
4544
+ `Skipping wheel check for ${publicPackageNames.length - relevantPackages.length} package(s) not reachable on the target platform`
4545
+ );
4546
+ }
4547
+ const publicSet = new Set(relevantPackages.map(import_python_analysis3.normalizePackageName));
4506
4548
  const packageWheels = /* @__PURE__ */ new Map();
4507
4549
  for (const pkg of lockFile.packages) {
4508
4550
  const normalized = (0, import_python_analysis3.normalizePackageName)(pkg.name);
@@ -4511,7 +4553,7 @@ To fix this, either:
4511
4553
  }
4512
4554
  }
4513
4555
  const incompatible = [];
4514
- for (const name of publicPackageNames) {
4556
+ for (const name of relevantPackages) {
4515
4557
  const normalized = (0, import_python_analysis3.normalizePackageName)(name);
4516
4558
  const wheels = packageWheels.get(normalized);
4517
4559
  if (!wheels || wheels.length === 0) {
@@ -4550,6 +4592,64 @@ To fix this, either:
4550
4592
  return incompatible;
4551
4593
  }
4552
4594
  };
4595
+ async function getPackagesReachableOnPlatform(lockFile, projectName, pythonMajor, pythonMinor, sysPlatform, platformMachine) {
4596
+ if (!projectName)
4597
+ return null;
4598
+ const rootNormalized = (0, import_python_analysis3.normalizePackageName)(projectName);
4599
+ const packageMap = /* @__PURE__ */ new Map();
4600
+ for (const pkg of lockFile.packages) {
4601
+ packageMap.set((0, import_python_analysis3.normalizePackageName)(pkg.name), pkg);
4602
+ }
4603
+ const rootPkg = packageMap.get(rootNormalized);
4604
+ if (!rootPkg)
4605
+ return null;
4606
+ const visited = /* @__PURE__ */ new Set();
4607
+ const queue = [];
4608
+ let queueHead = 0;
4609
+ async function enqueueDeps(pkg) {
4610
+ if (!pkg.dependencies)
4611
+ return;
4612
+ for (const dep of pkg.dependencies) {
4613
+ const normalized = (0, import_python_analysis3.normalizePackageName)(dep.name);
4614
+ if (visited.has(normalized))
4615
+ continue;
4616
+ if (dep.marker) {
4617
+ try {
4618
+ const compatible = await (0, import_python_analysis3.evaluateMarker)(
4619
+ dep.marker,
4620
+ pythonMajor,
4621
+ pythonMinor,
4622
+ sysPlatform,
4623
+ platformMachine
4624
+ );
4625
+ if (!compatible) {
4626
+ (0, import_build_utils5.debug)(
4627
+ `Skipping dependency ${dep.name}: marker "${dep.marker}" not satisfied on ${sysPlatform}`
4628
+ );
4629
+ continue;
4630
+ }
4631
+ } catch (err) {
4632
+ (0, import_build_utils5.debug)(
4633
+ `Failed to evaluate marker "${dep.marker}" for ${dep.name}, including conservatively: ${err instanceof Error ? err.message : String(err)}`
4634
+ );
4635
+ }
4636
+ }
4637
+ queue.push(normalized);
4638
+ }
4639
+ }
4640
+ await enqueueDeps(rootPkg);
4641
+ while (queueHead < queue.length) {
4642
+ const current = queue[queueHead++];
4643
+ if (visited.has(current))
4644
+ continue;
4645
+ visited.add(current);
4646
+ const pkg = packageMap.get(current);
4647
+ if (pkg) {
4648
+ await enqueueDeps(pkg);
4649
+ }
4650
+ }
4651
+ return visited;
4652
+ }
4553
4653
  async function mirrorPackagesIntoVendor({
4554
4654
  venvPath,
4555
4655
  vendorDirName,
@@ -4904,7 +5004,7 @@ var diagnostics = async ({
4904
5004
  var import_child_process2 = require("child_process");
4905
5005
  var import_fs7 = require("fs");
4906
5006
  var import_path9 = require("path");
4907
- var import_build_utils9 = require("@vercel/build-utils");
5007
+ var import_build_utils10 = require("@vercel/build-utils");
4908
5008
  var import_get_port = __toESM(require_get_port());
4909
5009
  var import_is_port_reachable = __toESM(require_is_port_reachable());
4910
5010
 
@@ -4913,6 +5013,8 @@ var import_fs6 = __toESM(require("fs"));
4913
5013
  var import_path8 = require("path");
4914
5014
  var import_build_utils7 = require("@vercel/build-utils");
4915
5015
  var import_build_utils8 = require("@vercel/build-utils");
5016
+ var import_build_utils9 = require("@vercel/build-utils");
5017
+ var import_python_analysis5 = require("@vercel/python-analysis");
4916
5018
  var PYTHON_ENTRYPOINT_FILENAMES = [
4917
5019
  "app",
4918
5020
  "index",
@@ -4943,11 +5045,12 @@ async function fileExists(filePath) {
4943
5045
  async function checkEntrypoint(workPath, relPath) {
4944
5046
  const absPath = (0, import_path8.join)(workPath, relPath);
4945
5047
  if (!await fileExists(absPath))
4946
- return false;
4947
- return (0, import_build_utils7.isPythonEntrypoint)({ fsPath: absPath });
5048
+ return null;
5049
+ const content = await import_fs6.default.promises.readFile(absPath, "utf-8");
5050
+ return (0, import_python_analysis5.findAppOrHandler)(content);
4948
5051
  }
4949
5052
  async function getPyprojectEntrypoint(workPath) {
4950
- const pyprojectData = await (0, import_build_utils8.readConfigFile)((0, import_path8.join)(workPath, "pyproject.toml"));
5053
+ const pyprojectData = await (0, import_build_utils9.readConfigFile)((0, import_path8.join)(workPath, "pyproject.toml"));
4951
5054
  if (!pyprojectData)
4952
5055
  return null;
4953
5056
  const scripts = pyprojectData.project?.scripts;
@@ -4970,9 +5073,10 @@ async function getPyprojectEntrypoint(workPath) {
4970
5073
  }
4971
5074
  async function findValidEntrypoint(workPath, candidates) {
4972
5075
  for (const candidate of candidates) {
4973
- if (await checkEntrypoint(workPath, candidate)) {
4974
- (0, import_build_utils7.debug)(`Detected Python entrypoint: ${candidate}`);
4975
- return candidate;
5076
+ const varName = await checkEntrypoint(workPath, candidate);
5077
+ if (varName) {
5078
+ (0, import_build_utils8.debug)(`Detected Python entrypoint: ${candidate} (variable: ${varName})`);
5079
+ return { entrypoint: candidate, variableName: varName };
4976
5080
  }
4977
5081
  }
4978
5082
  return null;
@@ -4983,7 +5087,7 @@ async function checkDjangoManage(workPath) {
4983
5087
  const content = await import_fs6.default.promises.readFile(managePath, "utf-8");
4984
5088
  if (!content.includes("DJANGO_SETTINGS_MODULE"))
4985
5089
  return false;
4986
- (0, import_build_utils7.debug)(`Found Django manage.py with DJANGO_SETTINGS_MODULE at ${workPath}`);
5090
+ (0, import_build_utils8.debug)(`Found Django manage.py with DJANGO_SETTINGS_MODULE at ${workPath}`);
4987
5091
  return true;
4988
5092
  } catch {
4989
5093
  return false;
@@ -4999,62 +5103,82 @@ async function getSubdirectories(workPath) {
4999
5103
  return [];
5000
5104
  }
5001
5105
  }
5002
- async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
5003
- const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
5106
+ function makeDetectError(framework) {
5107
+ const searchedList = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
5108
+ return new import_build_utils7.NowBuildError({
5109
+ code: `${framework.toUpperCase()}_ENTRYPOINT_NOT_FOUND`,
5110
+ message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searchedList}.`,
5111
+ link: `https://vercel.com/docs/frameworks/backend/${framework}#exporting-the-${framework}-application`,
5112
+ action: "Learn More"
5113
+ });
5114
+ }
5115
+ async function detectGenericPythonEntrypoint(workPath) {
5004
5116
  try {
5005
- if (await checkEntrypoint(workPath, entry)) {
5006
- (0, import_build_utils7.debug)(`Using configured Python entrypoint: ${entry}`);
5007
- return { entrypoint: entry };
5008
- }
5009
5117
  const found = await findValidEntrypoint(
5010
5118
  workPath,
5011
5119
  PYTHON_CANDIDATE_ENTRYPOINTS
5012
5120
  );
5013
5121
  return found ? { entrypoint: found } : null;
5014
5122
  } catch {
5015
- (0, import_build_utils7.debug)("Failed to discover Python entrypoint");
5123
+ (0, import_build_utils8.debug)("Failed to discover Python entrypoint");
5016
5124
  return null;
5017
5125
  }
5018
5126
  }
5019
- async function detectDjangoPythonEntrypoint(workPath, configuredEntrypoint) {
5020
- const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
5127
+ async function detectDjangoPythonEntrypoint(workPath) {
5021
5128
  try {
5022
- if (await checkEntrypoint(workPath, entry)) {
5023
- (0, import_build_utils7.debug)(`Using configured Python entrypoint: ${entry}`);
5024
- return { entrypoint: entry };
5025
- }
5026
5129
  const subdirs = await getSubdirectories(workPath);
5027
5130
  const rootDirs = ["", ...subdirs];
5028
5131
  for (const rootDir of rootDirs) {
5029
5132
  const currPath = (0, import_path8.join)(workPath, rootDir);
5030
5133
  const isDjango = await checkDjangoManage(currPath);
5031
5134
  if (isDjango) {
5032
- return { baseDir: rootDir };
5135
+ return { baseDir: rootDir, error: makeDetectError("django") };
5033
5136
  }
5034
5137
  }
5035
5138
  const candidates = getCandidateEntrypointsInDirs(rootDirs);
5036
5139
  const found = await findValidEntrypoint(workPath, candidates);
5037
5140
  return found ? { entrypoint: found } : null;
5038
5141
  } catch {
5039
- (0, import_build_utils7.debug)("Failed to discover Django Python entrypoint");
5142
+ (0, import_build_utils8.debug)("Failed to discover Django Python entrypoint");
5040
5143
  return null;
5041
5144
  }
5042
5145
  }
5043
- async function detectPythonEntrypoint(framework, workPath, configuredEntrypoint) {
5044
- const result = framework === "django" ? await detectDjangoPythonEntrypoint(workPath, configuredEntrypoint) : await detectGenericPythonEntrypoint(workPath, configuredEntrypoint);
5146
+ async function detectPythonEntrypoint(framework, workPath, configuredEntrypoint, service) {
5147
+ if (configuredEntrypoint) {
5148
+ const entrypoint = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
5149
+ let varName = await checkEntrypoint(workPath, entrypoint);
5150
+ if (!varName) {
5151
+ const isSpecialService = service?.type === "cron" || service?.type === "worker";
5152
+ if (isSpecialService) {
5153
+ varName = "app";
5154
+ }
5155
+ }
5156
+ if (varName) {
5157
+ (0, import_build_utils8.debug)(`Using configured Python entrypoint: ${entrypoint}`);
5158
+ return { entrypoint: { entrypoint, variableName: varName } };
5159
+ } else {
5160
+ return {
5161
+ error: new import_build_utils7.NowBuildError({
5162
+ code: "PYTHON_ENTRYPOINT_NOT_FOUND",
5163
+ message: `Could not find a top-level "app", "application", or "handler" in "${entrypoint}".`,
5164
+ link: "https://vercel.com/docs/functions/serverless-functions/runtimes/python",
5165
+ action: "Learn More"
5166
+ })
5167
+ };
5168
+ }
5169
+ }
5170
+ if (!framework) {
5171
+ return null;
5172
+ }
5173
+ const result = framework === "django" ? await detectDjangoPythonEntrypoint(workPath) : await detectGenericPythonEntrypoint(workPath);
5045
5174
  if (result)
5046
5175
  return result;
5047
5176
  const pyprojectEntry = await getPyprojectEntrypoint(workPath);
5048
- if (!pyprojectEntry)
5049
- return null;
5050
- return {
5051
- entrypoint: pyprojectEntry.entrypoint,
5052
- variableName: pyprojectEntry.variableName
5053
- };
5177
+ return pyprojectEntry ? { entrypoint: pyprojectEntry } : { error: makeDetectError(framework) };
5054
5178
  }
5055
5179
 
5056
5180
  // src/start-dev-server.ts
5057
- var import_python_analysis5 = require("@vercel/python-analysis");
5181
+ var import_python_analysis6 = require("@vercel/python-analysis");
5058
5182
  var DEV_SERVER_STARTUP_TIMEOUT = 5 * 6e4;
5059
5183
  function silenceNodeWarnings() {
5060
5184
  const original = process.emitWarning.bind(
@@ -5140,17 +5264,17 @@ async function syncDependencies({
5140
5264
  let { manifestPath } = installInfo;
5141
5265
  const manifest = pythonPackage.manifest;
5142
5266
  if (!manifestType || !manifestPath) {
5143
- (0, import_build_utils9.debug)("No Python project manifest found, skipping dependency sync");
5267
+ (0, import_build_utils10.debug)("No Python project manifest found, skipping dependency sync");
5144
5268
  return;
5145
5269
  }
5146
5270
  if (manifest?.origin && manifestType === "pyproject.toml") {
5147
5271
  const syncDir = (0, import_path9.join)(workPath, ".vercel", "python", "sync");
5148
5272
  (0, import_fs7.mkdirSync)(syncDir, { recursive: true });
5149
5273
  const tempPyproject = (0, import_path9.join)(syncDir, "pyproject.toml");
5150
- const content = (0, import_python_analysis5.stringifyManifest)(manifest.data);
5274
+ const content = (0, import_python_analysis6.stringifyManifest)(manifest.data);
5151
5275
  (0, import_fs7.writeFileSync)(tempPyproject, content, "utf8");
5152
5276
  manifestPath = tempPyproject;
5153
- (0, import_build_utils9.debug)(
5277
+ (0, import_build_utils10.debug)(
5154
5278
  `Wrote converted ${manifest.origin.kind} manifest to ${tempPyproject}`
5155
5279
  );
5156
5280
  }
@@ -5183,7 +5307,7 @@ async function syncDependencies({
5183
5307
  for (const [channel, chunk] of captured) {
5184
5308
  (channel === "stdout" ? writeOut : writeErr)(chunk.toString());
5185
5309
  }
5186
- throw new import_build_utils9.NowBuildError({
5310
+ throw new import_build_utils10.NowBuildError({
5187
5311
  code: "PYTHON_DEPENDENCY_SYNC_FAILED",
5188
5312
  message: `Failed to install Python dependencies from ${manifestType}: ${err instanceof Error ? err.message : String(err)}`
5189
5313
  });
@@ -5205,7 +5329,7 @@ async function runSync({
5205
5329
  switch (manifestType) {
5206
5330
  case "uv.lock": {
5207
5331
  if (!uvPath) {
5208
- throw new import_build_utils9.NowBuildError({
5332
+ throw new import_build_utils10.NowBuildError({
5209
5333
  code: "PYTHON_DEPENDENCY_SYNC_FAILED",
5210
5334
  message: "uv is required to install dependencies from uv.lock.",
5211
5335
  link: "https://docs.astral.sh/uv/getting-started/installation/",
@@ -5227,11 +5351,11 @@ async function runSync({
5227
5351
  break;
5228
5352
  }
5229
5353
  default:
5230
- (0, import_build_utils9.debug)(`Unknown manifest type: ${manifestType}`);
5354
+ (0, import_build_utils10.debug)(`Unknown manifest type: ${manifestType}`);
5231
5355
  return;
5232
5356
  }
5233
5357
  await new Promise((resolve3, reject) => {
5234
- (0, import_build_utils9.debug)(`Running "${spawnCmd} ${spawnArgs.join(" ")}" in ${projectDir}...`);
5358
+ (0, import_build_utils10.debug)(`Running "${spawnCmd} ${spawnArgs.join(" ")}" in ${projectDir}...`);
5235
5359
  const child = (0, import_child_process2.spawn)(spawnCmd, spawnArgs, {
5236
5360
  cwd: projectDir,
5237
5361
  env: getProtectedUvEnv(env),
@@ -5318,13 +5442,13 @@ async function doInstallVercelRuntime({
5318
5442
  `vercel_runtime-${VERCEL_RUNTIME_VERSION}.dist-info`
5319
5443
  );
5320
5444
  if ((0, import_fs7.existsSync)(distInfo)) {
5321
- (0, import_build_utils9.debug)(
5445
+ (0, import_build_utils10.debug)(
5322
5446
  `vercel-runtime ${VERCEL_RUNTIME_VERSION} already installed, skipping`
5323
5447
  );
5324
5448
  return;
5325
5449
  }
5326
5450
  }
5327
- (0, import_build_utils9.debug)(
5451
+ (0, import_build_utils10.debug)(
5328
5452
  `Installing vercel-runtime into ${targetDir} (type: ${isLocalDev ? "local" : "pypi"}, source: ${runtimeDep})`
5329
5453
  );
5330
5454
  const pip = uvPath ? { cmd: uvPath, prefix: ["pip", "install"] } : { cmd: pythonBin, prefix: ["-m", "pip", "install"] };
@@ -5339,14 +5463,14 @@ async function doInstallVercelRuntime({
5339
5463
  if (onStdout) {
5340
5464
  onStdout(data);
5341
5465
  } else {
5342
- (0, import_build_utils9.debug)(data.toString());
5466
+ (0, import_build_utils10.debug)(data.toString());
5343
5467
  }
5344
5468
  });
5345
5469
  child.stderr?.on("data", (data) => {
5346
5470
  if (onStderr) {
5347
5471
  onStderr(data);
5348
5472
  } else {
5349
- (0, import_build_utils9.debug)(data.toString());
5473
+ (0, import_build_utils10.debug)(data.toString());
5350
5474
  }
5351
5475
  });
5352
5476
  child.on("error", reject);
@@ -5414,13 +5538,13 @@ async function doInstallVercelWorkers({
5414
5538
  `vercel_workers-${VERCEL_WORKERS_VERSION}.dist-info`
5415
5539
  );
5416
5540
  if ((0, import_fs7.existsSync)(distInfo)) {
5417
- (0, import_build_utils9.debug)(
5541
+ (0, import_build_utils10.debug)(
5418
5542
  `vercel-workers ${VERCEL_WORKERS_VERSION} already installed, skipping`
5419
5543
  );
5420
5544
  return;
5421
5545
  }
5422
5546
  }
5423
- (0, import_build_utils9.debug)(
5547
+ (0, import_build_utils10.debug)(
5424
5548
  `Installing vercel-workers into ${targetDir} (type: ${isLocalDev ? "local" : "pypi"}, source: ${workersDep})`
5425
5549
  );
5426
5550
  const pip = uvPath ? { cmd: uvPath, prefix: ["pip", "install"] } : { cmd: pythonBin, prefix: ["-m", "pip", "install"] };
@@ -5435,14 +5559,14 @@ async function doInstallVercelWorkers({
5435
5559
  if (onStdout) {
5436
5560
  onStdout(data);
5437
5561
  } else {
5438
- (0, import_build_utils9.debug)(data.toString());
5562
+ (0, import_build_utils10.debug)(data.toString());
5439
5563
  }
5440
5564
  });
5441
5565
  child.stderr?.on("data", (data) => {
5442
5566
  if (onStderr) {
5443
5567
  onStderr(data);
5444
5568
  } else {
5445
- (0, import_build_utils9.debug)(data.toString());
5569
+ (0, import_build_utils10.debug)(data.toString());
5446
5570
  }
5447
5571
  });
5448
5572
  child.on("error", reject);
@@ -5472,12 +5596,12 @@ function installGlobalCleanupHandlers() {
5472
5596
  try {
5473
5597
  process.kill(info.pid, "SIGTERM");
5474
5598
  } catch (err) {
5475
- (0, import_build_utils9.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
5599
+ (0, import_build_utils10.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
5476
5600
  }
5477
5601
  try {
5478
5602
  process.kill(info.pid, "SIGKILL");
5479
5603
  } catch (err) {
5480
- (0, import_build_utils9.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
5604
+ (0, import_build_utils10.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
5481
5605
  }
5482
5606
  PERSISTENT_SERVERS.delete(key);
5483
5607
  }
@@ -5485,7 +5609,7 @@ function installGlobalCleanupHandlers() {
5485
5609
  try {
5486
5610
  restoreWarnings();
5487
5611
  } catch (err) {
5488
- (0, import_build_utils9.debug)(`Error restoring warnings: ${err}`);
5612
+ (0, import_build_utils10.debug)(`Error restoring warnings: ${err}`);
5489
5613
  }
5490
5614
  restoreWarnings = null;
5491
5615
  }
@@ -5522,26 +5646,26 @@ function createDevShim(workPath, entry, modulePath, serviceName, framework, vari
5522
5646
  const template = (0, import_fs7.readFileSync)(templatePath, "utf8");
5523
5647
  const shimSource = template.replace(/__VC_DEV_MODULE_NAME__/g, qualifiedModule).replace(/__VC_DEV_ENTRY_ABS__/g, entryAbs).replace(/__VC_DEV_FRAMEWORK__/g, framework).replace(/__VC_DEV_VARIABLE_NAME__/g, variableName);
5524
5648
  (0, import_fs7.writeFileSync)(shimPath, shimSource, "utf8");
5525
- (0, import_build_utils9.debug)(`Prepared Python dev shim at ${shimPath}`);
5649
+ (0, import_build_utils10.debug)(`Prepared Python dev shim at ${shimPath}`);
5526
5650
  return {
5527
5651
  module: DEV_SHIM_MODULE,
5528
5652
  extraPythonPath,
5529
5653
  shimDir: vercelPythonDir
5530
5654
  };
5531
5655
  } catch (err) {
5532
- (0, import_build_utils9.debug)(`Failed to prepare dev shim: ${err?.message || err}`);
5656
+ (0, import_build_utils10.debug)(`Failed to prepare dev shim: ${err?.message || err}`);
5533
5657
  return null;
5534
5658
  }
5535
5659
  }
5536
5660
  async function getMultiServicePythonRunner(workPath, env, systemPython, uvPath) {
5537
5661
  const { pythonCmd, venvRoot } = useVirtualEnv(workPath, env, systemPython);
5538
5662
  if (venvRoot) {
5539
- (0, import_build_utils9.debug)(`Using existing virtualenv at ${venvRoot} for multi-service dev`);
5663
+ (0, import_build_utils10.debug)(`Using existing virtualenv at ${venvRoot} for multi-service dev`);
5540
5664
  return { command: pythonCmd, args: [] };
5541
5665
  }
5542
5666
  const venvPath = (0, import_path9.join)(workPath, ".venv");
5543
5667
  await ensureVenv({ pythonPath: systemPython, venvPath, uvPath, quiet: true });
5544
- (0, import_build_utils9.debug)(`Created virtualenv at ${venvPath} for multi-service dev`);
5668
+ (0, import_build_utils10.debug)(`Created virtualenv at ${venvPath} for multi-service dev`);
5545
5669
  const pythonBin = getVenvPythonBin(venvPath);
5546
5670
  const binDir = getVenvBinDir(venvPath);
5547
5671
  env.VIRTUAL_ENV = venvPath;
@@ -5554,11 +5678,12 @@ var startDevServer = async (opts) => {
5554
5678
  workPath,
5555
5679
  meta = {},
5556
5680
  config,
5681
+ service,
5557
5682
  onStdout,
5558
5683
  onStderr
5559
5684
  } = opts;
5560
5685
  const framework = config?.framework;
5561
- const serviceName = typeof meta.serviceName === "string" ? meta.serviceName : void 0;
5686
+ const serviceName = service?.name ?? (typeof meta.serviceName === "string" ? meta.serviceName : void 0);
5562
5687
  const serverKey = serviceName ? `${workPath}::${framework}::${serviceName}` : `${workPath}::${framework}`;
5563
5688
  const existing = PERSISTENT_SERVERS.get(serverKey);
5564
5689
  if (existing) {
@@ -5588,40 +5713,36 @@ var startDevServer = async (opts) => {
5588
5713
  restoreWarnings = silenceNodeWarnings();
5589
5714
  installGlobalCleanupHandlers();
5590
5715
  const env = { ...process.env, ...meta.env || {} };
5591
- const serviceType = env.VERCEL_SERVICE_TYPE;
5592
- let entry;
5593
- let variableName;
5594
- if ((serviceType === "cron" || serviceType === "worker") && rawEntrypoint?.endsWith(".py")) {
5595
- entry = rawEntrypoint;
5716
+ const entrypoint = rawEntrypoint === "<detect>" ? void 0 : rawEntrypoint;
5717
+ let resolved;
5718
+ const detected = await detectPythonEntrypoint(
5719
+ framework,
5720
+ workPath,
5721
+ entrypoint,
5722
+ service
5723
+ );
5724
+ if (detected?.entrypoint) {
5725
+ resolved = detected.entrypoint;
5596
5726
  } else {
5597
- const detected = await detectPythonEntrypoint(
5598
- framework,
5727
+ const hookResult = await runFrameworkHook(framework, {
5728
+ pythonEnv: env,
5729
+ projectDir: (0, import_path9.join)(workPath, detected?.baseDir ?? ""),
5599
5730
  workPath,
5600
- rawEntrypoint
5601
- );
5602
- entry = detected?.entrypoint;
5603
- variableName = detected?.variableName;
5604
- if (!entry) {
5605
- const hookResult = await runFrameworkHook(framework, {
5606
- pythonEnv: env,
5607
- projectDir: (0, import_path9.join)(workPath, detected?.baseDir ?? ""),
5608
- workPath,
5609
- entrypoint: rawEntrypoint,
5610
- detected: detected ?? void 0
5611
- });
5612
- entry = hookResult?.entrypoint;
5613
- variableName = hookResult?.variableName;
5614
- }
5615
- if (!entry) {
5616
- const searched = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
5617
- throw new import_build_utils9.NowBuildError({
5618
- code: "PYTHON_ENTRYPOINT_NOT_FOUND",
5619
- message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searched}.`,
5620
- link: `https://vercel.com/docs/frameworks/backend/${framework?.toLowerCase()}#exporting-the-${framework?.toLowerCase()}-application`,
5621
- action: "Learn More"
5622
- });
5731
+ entrypoint,
5732
+ detected: detected ?? void 0
5733
+ });
5734
+ resolved = hookResult?.entrypoint;
5735
+ }
5736
+ if (!resolved) {
5737
+ if (detected?.error) {
5738
+ throw detected.error;
5623
5739
  }
5740
+ throw new import_build_utils10.NowBuildError({
5741
+ code: "PYTHON_ENTRYPOINT_NOT_FOUND",
5742
+ message: "No Python entrypoint could be detected. Please specify an entrypoint file."
5743
+ });
5624
5744
  }
5745
+ const { entrypoint: entry, variableName } = resolved;
5625
5746
  const modulePath = entry.replace(/\.py$/i, "").replace(/[\\/]/g, ".");
5626
5747
  let childProcess = null;
5627
5748
  let stdoutLogListener = null;
@@ -5645,7 +5766,7 @@ var startDevServer = async (opts) => {
5645
5766
  const yellow = "\x1B[33m";
5646
5767
  const white = "\x1B[1m";
5647
5768
  const reset = "\x1B[0m";
5648
- throw new import_build_utils9.NowBuildError({
5769
+ throw new import_build_utils10.NowBuildError({
5649
5770
  code: "PYTHON_EXTERNAL_VENV_DETECTED",
5650
5771
  message: `Detected activated venv at ${yellow}${venv}${reset}, ${white}vercel dev${reset} manages virtual environments automatically.
5651
5772
  Run ${white}deactivate${reset} and try again.`
@@ -5662,11 +5783,11 @@ Run ${white}deactivate${reset} and try again.`
5662
5783
  );
5663
5784
  spawnCommand = runner.command;
5664
5785
  spawnArgsPrefix = runner.args;
5665
- (0, import_build_utils9.debug)(
5786
+ (0, import_build_utils10.debug)(
5666
5787
  `Multi-service Python runner: ${spawnCommand} ${spawnArgsPrefix.join(" ")}`
5667
5788
  );
5668
5789
  } else if (venv) {
5669
- (0, import_build_utils9.debug)(`Running in virtualenv at ${venv}`);
5790
+ (0, import_build_utils10.debug)(`Running in virtualenv at ${venv}`);
5670
5791
  } else {
5671
5792
  const { pythonCmd: venvPythonCmd, venvRoot } = useVirtualEnv(
5672
5793
  workPath,
@@ -5675,9 +5796,9 @@ Run ${white}deactivate${reset} and try again.`
5675
5796
  );
5676
5797
  spawnCommand = venvPythonCmd;
5677
5798
  if (venvRoot) {
5678
- (0, import_build_utils9.debug)(`Using virtualenv at ${venvRoot}`);
5799
+ (0, import_build_utils10.debug)(`Using virtualenv at ${venvRoot}`);
5679
5800
  } else {
5680
- (0, import_build_utils9.debug)("No virtualenv found");
5801
+ (0, import_build_utils10.debug)("No virtualenv found");
5681
5802
  try {
5682
5803
  const yellow = "\x1B[33m";
5683
5804
  const reset = "\x1B[0m";
@@ -5758,7 +5879,7 @@ If you are using a virtual environment, activate it before running "vercel dev",
5758
5879
  const moduleToRun = devShim?.module || modulePath;
5759
5880
  const pythonArgs = ["-u", "-m", moduleToRun];
5760
5881
  const argv = [...spawnArgsPrefix, ...pythonArgs];
5761
- (0, import_build_utils9.debug)(
5882
+ (0, import_build_utils10.debug)(
5762
5883
  `Starting Python dev server (${framework}): ${spawnCommand} ${argv.join(" ")} [PORT=${port}]`
5763
5884
  );
5764
5885
  if (process.stdout.columns) {
@@ -5812,8 +5933,8 @@ If you are using a virtual environment, activate it before running "vercel dev",
5812
5933
  };
5813
5934
 
5814
5935
  // src/quirks/index.ts
5815
- var import_build_utils12 = require("@vercel/build-utils");
5816
- var import_python_analysis7 = require("@vercel/python-analysis");
5936
+ var import_build_utils13 = require("@vercel/build-utils");
5937
+ var import_python_analysis8 = require("@vercel/python-analysis");
5817
5938
 
5818
5939
  // src/quirks/matplotlib.ts
5819
5940
  var matplotlibQuirk = {
@@ -5828,7 +5949,7 @@ var matplotlibQuirk = {
5828
5949
  // src/quirks/litellm.ts
5829
5950
  var import_fs8 = __toESM(require("fs"));
5830
5951
  var import_path10 = require("path");
5831
- var import_build_utils10 = require("@vercel/build-utils");
5952
+ var import_build_utils11 = require("@vercel/build-utils");
5832
5953
  var LAMBDA_ROOT = "/var/task";
5833
5954
  var CONFIG_CANDIDATES = [
5834
5955
  "litellm_config.yaml",
@@ -5863,24 +5984,24 @@ var litellmQuirk = {
5863
5984
  );
5864
5985
  try {
5865
5986
  await import_fs8.default.promises.access(schemaPath);
5866
- (0, import_build_utils10.debug)(`LiteLLM quirk: found schema at ${schemaPath}`);
5987
+ (0, import_build_utils11.debug)(`LiteLLM quirk: found schema at ${schemaPath}`);
5867
5988
  buildEnv.PRISMA_SCHEMA_PATH = schemaPath;
5868
5989
  break;
5869
5990
  } catch {
5870
5991
  }
5871
5992
  }
5872
5993
  if (!buildEnv.PRISMA_SCHEMA_PATH) {
5873
- (0, import_build_utils10.debug)("LiteLLM quirk: schema.prisma not found in any site-packages");
5994
+ (0, import_build_utils11.debug)("LiteLLM quirk: schema.prisma not found in any site-packages");
5874
5995
  }
5875
5996
  if (!process.env.CONFIG_FILE_PATH) {
5876
5997
  const configName = await findConfigFile(ctx.workPath);
5877
5998
  if (configName) {
5878
- (0, import_build_utils10.debug)(`LiteLLM quirk: found config at ${configName}`);
5999
+ (0, import_build_utils11.debug)(`LiteLLM quirk: found config at ${configName}`);
5879
6000
  buildEnv.CONFIG_FILE_PATH = (0, import_path10.join)(ctx.workPath, configName);
5880
6001
  env.CONFIG_FILE_PATH = (0, import_path10.join)(LAMBDA_ROOT, configName);
5881
6002
  }
5882
6003
  } else {
5883
- (0, import_build_utils10.debug)(
6004
+ (0, import_build_utils11.debug)(
5884
6005
  `LiteLLM quirk: CONFIG_FILE_PATH already set to ${process.env.CONFIG_FILE_PATH}`
5885
6006
  );
5886
6007
  }
@@ -5892,8 +6013,8 @@ var litellmQuirk = {
5892
6013
  var import_fs9 = __toESM(require("fs"));
5893
6014
  var import_path11 = require("path");
5894
6015
  var import_execa4 = __toESM(require_execa());
5895
- var import_build_utils11 = require("@vercel/build-utils");
5896
- var import_python_analysis6 = require("@vercel/python-analysis");
6016
+ var import_build_utils12 = require("@vercel/build-utils");
6017
+ var import_python_analysis7 = require("@vercel/python-analysis");
5897
6018
  function execErrorMessage(err) {
5898
6019
  if (err != null && typeof err === "object" && "stderr" in err) {
5899
6020
  const stderr = String(err.stderr);
@@ -5935,7 +6056,7 @@ async function findUserSchema(workPath) {
5935
6056
  await import_fs9.default.promises.access(resolved);
5936
6057
  return resolved;
5937
6058
  } catch {
5938
- (0, import_build_utils11.debug)(`PRISMA_SCHEMA_PATH=${envPath} not found at ${resolved}`);
6059
+ (0, import_build_utils12.debug)(`PRISMA_SCHEMA_PATH=${envPath} not found at ${resolved}`);
5939
6060
  return null;
5940
6061
  }
5941
6062
  }
@@ -6039,7 +6160,7 @@ var prismaQuirk = {
6039
6160
  dummySchemaPath,
6040
6161
  buildDummySchema(generatedDir)
6041
6162
  );
6042
- (0, import_build_utils11.debug)(`Running prisma generate (dummy) with cache dir: ${cacheDir}`);
6163
+ (0, import_build_utils12.debug)(`Running prisma generate (dummy) with cache dir: ${cacheDir}`);
6043
6164
  try {
6044
6165
  const dummyResult = await (0, import_execa4.default)(
6045
6166
  pythonPath,
@@ -6051,11 +6172,11 @@ var prismaQuirk = {
6051
6172
  }
6052
6173
  );
6053
6174
  if (dummyResult.stdout)
6054
- (0, import_build_utils11.debug)(`prisma generate (dummy) stdout: ${dummyResult.stdout}`);
6175
+ (0, import_build_utils12.debug)(`prisma generate (dummy) stdout: ${dummyResult.stdout}`);
6055
6176
  if (dummyResult.stderr)
6056
- (0, import_build_utils11.debug)(`prisma generate (dummy) stderr: ${dummyResult.stderr}`);
6177
+ (0, import_build_utils12.debug)(`prisma generate (dummy) stderr: ${dummyResult.stderr}`);
6057
6178
  } catch (err) {
6058
- throw new import_build_utils11.NowBuildError({
6179
+ throw new import_build_utils12.NowBuildError({
6059
6180
  code: "PRISMA_GENERATE_FAILED",
6060
6181
  message: `Prisma engine download failed during \`prisma generate\`. Check that your prisma version is compatible with this Python version.
6061
6182
  ` + execErrorMessage(err)
@@ -6074,22 +6195,22 @@ var prismaQuirk = {
6074
6195
  const destPath = (0, import_path11.join)(cacheDir, runtimeName);
6075
6196
  try {
6076
6197
  await import_fs9.default.promises.access(destPath);
6077
- (0, import_build_utils11.debug)(`Engine binary: ${runtimeName} already exists, skipping`);
6198
+ (0, import_build_utils12.debug)(`Engine binary: ${runtimeName} already exists, skipping`);
6078
6199
  } catch {
6079
- (0, import_build_utils11.debug)(`Engine binary: copying ${entry} -> ${runtimeName}`);
6200
+ (0, import_build_utils12.debug)(`Engine binary: copying ${entry} -> ${runtimeName}`);
6080
6201
  await import_fs9.default.promises.copyFile(srcPath, destPath);
6081
6202
  }
6082
6203
  engineCopied = true;
6083
6204
  }
6084
6205
  } catch (err) {
6085
- throw new import_build_utils11.NowBuildError({
6206
+ throw new import_build_utils12.NowBuildError({
6086
6207
  code: "PRISMA_ENGINE_NOT_FOUND",
6087
6208
  message: `could not read Prisma engine directory "${nodeModulesDir}". This may indicate an incompatible prisma version.
6088
6209
  ` + (err instanceof Error ? err.message : String(err))
6089
6210
  });
6090
6211
  }
6091
6212
  if (!engineCopied) {
6092
- throw new import_build_utils11.NowBuildError({
6213
+ throw new import_build_utils12.NowBuildError({
6093
6214
  code: "PRISMA_ENGINE_NOT_FOUND",
6094
6215
  message: `could not find engine binary matching "${srcBinaryPrefix}*" in "${nodeModulesDir}". This may indicate an incompatible prisma version or an unsupported platform (${process.arch}).`
6095
6216
  });
@@ -6116,14 +6237,14 @@ echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIM
6116
6237
  pythonEnv
6117
6238
  );
6118
6239
  if (clientAlreadyGenerated) {
6119
- (0, import_build_utils11.debug)(
6240
+ (0, import_build_utils12.debug)(
6120
6241
  "Prisma quirk: client already generated, skipping user schema generate"
6121
6242
  );
6122
6243
  shouldGenerate = false;
6123
6244
  }
6124
6245
  }
6125
6246
  if (shouldGenerate) {
6126
- (0, import_build_utils11.debug)(`Running prisma generate with user schema: ${userSchema}`);
6247
+ (0, import_build_utils12.debug)(`Running prisma generate with user schema: ${userSchema}`);
6127
6248
  try {
6128
6249
  const userResult = await (0, import_execa4.default)(
6129
6250
  pythonPath,
@@ -6135,11 +6256,11 @@ echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIM
6135
6256
  }
6136
6257
  );
6137
6258
  if (userResult.stdout)
6138
- (0, import_build_utils11.debug)(`prisma generate stdout: ${userResult.stdout}`);
6259
+ (0, import_build_utils12.debug)(`prisma generate stdout: ${userResult.stdout}`);
6139
6260
  if (userResult.stderr)
6140
- (0, import_build_utils11.debug)(`prisma generate stderr: ${userResult.stderr}`);
6261
+ (0, import_build_utils12.debug)(`prisma generate stderr: ${userResult.stderr}`);
6141
6262
  } catch (err) {
6142
- throw new import_build_utils11.NowBuildError({
6263
+ throw new import_build_utils12.NowBuildError({
6143
6264
  code: "PRISMA_GENERATE_FAILED",
6144
6265
  message: `\`prisma generate\` failed for schema "${userSchema}".
6145
6266
  ` + execErrorMessage(err)
@@ -6153,9 +6274,9 @@ echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIM
6153
6274
  (0, import_path11.join)(sitePackages, "prisma"),
6154
6275
  sitePackages
6155
6276
  );
6156
- const count = await (0, import_python_analysis6.extendDistRecord)(sitePackages, "prisma", allFiles);
6277
+ const count = await (0, import_python_analysis7.extendDistRecord)(sitePackages, "prisma", allFiles);
6157
6278
  if (count > 0) {
6158
- (0, import_build_utils11.debug)(`Appended ${count} entries to prisma RECORD`);
6279
+ (0, import_build_utils12.debug)(`Appended ${count} entries to prisma RECORD`);
6159
6280
  }
6160
6281
  } catch (err) {
6161
6282
  console.warn(
@@ -6178,7 +6299,7 @@ var quirks = [litellmQuirk, prismaQuirk, matplotlibQuirk];
6178
6299
  function toposortQuirks(activated) {
6179
6300
  const nameToQuirk = /* @__PURE__ */ new Map();
6180
6301
  for (const q of activated) {
6181
- nameToQuirk.set((0, import_python_analysis7.normalizePackageName)(q.dependency), q);
6302
+ nameToQuirk.set((0, import_python_analysis8.normalizePackageName)(q.dependency), q);
6182
6303
  }
6183
6304
  const adj = /* @__PURE__ */ new Map();
6184
6305
  const inDegree = /* @__PURE__ */ new Map();
@@ -6189,7 +6310,7 @@ function toposortQuirks(activated) {
6189
6310
  for (const q of activated) {
6190
6311
  if (q.runsBefore) {
6191
6312
  for (const dep of q.runsBefore) {
6192
- const target = nameToQuirk.get((0, import_python_analysis7.normalizePackageName)(dep));
6313
+ const target = nameToQuirk.get((0, import_python_analysis8.normalizePackageName)(dep));
6193
6314
  if (target) {
6194
6315
  adj.get(q).add(target);
6195
6316
  inDegree.set(target, inDegree.get(target) + 1);
@@ -6198,7 +6319,7 @@ function toposortQuirks(activated) {
6198
6319
  }
6199
6320
  if (q.runsAfter) {
6200
6321
  for (const dep of q.runsAfter) {
6201
- const source = nameToQuirk.get((0, import_python_analysis7.normalizePackageName)(dep));
6322
+ const source = nameToQuirk.get((0, import_python_analysis8.normalizePackageName)(dep));
6202
6323
  if (source) {
6203
6324
  adj.get(source).add(q);
6204
6325
  inDegree.set(q, inDegree.get(q) + 1);
@@ -6239,23 +6360,23 @@ async function runQuirks(ctx) {
6239
6360
  const installedNames = /* @__PURE__ */ new Set();
6240
6361
  const sitePackageDirs = await getVenvSitePackagesDirs(ctx.venvPath);
6241
6362
  for (const dir of sitePackageDirs) {
6242
- const distributions = await (0, import_python_analysis7.scanDistributions)(dir);
6363
+ const distributions = await (0, import_python_analysis8.scanDistributions)(dir);
6243
6364
  for (const name of distributions.keys()) {
6244
- installedNames.add((0, import_python_analysis7.normalizePackageName)(name));
6365
+ installedNames.add((0, import_python_analysis8.normalizePackageName)(name));
6245
6366
  }
6246
6367
  }
6247
6368
  const activated = quirks.filter((quirk) => {
6248
6369
  const installed = installedNames.has(
6249
- (0, import_python_analysis7.normalizePackageName)(quirk.dependency)
6370
+ (0, import_python_analysis8.normalizePackageName)(quirk.dependency)
6250
6371
  );
6251
6372
  if (!installed) {
6252
- (0, import_build_utils12.debug)(`Quirk "${quirk.dependency}": not installed, skipping`);
6373
+ (0, import_build_utils13.debug)(`Quirk "${quirk.dependency}": not installed, skipping`);
6253
6374
  }
6254
6375
  return installed;
6255
6376
  });
6256
6377
  const sorted = toposortQuirks(activated);
6257
6378
  for (const quirk of sorted) {
6258
- (0, import_build_utils12.debug)(`Quirk "${quirk.dependency}": detected, running fix-up`);
6379
+ (0, import_build_utils13.debug)(`Quirk "${quirk.dependency}": detected, running fix-up`);
6259
6380
  const result = await quirk.run(ctx);
6260
6381
  if (result.env) {
6261
6382
  Object.assign(mergedEnv, result.env);
@@ -6279,31 +6400,30 @@ async function runQuirks(ctx) {
6279
6400
  var import_fs10 = __toESM(require("fs"));
6280
6401
  var import_path12 = require("path");
6281
6402
  var import_execa5 = __toESM(require_execa());
6282
- var import_build_utils13 = require("@vercel/build-utils");
6403
+ var import_build_utils14 = require("@vercel/build-utils");
6283
6404
  var scriptPath = (0, import_path12.join)(__dirname, "..", "templates", "vc_django_settings.py");
6284
6405
  var script = import_fs10.default.readFileSync(scriptPath, "utf-8");
6285
6406
  async function getDjangoSettings(projectDir, env) {
6286
- try {
6287
- const { stdout } = await (0, import_execa5.default)("python", ["-c", script], {
6288
- env,
6289
- cwd: projectDir
6290
- });
6291
- const parsed = JSON.parse(stdout);
6292
- if (!parsed)
6293
- return null;
6294
- return {
6295
- settingsModule: parsed.settings_module,
6296
- djangoSettings: parsed.django_settings
6297
- };
6298
- } catch (err) {
6299
- (0, import_build_utils13.debug)(`Django hook: failed to discover settings from manage.py: ${err}`);
6300
- return null;
6407
+ const { stdout } = await (0, import_execa5.default)("python", ["-c", script], {
6408
+ env,
6409
+ cwd: projectDir
6410
+ });
6411
+ const parsed = JSON.parse(stdout);
6412
+ if (!parsed) {
6413
+ throw new Error("manage.py did not return any settings");
6301
6414
  }
6415
+ return {
6416
+ settingsModule: parsed.settings_module,
6417
+ djangoSettings: parsed.django_settings,
6418
+ djangoVersion: parsed.django_version ?? null
6419
+ };
6302
6420
  }
6303
- async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir, settingsModule, djangoSettings) {
6421
+ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir, settingsModule, djangoSettings, djangoVersion) {
6304
6422
  const pythonPath = getVenvPythonBin(venvPath);
6305
6423
  const storages = djangoSettings["STORAGES"];
6306
- const storageBackend = storages?.staticfiles?.BACKEND ?? djangoSettings["STATICFILES_STORAGE"] ?? "django.contrib.staticfiles.storage.StaticFilesStorage";
6424
+ const useLegacySetting = !djangoVersion || djangoVersion[0] < 5 || djangoVersion[0] === 5 && djangoVersion[1] < 1;
6425
+ const legacyBackend = useLegacySetting ? djangoSettings["STATICFILES_STORAGE"] : void 0;
6426
+ const storageBackend = storages?.staticfiles?.BACKEND ?? legacyBackend ?? "django.contrib.staticfiles.storage.StaticFilesStorage";
6307
6427
  const staticUrl = djangoSettings["STATIC_URL"] ?? "/static/";
6308
6428
  const staticRoot = djangoSettings["STATIC_ROOT"] != null ? String(djangoSettings["STATIC_ROOT"]) : null;
6309
6429
  const whitenoiseUseFinders = djangoSettings["WHITENOISE_USE_FINDERS"] === true;
@@ -6325,6 +6445,7 @@ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir,
6325
6445
  return {
6326
6446
  staticSourceDirs,
6327
6447
  staticRoot: staticRoot ? (0, import_path12.resolve)(workPath, staticRoot) : null,
6448
+ cdnOutputDir: null,
6328
6449
  manifestRelPath: null
6329
6450
  };
6330
6451
  }
@@ -6371,19 +6492,20 @@ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir,
6371
6492
  await import_fs10.default.promises.mkdir(resolvedStaticRoot, { recursive: true });
6372
6493
  await import_fs10.default.promises.copyFile(manifestSrc, manifestDest);
6373
6494
  manifestRelPath = (0, import_path12.relative)(workPath, manifestDest);
6374
- (0, import_build_utils13.debug)(`Copied staticfiles.json to ${manifestDest} for Lambda bundle`);
6495
+ (0, import_build_utils14.debug)(`Copied staticfiles.json to ${manifestDest} for Lambda bundle`);
6375
6496
  }
6376
6497
  return {
6377
6498
  staticSourceDirs,
6378
6499
  staticRoot: staticRoot ? (0, import_path12.resolve)(workPath, staticRoot) : null,
6500
+ cdnOutputDir: outputStaticDir,
6379
6501
  manifestRelPath
6380
6502
  };
6381
6503
  }
6382
6504
 
6383
6505
  // src/index.ts
6384
- var import_python_analysis8 = require("@vercel/python-analysis");
6506
+ var import_python_analysis9 = require("@vercel/python-analysis");
6385
6507
  var writeFile = import_fs11.default.promises.writeFile;
6386
- var version = 3;
6508
+ var version = -1;
6387
6509
  async function runFrameworkHook(framework, ctx) {
6388
6510
  const hook = framework ? frameworkHooks[framework] : void 0;
6389
6511
  return hook?.(ctx);
@@ -6397,36 +6519,52 @@ var frameworkHooks = {
6397
6519
  detected
6398
6520
  }) => {
6399
6521
  if (detected?.baseDir === void 0) {
6400
- (0, import_build_utils14.debug)("Django hook: no manage.py detected, skipping");
6522
+ (0, import_build_utils15.debug)("Django hook: no manage.py detected, skipping");
6401
6523
  return;
6402
6524
  }
6403
- const settingsResult = await getDjangoSettings(projectDir, pythonEnv);
6404
- (0, import_build_utils14.debug)(`Django settings: ${JSON.stringify(settingsResult)}`);
6405
- if (!settingsResult)
6406
- return;
6407
- const { djangoSettings, settingsModule } = settingsResult;
6408
- let entrypoint;
6409
- let variableName;
6525
+ let settingsResult;
6526
+ try {
6527
+ settingsResult = await getDjangoSettings(projectDir, pythonEnv);
6528
+ } catch (err) {
6529
+ let detail;
6530
+ if (err?.code === "ENOENT") {
6531
+ detail = `command not found: python
6532
+ Hint: activate a venv or run with \`uv run vercel dev\``;
6533
+ } else {
6534
+ detail = err?.stderr || err?.message || String(err);
6535
+ }
6536
+ throw new import_build_utils15.NowBuildError({
6537
+ code: "DJANGO_SETTINGS_FAILED",
6538
+ message: `Failed to read Django application settings from ${projectDir}/manage.py:
6539
+ ${detail}`
6540
+ });
6541
+ }
6542
+ (0, import_build_utils15.debug)(`Django settings: ${JSON.stringify(settingsResult)}`);
6543
+ const { djangoSettings, settingsModule, djangoVersion } = settingsResult;
6544
+ if (djangoVersion) {
6545
+ console.log(`Django ${djangoVersion.join(".")} detected`);
6546
+ }
6547
+ let resolvedEntrypoint;
6410
6548
  const baseDir = detected?.baseDir ?? "";
6411
6549
  const asgiApp = djangoSettings["ASGI_APPLICATION"];
6412
6550
  if (typeof asgiApp === "string") {
6413
6551
  const parts = asgiApp.split(".");
6414
- variableName = parts.at(-1);
6552
+ const variableName = parts.at(-1);
6415
6553
  const rel = `${parts.slice(0, -1).join("/")}.py`;
6416
- entrypoint = baseDir ? `${baseDir}/${rel}` : rel;
6417
- (0, import_build_utils14.debug)(
6418
- `Django hook: ASGI entrypoint: ${entrypoint} (variable: ${variableName})`
6419
- );
6554
+ const ep = baseDir ? `${baseDir}/${rel}` : rel;
6555
+ (0, import_build_utils15.debug)(`Django hook: ASGI entrypoint: ${ep} (variable: ${variableName})`);
6556
+ resolvedEntrypoint = { entrypoint: ep, variableName };
6420
6557
  } else {
6421
6558
  const wsgiApp = djangoSettings["WSGI_APPLICATION"];
6422
6559
  if (typeof wsgiApp === "string") {
6423
6560
  const parts = wsgiApp.split(".");
6424
- variableName = parts.at(-1);
6561
+ const variableName = parts.at(-1);
6425
6562
  const rel = `${parts.slice(0, -1).join("/")}.py`;
6426
- entrypoint = baseDir ? `${baseDir}/${rel}` : rel;
6427
- (0, import_build_utils14.debug)(
6428
- `Django hook: WSGI entrypoint: ${entrypoint} (variable: ${variableName})`
6563
+ const ep = baseDir ? `${baseDir}/${rel}` : rel;
6564
+ (0, import_build_utils15.debug)(
6565
+ `Django hook: WSGI entrypoint: ${ep} (variable: ${variableName})`
6429
6566
  );
6567
+ resolvedEntrypoint = { entrypoint: ep, variableName };
6430
6568
  }
6431
6569
  }
6432
6570
  let djangoStatic = null;
@@ -6438,10 +6576,11 @@ var frameworkHooks = {
6438
6576
  pythonEnv,
6439
6577
  outputStaticDir,
6440
6578
  settingsModule,
6441
- djangoSettings
6579
+ djangoSettings,
6580
+ djangoVersion
6442
6581
  );
6443
6582
  }
6444
- return { entrypoint, variableName, djangoStatic };
6583
+ return { entrypoint: resolvedEntrypoint, djangoStatic };
6445
6584
  }
6446
6585
  };
6447
6586
  async function downloadFilesInWorkPath({
@@ -6450,13 +6589,14 @@ async function downloadFilesInWorkPath({
6450
6589
  files,
6451
6590
  meta = {}
6452
6591
  }) {
6453
- (0, import_build_utils14.debug)("Downloading user files...");
6454
- let downloadedFiles = await (0, import_build_utils14.download)(files, workPath, meta);
6455
- if (meta.isDev) {
6592
+ (0, import_build_utils15.debug)("Downloading user files...");
6593
+ let downloadedFiles = await (0, import_build_utils15.download)(files, workPath, meta);
6594
+ if (meta.isDev && entrypoint) {
6456
6595
  const { devCacheDir = (0, import_path13.join)(workPath, ".now", "cache") } = meta;
6457
- const destCache = (0, import_path13.join)(devCacheDir, (0, import_path13.basename)(entrypoint, ".py"));
6458
- await (0, import_build_utils14.download)(downloadedFiles, destCache);
6459
- downloadedFiles = await (0, import_build_utils14.glob)("**", destCache);
6596
+ const cacheKey = (0, import_path13.basename)(entrypoint).replace(/\./g, "_");
6597
+ const destCache = (0, import_path13.join)(devCacheDir, cacheKey);
6598
+ await (0, import_build_utils15.download)(downloadedFiles, destCache);
6599
+ downloadedFiles = await (0, import_build_utils15.glob)("**", destCache);
6460
6600
  workPath = destCache;
6461
6601
  }
6462
6602
  return workPath;
@@ -6465,19 +6605,20 @@ var build = async ({
6465
6605
  workPath,
6466
6606
  repoRootPath,
6467
6607
  files: originalFiles,
6468
- entrypoint,
6608
+ entrypoint: rawEntrypoint,
6469
6609
  meta = {},
6470
6610
  config,
6471
6611
  span: parentSpan,
6472
6612
  service
6473
6613
  }) => {
6474
- const builderSpan = parentSpan ?? new import_build_utils14.Span({ name: "vc.builder" });
6614
+ let entrypoint = rawEntrypoint === "<detect>" ? void 0 : rawEntrypoint;
6615
+ const builderSpan = parentSpan ?? new import_build_utils15.Span({ name: "vc.builder" });
6475
6616
  const framework = config?.framework;
6476
6617
  const shouldInstallVercelWorkers = config?.hasWorkerServices === true;
6477
6618
  let spawnEnv;
6478
6619
  let projectInstallCommand;
6479
6620
  let hasCustomCommand = false;
6480
- (0, import_build_utils14.debug)(`workPath: ${workPath}`);
6621
+ (0, import_build_utils15.debug)(`workPath: ${workPath}`);
6481
6622
  workPath = await downloadFilesInWorkPath({
6482
6623
  workPath,
6483
6624
  files: originalFiles,
@@ -6493,35 +6634,17 @@ var build = async ({
6493
6634
  console.log('Failed to create "setup.cfg" file');
6494
6635
  throw err;
6495
6636
  }
6496
- let fsFiles = await (0, import_build_utils14.glob)("**", workPath);
6497
6637
  let detected;
6498
- let entrypointNotFound;
6499
- if ((0, import_build_utils14.isPythonFramework)(framework) && // XXX: we might want to detect anyway for django!
6500
- (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
6501
- detected = await detectPythonEntrypoint(
6502
- config.framework,
6503
- workPath,
6504
- entrypoint
6505
- ) ?? void 0;
6506
- if (detected?.entrypoint) {
6507
- (0, import_build_utils14.debug)(
6508
- `Resolved Python entrypoint to "${detected.entrypoint}" (configured "${entrypoint}" not found).`
6509
- );
6510
- entrypoint = detected.entrypoint;
6511
- } else {
6512
- const searchedList = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
6513
- entrypointNotFound = new import_build_utils14.NowBuildError({
6514
- code: `${framework.toUpperCase()}_ENTRYPOINT_NOT_FOUND`,
6515
- message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searchedList}.`,
6516
- link: `https://vercel.com/docs/frameworks/backend/${framework}#exporting-the-${framework}-application`,
6517
- action: "Learn More"
6518
- });
6519
- }
6520
- }
6521
- if (entrypointNotFound && detected?.baseDir === void 0) {
6522
- throw entrypointNotFound;
6638
+ detected = await detectPythonEntrypoint(
6639
+ config.framework,
6640
+ workPath,
6641
+ entrypoint,
6642
+ service
6643
+ ) ?? void 0;
6644
+ if (detected?.error && detected?.baseDir === void 0) {
6645
+ throw detected?.error;
6523
6646
  }
6524
- const entryDirectory = detected?.baseDir ?? (0, import_path13.dirname)(entrypoint);
6647
+ const entryDirectory = detected?.baseDir ?? (entrypoint ? (0, import_path13.dirname)(entrypoint) : ".");
6525
6648
  const entrypointAbsDir = (0, import_path13.join)(workPath, entryDirectory);
6526
6649
  const rootDir = repoRootPath ?? workPath;
6527
6650
  const pythonPackage = await builderSpan.child("vc.builder.python.discover").trace(
@@ -6552,7 +6675,6 @@ var build = async ({
6552
6675
  `
6553
6676
  );
6554
6677
  }
6555
- fsFiles = await (0, import_build_utils14.glob)("**", workPath);
6556
6678
  const venvPath = service?.name ? (0, import_path13.join)(workPath, ".vercel", "python", "services", service.name, ".venv") : (0, import_path13.join)(workPath, ".vercel", "python", ".venv");
6557
6679
  await builderSpan.child("vc.builder.python.venv").trace(async () => {
6558
6680
  await ensureVenv({
@@ -6560,14 +6682,14 @@ var build = async ({
6560
6682
  venvPath
6561
6683
  });
6562
6684
  });
6563
- if ((0, import_build_utils14.isPythonFramework)(framework)) {
6685
+ if ((0, import_build_utils15.isPythonFramework)(framework)) {
6564
6686
  const {
6565
6687
  cliType,
6566
6688
  lockfileVersion,
6567
6689
  packageJsonPackageManager,
6568
6690
  turboSupportsCorepackHome
6569
- } = await (0, import_build_utils14.scanParentDirs)(workPath, true);
6570
- spawnEnv = (0, import_build_utils14.getEnvForPackageManager)({
6691
+ } = await (0, import_build_utils15.scanParentDirs)(workPath, true);
6692
+ spawnEnv = (0, import_build_utils15.getEnvForPackageManager)({
6571
6693
  cliType,
6572
6694
  lockfileVersion,
6573
6695
  packageJsonPackageManager,
@@ -6592,8 +6714,11 @@ var build = async ({
6592
6714
  let uv;
6593
6715
  try {
6594
6716
  const uvPath = await getUvBinaryOrInstall(pythonVersion.pythonPath);
6595
- console.log(`Using uv at "${uvPath}"`);
6596
6717
  uv = new UvRunner(uvPath);
6718
+ const uvVersionOutput = (0, import_child_process3.execSync)(`${uvPath} --version`, {
6719
+ encoding: "utf8"
6720
+ }).trim();
6721
+ console.log(`Using ${uvVersionOutput}`);
6597
6722
  } catch (err) {
6598
6723
  console.log("Failed to install or locate uv");
6599
6724
  throw new Error(
@@ -6603,14 +6728,14 @@ var build = async ({
6603
6728
  let uvLockPath = null;
6604
6729
  let uvProjectDir = null;
6605
6730
  let projectName;
6606
- await builderSpan.child(import_build_utils14.BUILDER_INSTALLER_STEP, {
6731
+ await builderSpan.child(import_build_utils15.BUILDER_INSTALLER_STEP, {
6607
6732
  installCommand: projectInstallCommand || void 0
6608
6733
  }).trace(async () => {
6609
6734
  if (projectInstallCommand) {
6610
6735
  console.log(
6611
6736
  `Running "install" command: \`${projectInstallCommand}\`...`
6612
6737
  );
6613
- await (0, import_build_utils14.execCommand)(projectInstallCommand, {
6738
+ await (0, import_build_utils15.execCommand)(projectInstallCommand, {
6614
6739
  env: pythonEnv,
6615
6740
  cwd: workPath
6616
6741
  });
@@ -6650,15 +6775,15 @@ var build = async ({
6650
6775
  });
6651
6776
  }
6652
6777
  });
6653
- if ((0, import_build_utils14.isPythonFramework)(framework)) {
6778
+ if ((0, import_build_utils15.isPythonFramework)(framework)) {
6654
6779
  const projectBuildCommand = config?.projectSettings?.buildCommand ?? // fallback if provided directly on config (some callers set this)
6655
6780
  config?.buildCommand;
6656
- await builderSpan.child(import_build_utils14.BUILDER_COMPILE_STEP, {
6781
+ await builderSpan.child(import_build_utils15.BUILDER_COMPILE_STEP, {
6657
6782
  buildCommand: projectBuildCommand || void 0
6658
6783
  }).trace(async () => {
6659
6784
  if (projectBuildCommand) {
6660
6785
  console.log(`Running "${projectBuildCommand}"`);
6661
- await (0, import_build_utils14.execCommand)(projectBuildCommand, {
6786
+ await (0, import_build_utils15.execCommand)(projectBuildCommand, {
6662
6787
  env: pythonEnv,
6663
6788
  cwd: workPath
6664
6789
  });
@@ -6679,16 +6804,20 @@ var build = async ({
6679
6804
  entrypoint,
6680
6805
  detected
6681
6806
  });
6682
- if (entrypointNotFound && hookResult?.entrypoint) {
6683
- entrypoint = hookResult.entrypoint;
6684
- entrypointNotFound = void 0;
6685
- }
6686
- if (entrypointNotFound) {
6687
- throw entrypointNotFound;
6807
+ const resolved = hookResult?.entrypoint ?? detected?.entrypoint;
6808
+ if (!resolved && detected?.error) {
6809
+ throw detected?.error;
6810
+ }
6811
+ entrypoint = resolved?.entrypoint;
6812
+ if (!entrypoint) {
6813
+ throw new import_build_utils15.NowBuildError({
6814
+ code: "PYTHON_ENTRYPOINT_NOT_FOUND",
6815
+ message: "No Python entrypoint could be detected. Please specify an entrypoint file."
6816
+ });
6688
6817
  }
6689
6818
  const djangoStatic = hookResult?.djangoStatic ?? null;
6690
6819
  const runtimeDep = baseEnv.VERCEL_RUNTIME_PYTHON || `vercel-runtime==${VERCEL_RUNTIME_VERSION}`;
6691
- (0, import_build_utils14.debug)(`Installing ${runtimeDep}`);
6820
+ (0, import_build_utils15.debug)(`Installing ${runtimeDep}`);
6692
6821
  await uv.pip({
6693
6822
  venvPath,
6694
6823
  projectDir: (0, import_path13.join)(workPath, entryDirectory),
@@ -6696,7 +6825,7 @@ var build = async ({
6696
6825
  });
6697
6826
  if (shouldInstallVercelWorkers) {
6698
6827
  const workersDep = baseEnv.VERCEL_WORKERS_PYTHON || `vercel-workers==${VERCEL_WORKERS_VERSION}`;
6699
- (0, import_build_utils14.debug)(`Installing ${workersDep}`);
6828
+ (0, import_build_utils15.debug)(`Installing ${workersDep}`);
6700
6829
  await uv.pip({
6701
6830
  venvPath,
6702
6831
  projectDir: (0, import_path13.join)(workPath, entryDirectory),
@@ -6707,15 +6836,15 @@ var build = async ({
6707
6836
  if (quirksResult.buildEnv) {
6708
6837
  Object.assign(pythonEnv, quirksResult.buildEnv);
6709
6838
  }
6710
- (0, import_build_utils14.debug)("Entrypoint is", entrypoint);
6839
+ (0, import_build_utils15.debug)("Entrypoint is", entrypoint);
6711
6840
  const moduleName = entrypoint.replace(/\//g, ".").replace(/\.py$/i, "");
6712
6841
  const handlerFunction = typeof config?.handlerFunction === "string" ? config.handlerFunction : void 0;
6713
6842
  if (handlerFunction) {
6714
6843
  const entrypointPath = (0, import_path13.join)(workPath, entrypoint);
6715
6844
  const source = await import_fs11.default.promises.readFile(entrypointPath, "utf-8");
6716
- const found = await (0, import_python_analysis8.containsTopLevelCallable)(source, handlerFunction);
6845
+ const found = await (0, import_python_analysis9.containsTopLevelCallable)(source, handlerFunction);
6717
6846
  if (!found) {
6718
- throw new import_build_utils14.NowBuildError({
6847
+ throw new import_build_utils15.NowBuildError({
6719
6848
  code: "PYTHON_HANDLER_NOT_FOUND",
6720
6849
  message: `Handler function "${handlerFunction}" not found in ${entrypoint}. Ensure it is defined at the module's top level.`
6721
6850
  });
@@ -6724,10 +6853,10 @@ var build = async ({
6724
6853
  const vendorDir = resolveVendorDir();
6725
6854
  const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
6726
6855
  const entrypointWithSuffix = `${entrypoint}${suffix}`;
6727
- (0, import_build_utils14.debug)("Entrypoint with suffix is", entrypointWithSuffix);
6856
+ (0, import_build_utils15.debug)("Entrypoint with suffix is", entrypointWithSuffix);
6728
6857
  const handlerFuncEnvLine = handlerFunction ? `
6729
6858
  "__VC_HANDLER_FUNC_NAME": "${handlerFunction}",` : "";
6730
- const variableName = hookResult?.variableName ?? detected?.variableName ?? "";
6859
+ const variableName = resolved?.variableName ?? "";
6731
6860
  const runtimeTrampoline = `
6732
6861
  import importlib
6733
6862
  import os
@@ -6785,18 +6914,6 @@ from vercel_runtime.vc_init import vc_handler
6785
6914
  "**/yarn.lock",
6786
6915
  "**/package-lock.json"
6787
6916
  ];
6788
- if (djangoStatic) {
6789
- const dirsToExclude = [
6790
- ...djangoStatic.staticSourceDirs,
6791
- ...djangoStatic.staticRoot ? [djangoStatic.staticRoot] : []
6792
- ];
6793
- for (const absDir of dirsToExclude) {
6794
- const rel = (0, import_path13.relative)(workPath, absDir);
6795
- if (!rel.startsWith("..")) {
6796
- predefinedExcludes.push(`${rel}/**`);
6797
- }
6798
- }
6799
- }
6800
6917
  const lambdaEnv = {};
6801
6918
  lambdaEnv.PYTHONPATH = vendorDir;
6802
6919
  Object.assign(lambdaEnv, quirksResult.env);
@@ -6807,9 +6924,9 @@ from vercel_runtime.vc_init import vc_handler
6807
6924
  cwd: workPath,
6808
6925
  ignore: config && typeof config.excludeFiles === "string" ? [...predefinedExcludes, config.excludeFiles] : predefinedExcludes
6809
6926
  };
6810
- const files = await (0, import_build_utils14.glob)("**", globOptions);
6927
+ const files = await (0, import_build_utils15.glob)("**", globOptions);
6811
6928
  if (djangoStatic?.manifestRelPath) {
6812
- files[djangoStatic.manifestRelPath] = new import_build_utils14.FileFsRef({
6929
+ files[djangoStatic.manifestRelPath] = new import_build_utils15.FileFsRef({
6813
6930
  fsPath: (0, import_path13.join)(workPath, djangoStatic.manifestRelPath)
6814
6931
  });
6815
6932
  }
@@ -6846,12 +6963,12 @@ from vercel_runtime.vc_init import vc_handler
6846
6963
  }
6847
6964
  });
6848
6965
  const handlerPyFilename = "vc__handler__python";
6849
- files[`${handlerPyFilename}.py`] = new import_build_utils14.FileBlob({ data: runtimeTrampoline });
6966
+ files[`${handlerPyFilename}.py`] = new import_build_utils15.FileBlob({ data: runtimeTrampoline });
6850
6967
  if (config.framework === "fasthtml") {
6851
6968
  const { SESSKEY = "" } = process.env;
6852
- files[".sesskey"] = new import_build_utils14.FileBlob({ data: `"${SESSKEY}"` });
6969
+ files[".sesskey"] = new import_build_utils15.FileBlob({ data: `"${SESSKEY}"` });
6853
6970
  }
6854
- const output = new import_build_utils14.Lambda({
6971
+ const output = new import_build_utils15.Lambda({
6855
6972
  files,
6856
6973
  handler: `${handlerPyFilename}.vc_handler`,
6857
6974
  runtime: pythonVersion.runtime,
@@ -6867,16 +6984,33 @@ from vercel_runtime.vc_init import vc_handler
6867
6984
  uvLockPath
6868
6985
  });
6869
6986
  } catch (err) {
6870
- (0, import_build_utils14.debug)(
6987
+ (0, import_build_utils15.debug)(
6871
6988
  `Failed to write project manifest: ${err instanceof Error ? err.message : String(err)}`
6872
6989
  );
6873
6990
  }
6874
6991
  }
6875
- return { output };
6992
+ if (!(0, import_build_utils15.isPythonFramework)(framework)) {
6993
+ return { resultVersion: 3, result: { output } };
6994
+ }
6995
+ const lambdaPath = service?.name ? `_svc/${service.name}/index` : "index";
6996
+ const staticFiles = djangoStatic?.cdnOutputDir ? await (0, import_build_utils15.glob)("**", { cwd: djangoStatic.cdnOutputDir }) : {};
6997
+ return {
6998
+ resultVersion: 2,
6999
+ result: {
7000
+ output: {
7001
+ [lambdaPath]: output,
7002
+ ...staticFiles
7003
+ },
7004
+ routes: [
7005
+ { handle: "filesystem" },
7006
+ { src: "/(.*)", dest: `/${lambdaPath}` }
7007
+ ]
7008
+ }
7009
+ };
6876
7010
  };
6877
7011
  var shouldServe = (opts) => {
6878
7012
  const framework = opts.config.framework;
6879
- if ((0, import_build_utils14.isPythonFramework)(framework)) {
7013
+ if ((0, import_build_utils15.isPythonFramework)(framework)) {
6880
7014
  const requestPath = opts.requestPath.replace(/\/$/, "");
6881
7015
  if (requestPath.startsWith("api") && opts.hasMatched) {
6882
7016
  return false;