@vercel/python 14.2.1 → 16.0.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 +802 -528
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -7078,6 +7078,7 @@ var UvRunner = class {
|
|
|
7078
7078
|
frozen,
|
|
7079
7079
|
noBuild,
|
|
7080
7080
|
noInstallProject,
|
|
7081
|
+
onlyGroup,
|
|
7081
7082
|
pythonPlatform
|
|
7082
7083
|
} = options;
|
|
7083
7084
|
const args = ["sync", "--active", "--no-dev", "--link-mode", "hardlink"];
|
|
@@ -7092,6 +7093,9 @@ var UvRunner = class {
|
|
|
7092
7093
|
if (noInstallProject) {
|
|
7093
7094
|
args.push("--no-install-project");
|
|
7094
7095
|
}
|
|
7096
|
+
if (onlyGroup) {
|
|
7097
|
+
args.push("--only-group", onlyGroup);
|
|
7098
|
+
}
|
|
7095
7099
|
if (pythonPlatform) {
|
|
7096
7100
|
args.push("--python-platform", pythonPlatform);
|
|
7097
7101
|
}
|
|
@@ -12935,6 +12939,7 @@ function getImportClosureOptions({
|
|
|
12935
12939
|
}
|
|
12936
12940
|
|
|
12937
12941
|
// src/index.ts
|
|
12942
|
+
var import_build_utils25 = require("@vercel/build-utils");
|
|
12938
12943
|
var writeFile = import_fs20.default.promises.writeFile;
|
|
12939
12944
|
var PYTHON_ENTRYPOINT_DOCS_URL2 = "https://vercel.com/docs/functions/runtimes/python#python-entrypoints";
|
|
12940
12945
|
var version = -1;
|
|
@@ -13330,95 +13335,17 @@ async function installInjectedPackage({
|
|
|
13330
13335
|
]
|
|
13331
13336
|
});
|
|
13332
13337
|
}
|
|
13333
|
-
|
|
13338
|
+
async function setupPythonToolchain({
|
|
13339
|
+
builderSpan,
|
|
13334
13340
|
workPath,
|
|
13335
|
-
|
|
13336
|
-
|
|
13337
|
-
|
|
13338
|
-
meta
|
|
13339
|
-
|
|
13340
|
-
span: parentSpan,
|
|
13341
|
-
service,
|
|
13342
|
-
registerPreDeploy
|
|
13343
|
-
}) => {
|
|
13344
|
-
let entrypoint = rawEntrypoint === "<detect>" ? void 0 : rawEntrypoint;
|
|
13345
|
-
const isPyprojectEntrypoint = entrypoint !== void 0 && (0, import_path21.basename)(entrypoint) === "pyproject.toml";
|
|
13346
|
-
if (isPyprojectEntrypoint && entrypoint !== "pyproject.toml") {
|
|
13347
|
-
throw new import_build_utils24.NowBuildError({
|
|
13348
|
-
code: "PYTHON_INVALID_PYPROJECT_ENTRYPOINT",
|
|
13349
|
-
message: `A "pyproject.toml" entrypoint must sit at the service root. Set the service "root" to "${(0, import_path21.dirname)(entrypoint)}" and use entrypoint "pyproject.toml".`
|
|
13350
|
-
});
|
|
13351
|
-
}
|
|
13352
|
-
const builderSpan = parentSpan ?? new import_build_utils24.Span({ name: "vc.builder" });
|
|
13353
|
-
const framework = config?.framework;
|
|
13354
|
-
let subscriberDeclarations = [];
|
|
13355
|
-
let subscribers = [];
|
|
13356
|
-
let workflows = [];
|
|
13357
|
-
let legacyWorkersProject = false;
|
|
13358
|
-
let workflowMode = "workers";
|
|
13359
|
-
let spawnEnv;
|
|
13360
|
-
let projectInstallCommand;
|
|
13361
|
-
let hasCustomCommand = false;
|
|
13362
|
-
const target = getTargetPlatform(meta.isDev ?? false);
|
|
13363
|
-
(0, import_build_utils24.debug)(`workPath: ${workPath}`);
|
|
13364
|
-
workPath = await downloadFilesInWorkPath({
|
|
13365
|
-
workPath,
|
|
13366
|
-
files: originalFiles,
|
|
13367
|
-
entrypoint,
|
|
13368
|
-
meta
|
|
13369
|
-
});
|
|
13370
|
-
legacyWorkersProject = await isLegacyWorkersProject(workPath);
|
|
13371
|
-
if (isPyprojectEntrypoint || !service && (0, import_build_utils24.isPythonFramework)(framework)) {
|
|
13372
|
-
subscriberDeclarations = await getPyprojectSubscribers(workPath, {
|
|
13373
|
-
legacySchema: legacyWorkersProject
|
|
13374
|
-
});
|
|
13375
|
-
workflows = await getPyprojectWorkflows(workPath);
|
|
13376
|
-
}
|
|
13377
|
-
try {
|
|
13378
|
-
if (meta.isDev) {
|
|
13379
|
-
const setupCfg = (0, import_path21.join)(workPath, "setup.cfg");
|
|
13380
|
-
await writeFile(setupCfg, "[install]\nprefix=\n");
|
|
13381
|
-
}
|
|
13382
|
-
} catch (err) {
|
|
13383
|
-
console.log('Failed to create "setup.cfg" file');
|
|
13384
|
-
throw err;
|
|
13385
|
-
}
|
|
13386
|
-
let detected;
|
|
13387
|
-
const handlerFunction = typeof config?.handlerFunction === "string" ? config.handlerFunction : void 0;
|
|
13388
|
-
if (isPyprojectEntrypoint) {
|
|
13389
|
-
const declared = await getVercelToolsEntrypoint(workPath, repoRootPath);
|
|
13390
|
-
if (declared) {
|
|
13391
|
-
detected = { entrypoint: declared };
|
|
13392
|
-
} else if (subscriberDeclarations.length === 0 && workflows.length === 0) {
|
|
13393
|
-
throw new import_build_utils24.NowBuildError({
|
|
13394
|
-
code: "PYTHON_PYPROJECT_NOTHING_TO_BUILD",
|
|
13395
|
-
message: 'Entrypoint "pyproject.toml" declares nothing to build. Set "tool.vercel.entrypoint" for a web app and/or declare "[[tool.vercel.subscribers]]" or "[[tool.vercel.workflows]]" entries in pyproject.toml.'
|
|
13396
|
-
});
|
|
13397
|
-
}
|
|
13398
|
-
entrypoint = void 0;
|
|
13399
|
-
} else {
|
|
13400
|
-
detected = await detectPythonEntrypoint(
|
|
13401
|
-
config.framework,
|
|
13402
|
-
workPath,
|
|
13403
|
-
entrypoint ? {
|
|
13404
|
-
filePath: entrypoint,
|
|
13405
|
-
// For schedule-triggered jobs, the WSGI variable is always 'app' (created dynamically).
|
|
13406
|
-
// For other services, handlerFunction is used as the entrypoint variable name.
|
|
13407
|
-
varName: service && (0, import_build_utils24.isScheduleTriggeredService)(service) ? void 0 : handlerFunction
|
|
13408
|
-
} : void 0,
|
|
13409
|
-
service,
|
|
13410
|
-
repoRootPath
|
|
13411
|
-
) ?? void 0;
|
|
13412
|
-
}
|
|
13413
|
-
if (detected?.error && detected?.baseDir === void 0) {
|
|
13414
|
-
throw detected?.error;
|
|
13415
|
-
}
|
|
13416
|
-
const entryDirectory = detected?.baseDir ?? (entrypoint ? (0, import_path21.dirname)(entrypoint) : ".");
|
|
13417
|
-
const entrypointAbsDir = (0, import_path21.join)(workPath, entryDirectory);
|
|
13418
|
-
const rootDir = repoRootPath ?? workPath;
|
|
13341
|
+
entrypointDir,
|
|
13342
|
+
rootDir,
|
|
13343
|
+
venvPath,
|
|
13344
|
+
meta
|
|
13345
|
+
}) {
|
|
13419
13346
|
const pythonPackage = await builderSpan.child("vc.builder.python.discover").trace(
|
|
13420
13347
|
() => discoverPackage({
|
|
13421
|
-
entrypointDir
|
|
13348
|
+
entrypointDir,
|
|
13422
13349
|
rootDir
|
|
13423
13350
|
})
|
|
13424
13351
|
);
|
|
@@ -13455,7 +13382,6 @@ var build = async ({
|
|
|
13455
13382
|
}
|
|
13456
13383
|
const uvVersion = checkUvBinaryVersion(uv.getPath());
|
|
13457
13384
|
console.log(`Using ${uvVersion}`);
|
|
13458
|
-
const venvPath = service?.name ? (0, import_path21.join)(workPath, ".vercel", "python", "services", service.name, ".venv") : (0, import_path21.join)(workPath, ".vercel", "python", ".venv");
|
|
13459
13385
|
const hasCachedVenv = import_fs20.default.existsSync((0, import_path21.join)(venvPath, "pyvenv.cfg"));
|
|
13460
13386
|
const hasCachedUv = import_fs20.default.existsSync(uvCacheDir);
|
|
13461
13387
|
const restoredCache = hasCachedVenv && hasCachedUv ? "both" : hasCachedVenv ? "venv" : hasCachedUv ? "uv" : "none";
|
|
@@ -13472,377 +13398,67 @@ var build = async ({
|
|
|
13472
13398
|
uvCacheDir
|
|
13473
13399
|
});
|
|
13474
13400
|
});
|
|
13475
|
-
|
|
13476
|
-
|
|
13477
|
-
|
|
13478
|
-
|
|
13479
|
-
|
|
13480
|
-
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
13486
|
-
|
|
13487
|
-
|
|
13488
|
-
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
});
|
|
13492
|
-
const installCommand = config?.projectSettings?.installCommand;
|
|
13493
|
-
if (typeof installCommand === "string") {
|
|
13494
|
-
const trimmed = installCommand.trim();
|
|
13495
|
-
if (trimmed) {
|
|
13496
|
-
projectInstallCommand = trimmed;
|
|
13497
|
-
} else {
|
|
13498
|
-
console.log('Skipping "install" command...');
|
|
13499
|
-
}
|
|
13500
|
-
}
|
|
13501
|
-
}
|
|
13502
|
-
const baseEnv = spawnEnv || process.env;
|
|
13503
|
-
const pythonEnv = createVenvEnv(venvPath, baseEnv, uvCacheDir);
|
|
13504
|
-
pythonEnv.VERCEL_PYTHON_VENV_PATH = venvPath;
|
|
13505
|
-
let assumeDepsInstalled = false;
|
|
13506
|
-
let uvLockPath = null;
|
|
13507
|
-
let uvProjectDir = null;
|
|
13508
|
-
let projectName;
|
|
13509
|
-
let usedUvManagedInstall = false;
|
|
13510
|
-
await builderSpan.child(import_build_utils24.BUILDER_INSTALLER_STEP, {
|
|
13511
|
-
installCommand: projectInstallCommand || void 0,
|
|
13512
|
-
runtime: "python",
|
|
13513
|
-
"python.cache.restored": restoredCache
|
|
13514
|
-
}).trace(async () => {
|
|
13515
|
-
if (projectInstallCommand) {
|
|
13516
|
-
await import_fs20.default.promises.rm(venvPath, { recursive: true, force: true });
|
|
13517
|
-
await ensureVenv({
|
|
13518
|
-
pythonVersion,
|
|
13519
|
-
venvPath,
|
|
13520
|
-
uvPath: uv.getPath(),
|
|
13521
|
-
uvCacheDir,
|
|
13522
|
-
quiet: true
|
|
13523
|
-
});
|
|
13524
|
-
console.log(
|
|
13525
|
-
`Running "install" command: \`${projectInstallCommand}\`...`
|
|
13526
|
-
);
|
|
13527
|
-
await (0, import_build_utils24.execCommand)(projectInstallCommand, {
|
|
13528
|
-
env: pythonEnv,
|
|
13529
|
-
cwd: workPath
|
|
13530
|
-
});
|
|
13531
|
-
assumeDepsInstalled = true;
|
|
13532
|
-
hasCustomCommand = true;
|
|
13533
|
-
} else {
|
|
13534
|
-
const hasCustomScript = await runPyprojectScript(
|
|
13535
|
-
workPath,
|
|
13536
|
-
["vercel-install", "now-install", "install"],
|
|
13537
|
-
pythonEnv,
|
|
13538
|
-
/* useUserVirtualEnv */
|
|
13539
|
-
false
|
|
13540
|
-
);
|
|
13541
|
-
if (hasCustomScript) {
|
|
13542
|
-
assumeDepsInstalled = true;
|
|
13543
|
-
hasCustomCommand = true;
|
|
13544
|
-
}
|
|
13545
|
-
}
|
|
13546
|
-
if (!assumeDepsInstalled) {
|
|
13547
|
-
const lockCacheKey = service?.name ? `uv.lock.${service.name}` : "uv.lock";
|
|
13548
|
-
const cachedLockPath = (0, import_path21.join)(uvCacheDir, lockCacheKey);
|
|
13549
|
-
const { projectDir, lockPath, lockFileProvidedByUser } = await ensureUvProject({
|
|
13550
|
-
workPath,
|
|
13551
|
-
rootDir,
|
|
13552
|
-
venvPath,
|
|
13553
|
-
pythonPackage,
|
|
13554
|
-
pythonVersion: pythonVersionString(pythonVersion),
|
|
13555
|
-
uv,
|
|
13556
|
-
requireBinaryWheels: false,
|
|
13557
|
-
cachedLockPath
|
|
13558
|
-
});
|
|
13559
|
-
uvLockPath = lockPath;
|
|
13560
|
-
uvProjectDir = projectDir;
|
|
13561
|
-
projectName = pythonPackage?.manifest?.data?.project?.name;
|
|
13562
|
-
await uv.sync({
|
|
13563
|
-
venvPath,
|
|
13564
|
-
projectDir,
|
|
13565
|
-
frozen: lockFileProvidedByUser,
|
|
13566
|
-
locked: !lockFileProvidedByUser,
|
|
13567
|
-
pythonPlatform: target.uvPlatform
|
|
13568
|
-
});
|
|
13569
|
-
usedUvManagedInstall = true;
|
|
13570
|
-
if (lockPath && import_fs20.default.existsSync(lockPath)) {
|
|
13571
|
-
await import_fs20.default.promises.mkdir(uvCacheDir, { recursive: true });
|
|
13572
|
-
await import_fs20.default.promises.copyFile(lockPath, cachedLockPath);
|
|
13573
|
-
}
|
|
13574
|
-
}
|
|
13575
|
-
});
|
|
13576
|
-
if ((0, import_build_utils24.isPythonFramework)(framework)) {
|
|
13577
|
-
const projectBuildCommand = config?.projectSettings?.buildCommand ?? // fallback if provided directly on config (some callers set this)
|
|
13578
|
-
config?.buildCommand;
|
|
13579
|
-
await builderSpan.child(import_build_utils24.BUILDER_COMPILE_STEP, {
|
|
13580
|
-
buildCommand: projectBuildCommand || void 0
|
|
13581
|
-
}).trace(async () => {
|
|
13582
|
-
if (projectBuildCommand) {
|
|
13583
|
-
console.log(`Running "${projectBuildCommand}"`);
|
|
13584
|
-
await (0, import_build_utils24.execCommand)(projectBuildCommand, {
|
|
13585
|
-
env: pythonEnv,
|
|
13586
|
-
cwd: workPath
|
|
13587
|
-
});
|
|
13588
|
-
} else {
|
|
13589
|
-
await runPyprojectScript(
|
|
13590
|
-
workPath,
|
|
13591
|
-
["vercel-build", "now-build", "build"],
|
|
13592
|
-
pythonEnv
|
|
13593
|
-
);
|
|
13594
|
-
}
|
|
13595
|
-
});
|
|
13596
|
-
}
|
|
13597
|
-
const hookResult = await runFrameworkHook(framework, {
|
|
13598
|
-
pythonEnv,
|
|
13401
|
+
return { pythonPackage, pythonVersion, uv, uvCacheDir, restoredCache };
|
|
13402
|
+
}
|
|
13403
|
+
async function runUvManagedInstall({
|
|
13404
|
+
workPath,
|
|
13405
|
+
rootDir,
|
|
13406
|
+
venvPath,
|
|
13407
|
+
pythonPackage,
|
|
13408
|
+
pythonVersion,
|
|
13409
|
+
uv,
|
|
13410
|
+
uvCacheDir,
|
|
13411
|
+
lockCacheKey,
|
|
13412
|
+
pythonPlatform,
|
|
13413
|
+
extraSyncParams
|
|
13414
|
+
}) {
|
|
13415
|
+
const cachedLockPath = (0, import_path21.join)(uvCacheDir, lockCacheKey);
|
|
13416
|
+
const result = await ensureUvProject({
|
|
13599
13417
|
workPath,
|
|
13418
|
+
rootDir,
|
|
13600
13419
|
venvPath,
|
|
13601
|
-
entrypoint,
|
|
13602
|
-
detected,
|
|
13603
|
-
pyprojectData: pythonPackage.manifest?.data
|
|
13604
|
-
});
|
|
13605
|
-
const resolved = isPyprojectEntrypoint ? detected?.entrypoint : hookResult?.entrypoint ?? detected?.entrypoint;
|
|
13606
|
-
if (!resolved && detected?.error) {
|
|
13607
|
-
throw detected?.error;
|
|
13608
|
-
}
|
|
13609
|
-
entrypoint = resolved?.entrypoint;
|
|
13610
|
-
const isWorkersOnly = !entrypoint && isPyprojectEntrypoint && (subscriberDeclarations.length > 0 || workflows.length > 0);
|
|
13611
|
-
if (!entrypoint && !isWorkersOnly) {
|
|
13612
|
-
throw new import_build_utils24.NowBuildError({
|
|
13613
|
-
code: "PYTHON_ENTRYPOINT_NOT_FOUND",
|
|
13614
|
-
message: "No Python entrypoint could be detected. Please specify an entrypoint file."
|
|
13615
|
-
});
|
|
13616
|
-
}
|
|
13617
|
-
const djangoStatic = hookResult?.djangoStatic ?? null;
|
|
13618
|
-
const fastapiStatic = hookResult?.fastapiStatic ?? null;
|
|
13619
|
-
const importSeeds = hookResult?.importSeeds ?? [];
|
|
13620
|
-
const cdnOutputDir = djangoStatic?.cdnOutputDir ?? fastapiStatic?.cdnOutputDir ?? null;
|
|
13621
|
-
const pipPlatformArgs = target.uvPlatform ? ["--python-platform", target.uvPlatform] : [];
|
|
13622
|
-
await installInjectedPackage({
|
|
13623
|
-
name: "vercel-runtime",
|
|
13624
|
-
requirement: `vercel-runtime==${VERCEL_RUNTIME_VERSION}`,
|
|
13625
|
-
envOverride: baseEnv.VERCEL_RUNTIME_PYTHON,
|
|
13626
|
-
allowLocalSource: true,
|
|
13627
|
-
uv,
|
|
13628
|
-
venvPath,
|
|
13629
|
-
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
13630
|
-
pipPlatformArgs
|
|
13631
|
-
});
|
|
13632
|
-
const queueAdapterBootstrap = await getQueueAdapterBootstrap({
|
|
13633
13420
|
pythonPackage,
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
|
|
13421
|
+
pythonVersion: pythonVersionString(pythonVersion),
|
|
13422
|
+
uv,
|
|
13423
|
+
requireBinaryWheels: false,
|
|
13424
|
+
cachedLockPath
|
|
13637
13425
|
});
|
|
13638
|
-
const
|
|
13639
|
-
|
|
13640
|
-
await
|
|
13641
|
-
...injectedPackage,
|
|
13642
|
-
uv,
|
|
13426
|
+
const { projectDir, lockPath, lockFileProvidedByUser } = result;
|
|
13427
|
+
if (extraSyncParams !== void 0) {
|
|
13428
|
+
await uv.sync({
|
|
13643
13429
|
venvPath,
|
|
13644
|
-
projectDir
|
|
13645
|
-
|
|
13430
|
+
projectDir,
|
|
13431
|
+
frozen: lockFileProvidedByUser,
|
|
13432
|
+
locked: !lockFileProvidedByUser,
|
|
13433
|
+
pythonPlatform,
|
|
13434
|
+
...extraSyncParams
|
|
13646
13435
|
});
|
|
13647
13436
|
}
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
});
|
|
13652
|
-
if (localSdkSourcePaths.length > 0) {
|
|
13653
|
-
(0, import_build_utils24.debug)(
|
|
13654
|
-
`Installing vercel SDK override from ${baseEnv.VERCEL_SDK_PYTHON}: ` + localSdkSourcePaths.join(", ")
|
|
13655
|
-
);
|
|
13656
|
-
await uv.pip({
|
|
13657
|
-
venvPath,
|
|
13658
|
-
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
13659
|
-
args: [
|
|
13660
|
-
"install",
|
|
13661
|
-
"--link-mode",
|
|
13662
|
-
"copy",
|
|
13663
|
-
// Without --no-sources, uv resolves the checkout's workspace
|
|
13664
|
-
// dependencies as editable .pth installs pointing at the (build
|
|
13665
|
-
// only) checkout mount — invisible to bundling and dangling at
|
|
13666
|
-
// runtime. Explicit paths stay real installs; the remaining
|
|
13667
|
-
// workspace siblings resolve from PyPI.
|
|
13668
|
-
"--no-sources",
|
|
13669
|
-
...pipPlatformArgs,
|
|
13670
|
-
...localSdkSourcePaths
|
|
13671
|
-
]
|
|
13672
|
-
});
|
|
13673
|
-
}
|
|
13674
|
-
if (workflows.length > 0) {
|
|
13675
|
-
workflowMode = await resolveWorkflowServingMode({
|
|
13676
|
-
pythonPackage,
|
|
13677
|
-
uv,
|
|
13678
|
-
venvPath,
|
|
13679
|
-
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
13680
|
-
uvLockPath
|
|
13681
|
-
});
|
|
13682
|
-
if (workflowMode === "workers" && workflows.length > 1) {
|
|
13683
|
-
throw new import_build_utils24.NowBuildError({
|
|
13684
|
-
code: "PYTHON_INVALID_WORKFLOW_CONFIG",
|
|
13685
|
-
message: `"tool.vercel.workflows" declares multiple entrypoints, which requires ${QUEUE_WORKFLOW_SDK_REQUIREMENT} with a distinct namespace per Workflows registry; the installed SDK serves every workflow on the shared __wkf_* topic`
|
|
13686
|
-
});
|
|
13687
|
-
}
|
|
13688
|
-
}
|
|
13689
|
-
const shouldInstallVercelWorkers = legacyWorkersProject || workflows.length > 0 && workflowMode === "workers";
|
|
13690
|
-
if (shouldInstallVercelWorkers) {
|
|
13691
|
-
await installInjectedPackage({
|
|
13692
|
-
name: "vercel-workers",
|
|
13693
|
-
requirement: `vercel-workers==${VERCEL_WORKERS_VERSION}`,
|
|
13694
|
-
envOverride: baseEnv.VERCEL_WORKERS_PYTHON,
|
|
13695
|
-
allowLocalSource: true,
|
|
13696
|
-
uv,
|
|
13697
|
-
venvPath,
|
|
13698
|
-
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
13699
|
-
pipPlatformArgs
|
|
13700
|
-
});
|
|
13701
|
-
}
|
|
13702
|
-
const quirksResult = await runQuirks({ venvPath, pythonEnv, workPath });
|
|
13703
|
-
if (quirksResult.buildEnv) {
|
|
13704
|
-
Object.assign(pythonEnv, quirksResult.buildEnv);
|
|
13705
|
-
}
|
|
13706
|
-
const queueIntegrations = queueAdapterBootstrap.integrations;
|
|
13707
|
-
const writeGeneratedQueueHandler = async (outputPath, declaration) => {
|
|
13708
|
-
const generatedPath = getGeneratedQueueHandlerPath(outputPath);
|
|
13709
|
-
await import_fs20.default.promises.mkdir((0, import_path21.dirname)((0, import_path21.join)(workPath, generatedPath)), {
|
|
13710
|
-
recursive: true
|
|
13711
|
-
});
|
|
13712
|
-
await import_fs20.default.promises.writeFile(
|
|
13713
|
-
(0, import_path21.join)(workPath, generatedPath),
|
|
13714
|
-
createQueueHandlerModule(declaration, queueIntegrations)
|
|
13715
|
-
);
|
|
13716
|
-
};
|
|
13717
|
-
if (subscriberDeclarations.length > 0 && !legacyWorkersProject) {
|
|
13718
|
-
subscribers = await resolveQueueSubscribers({
|
|
13719
|
-
declarations: subscriberDeclarations,
|
|
13720
|
-
uv,
|
|
13721
|
-
venvPath,
|
|
13722
|
-
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
13723
|
-
integrations: queueIntegrations
|
|
13724
|
-
});
|
|
13725
|
-
if (workflowMode === "queue") {
|
|
13726
|
-
for (const subscriber of subscribers) {
|
|
13727
|
-
if (!subscriber.topicPatterns) {
|
|
13728
|
-
subscriber.subscriptions = subscriber.subscriptions.filter(
|
|
13729
|
-
(subscription) => !isWorkflowQueueTopic(subscription.topic)
|
|
13730
|
-
);
|
|
13731
|
-
}
|
|
13732
|
-
}
|
|
13733
|
-
}
|
|
13734
|
-
for (const subscriber of subscribers) {
|
|
13735
|
-
await writeGeneratedQueueHandler(
|
|
13736
|
-
getSubscriberOutputPath(subscriber.name),
|
|
13737
|
-
subscriber
|
|
13738
|
-
);
|
|
13739
|
-
}
|
|
13740
|
-
}
|
|
13741
|
-
const workflowQueueSubscriptions = /* @__PURE__ */ new Map();
|
|
13742
|
-
if (workflows.length > 0 && workflowMode === "queue") {
|
|
13743
|
-
const resolved2 = await resolveQueueSubscribers({
|
|
13744
|
-
declarations: workflows.map((workflow) => ({
|
|
13745
|
-
name: workflow.name,
|
|
13746
|
-
entrypoint: workflow.entrypoint,
|
|
13747
|
-
moduleName: workflow.moduleName,
|
|
13748
|
-
variableName: workflow.variableName
|
|
13749
|
-
})),
|
|
13750
|
-
uv,
|
|
13751
|
-
venvPath,
|
|
13752
|
-
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
13753
|
-
kind: "workflow",
|
|
13754
|
-
integrations: queueIntegrations
|
|
13755
|
-
});
|
|
13756
|
-
for (let i = 0; i < resolved2.length; i++) {
|
|
13757
|
-
for (let j = i + 1; j < resolved2.length; j++) {
|
|
13758
|
-
const overlaps = resolved2[i].subscriptions.some(
|
|
13759
|
-
(left) => resolved2[j].subscriptions.some(
|
|
13760
|
-
(right) => queueTopicPatternsOverlap(left.topic, right.topic)
|
|
13761
|
-
)
|
|
13762
|
-
);
|
|
13763
|
-
if (overlaps) {
|
|
13764
|
-
throw new import_build_utils24.NowBuildError({
|
|
13765
|
-
code: "PYTHON_INVALID_WORKFLOW_CONFIG",
|
|
13766
|
-
message: `workflow entrypoints "${resolved2[i].moduleName}:${resolved2[i].variableName}" and "${resolved2[j].moduleName}:${resolved2[j].variableName}" subscribe to overlapping queue topics; construct each vercel.workflow.Workflows registry with a distinct namespace`
|
|
13767
|
-
});
|
|
13768
|
-
}
|
|
13769
|
-
}
|
|
13770
|
-
}
|
|
13771
|
-
for (const workflow of resolved2) {
|
|
13772
|
-
workflowQueueSubscriptions.set(workflow.name, workflow.subscriptions);
|
|
13773
|
-
await writeGeneratedQueueHandler(
|
|
13774
|
-
getWorkflowOutputPath(workflow.name),
|
|
13775
|
-
workflow
|
|
13776
|
-
);
|
|
13777
|
-
}
|
|
13778
|
-
}
|
|
13779
|
-
const preDeployCommand = config?.preDeployCommand;
|
|
13780
|
-
if (registerPreDeploy && typeof preDeployCommand === "string") {
|
|
13781
|
-
const capturedEnv = { ...pythonEnv };
|
|
13782
|
-
const capturedCwd = workPath;
|
|
13783
|
-
registerPreDeploy(async () => {
|
|
13784
|
-
await builderSpan.child(import_build_utils24.BUILDER_PRE_DEPLOY_STEP, {
|
|
13785
|
-
preDeployCommand
|
|
13786
|
-
}).trace(async () => {
|
|
13787
|
-
console.log(`Running pre-deploy command: \`${preDeployCommand}\``);
|
|
13788
|
-
await (0, import_build_utils24.execCommand)(preDeployCommand, {
|
|
13789
|
-
env: capturedEnv,
|
|
13790
|
-
cwd: capturedCwd
|
|
13791
|
-
});
|
|
13792
|
-
});
|
|
13793
|
-
});
|
|
13437
|
+
if (lockPath && import_fs20.default.existsSync(lockPath)) {
|
|
13438
|
+
await import_fs20.default.promises.mkdir(uvCacheDir, { recursive: true });
|
|
13439
|
+
await import_fs20.default.promises.copyFile(lockPath, cachedLockPath);
|
|
13794
13440
|
}
|
|
13441
|
+
return result;
|
|
13442
|
+
}
|
|
13443
|
+
async function packFunctionBundle({
|
|
13444
|
+
builderSpan,
|
|
13445
|
+
workPath,
|
|
13446
|
+
uvLockPath,
|
|
13447
|
+
uvProjectDir,
|
|
13448
|
+
projectName,
|
|
13449
|
+
pythonVersion,
|
|
13450
|
+
hasCustomCommand,
|
|
13451
|
+
alwaysBundlePackages,
|
|
13452
|
+
initialFiles,
|
|
13453
|
+
additionalExcludes,
|
|
13454
|
+
compileAllEnabled,
|
|
13455
|
+
compileEnv,
|
|
13456
|
+
venvPath,
|
|
13457
|
+
entrypoint,
|
|
13458
|
+
importClosureContext,
|
|
13459
|
+
largeFunctionLabel
|
|
13460
|
+
}) {
|
|
13795
13461
|
const vendorDir = resolveVendorDir();
|
|
13796
|
-
let crons;
|
|
13797
|
-
let runtimeTrampoline;
|
|
13798
|
-
if (entrypoint) {
|
|
13799
|
-
(0, import_build_utils24.debug)("Entrypoint is", entrypoint);
|
|
13800
|
-
const moduleName = entrypointToModule(entrypoint);
|
|
13801
|
-
if (handlerFunction) {
|
|
13802
|
-
const entrypointPath = (0, import_path21.join)(workPath, entrypoint);
|
|
13803
|
-
const source = await import_fs20.default.promises.readFile(entrypointPath, "utf-8");
|
|
13804
|
-
const found = await (0, import_python_analysis12.containsTopLevelCallable)(source, handlerFunction);
|
|
13805
|
-
if (!found) {
|
|
13806
|
-
throw new import_build_utils24.NowBuildError({
|
|
13807
|
-
code: "PYTHON_HANDLER_NOT_FOUND",
|
|
13808
|
-
message: `Handler function "${handlerFunction}" not found in ${entrypoint}. Ensure it is defined at the module's top level.`
|
|
13809
|
-
});
|
|
13810
|
-
}
|
|
13811
|
-
}
|
|
13812
|
-
const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
|
|
13813
|
-
const entrypointWithSuffix = `${entrypoint}${suffix}`;
|
|
13814
|
-
(0, import_build_utils24.debug)("Entrypoint with suffix is", entrypointWithSuffix);
|
|
13815
|
-
crons = await getServiceCrons({
|
|
13816
|
-
service,
|
|
13817
|
-
entrypoint,
|
|
13818
|
-
rawEntrypoint,
|
|
13819
|
-
handlerFunction,
|
|
13820
|
-
pythonBin: getVenvPythonBin(venvPath),
|
|
13821
|
-
env: pythonEnv,
|
|
13822
|
-
workPath
|
|
13823
|
-
});
|
|
13824
|
-
const extraTrampolineEnv = [];
|
|
13825
|
-
if (crons?.length) {
|
|
13826
|
-
const json = JSON.stringify(buildCronRouteTable(crons));
|
|
13827
|
-
(0, import_assert.default)(!json.includes("\\"), `backslash in cron route table: ${json}`);
|
|
13828
|
-
extraTrampolineEnv.push(`"__VC_CRON_ROUTES": '${json}'`);
|
|
13829
|
-
}
|
|
13830
|
-
const variableName = resolved?.variableName ?? "";
|
|
13831
|
-
runtimeTrampoline = createRuntimeTrampoline({
|
|
13832
|
-
moduleName,
|
|
13833
|
-
entrypoint: entrypointWithSuffix,
|
|
13834
|
-
vendorDir,
|
|
13835
|
-
variableName,
|
|
13836
|
-
extraEnv: extraTrampolineEnv
|
|
13837
|
-
});
|
|
13838
|
-
}
|
|
13839
|
-
const compileAllEnabled = shouldCompileAll({
|
|
13840
|
-
isDev: meta.isDev,
|
|
13841
|
-
hasCustomCommand,
|
|
13842
|
-
// A pre-deploy command can rewrite source after the build, which would make
|
|
13843
|
-
// unchecked-hash precompiled bytecode stale; skip precompilation to avoid serving it.
|
|
13844
|
-
hasPreDeployCommand: typeof preDeployCommand === "string"
|
|
13845
|
-
});
|
|
13846
13462
|
const predefinedExcludes = [
|
|
13847
13463
|
".git/**",
|
|
13848
13464
|
".gitignore",
|
|
@@ -13861,71 +13477,13 @@ var build = async ({
|
|
|
13861
13477
|
"**/yarn.lock",
|
|
13862
13478
|
"**/package-lock.json"
|
|
13863
13479
|
];
|
|
13864
|
-
const
|
|
13865
|
-
lambdaEnv.PYTHONPATH = vendorDir;
|
|
13866
|
-
lambdaEnv.PYTHONDONTWRITEBYTECODE = "1";
|
|
13867
|
-
Object.assign(lambdaEnv, quirksResult.env);
|
|
13868
|
-
if (shouldInstallVercelWorkers) {
|
|
13869
|
-
lambdaEnv.VERCEL_HAS_WORKER_SERVICES = "1";
|
|
13870
|
-
}
|
|
13871
|
-
if (queueIntegrations.length > 0) {
|
|
13872
|
-
lambdaEnv.VERCEL_QUEUE_INTEGRATIONS = queueIntegrations.map(
|
|
13873
|
-
({ module: module2, installer, servingActivator }) => `${module2}:${installer}` + (servingActivator ? `:${servingActivator}` : "")
|
|
13874
|
-
).join(",");
|
|
13875
|
-
}
|
|
13876
|
-
const apschedulerSubscribers = apschedulerSubscriberIdentities(subscribers);
|
|
13877
|
-
if (apschedulerSubscribers.length > 0) {
|
|
13878
|
-
lambdaEnv.VERCEL_APSCHEDULER_SUBSCRIBERS = JSON.stringify(
|
|
13879
|
-
apschedulerSubscribers
|
|
13880
|
-
);
|
|
13881
|
-
const previewConfig = await getApschedulerPreviewConfig(workPath);
|
|
13882
|
-
if (previewConfig) {
|
|
13883
|
-
lambdaEnv.VERCEL_APSCHEDULER_PREVIEW_IDLE_TIMEOUT_SECONDS = String(
|
|
13884
|
-
previewConfig.idleTimeoutSeconds
|
|
13885
|
-
);
|
|
13886
|
-
}
|
|
13887
|
-
}
|
|
13888
|
-
const functionConfig = getMatchingFunction(
|
|
13889
|
-
config,
|
|
13890
|
-
entrypoint
|
|
13891
|
-
)?.functionConfig;
|
|
13892
|
-
const includeFilesPatterns = [
|
|
13893
|
-
...normalizeGlobs(config?.includeFiles),
|
|
13894
|
-
...normalizeGlobs(functionConfig?.includeFiles)
|
|
13895
|
-
];
|
|
13896
|
-
const excludeFilesPatterns = [
|
|
13897
|
-
...normalizeGlobs(config?.excludeFiles),
|
|
13898
|
-
...normalizeGlobs(functionConfig?.excludeFiles)
|
|
13899
|
-
];
|
|
13900
|
-
const cdnBundle = getFastAPICdnBundle(
|
|
13901
|
-
fastapiStatic?.collectedMounts ?? [],
|
|
13902
|
-
workPath,
|
|
13903
|
-
pythonPackage.manifest?.data?.tool?.vercel?.fastapi
|
|
13904
|
-
);
|
|
13905
|
-
const globOptions = {
|
|
13480
|
+
const files = await (0, import_build_utils24.glob)("**", {
|
|
13906
13481
|
cwd: workPath,
|
|
13907
|
-
ignore: [
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
...cdnBundle.excludePatterns
|
|
13911
|
-
]
|
|
13912
|
-
};
|
|
13913
|
-
const files = await (0, import_build_utils24.glob)("**", globOptions);
|
|
13914
|
-
for (const pattern of includeFilesPatterns) {
|
|
13915
|
-
Object.assign(files, await (0, import_build_utils24.glob)(pattern, workPath));
|
|
13916
|
-
}
|
|
13917
|
-
Object.assign(files, cdnBundle.directoryStubs);
|
|
13482
|
+
ignore: [...predefinedExcludes, ...additionalExcludes ?? []]
|
|
13483
|
+
});
|
|
13484
|
+
Object.assign(files, initialFiles);
|
|
13918
13485
|
const appPythonSourceFiles = Object.keys(files).filter((file) => file.endsWith(".py")).map((file) => (0, import_path21.join)(workPath, file)).sort();
|
|
13919
|
-
|
|
13920
|
-
files[djangoStatic.manifestRelPath] = new import_build_utils24.FileFsRef({
|
|
13921
|
-
fsPath: (0, import_path21.join)(workPath, djangoStatic.manifestRelPath)
|
|
13922
|
-
});
|
|
13923
|
-
}
|
|
13924
|
-
const handlerPyFilename = "vc__handler__python";
|
|
13925
|
-
if (config.framework === "fasthtml") {
|
|
13926
|
-
const { SESSKEY = "" } = process.env;
|
|
13927
|
-
files[".sesskey"] = new import_build_utils24.FileBlob({ data: `"${SESSKEY}"` });
|
|
13928
|
-
}
|
|
13486
|
+
let pycachePrefix;
|
|
13929
13487
|
await builderSpan.child("vc.builder.python.bundle").trace(async (bundleSpan) => {
|
|
13930
13488
|
const installedDistributions = await InstalledPythonDistributions.load({
|
|
13931
13489
|
venvPath,
|
|
@@ -13941,10 +13499,7 @@ var build = async ({
|
|
|
13941
13499
|
projectName,
|
|
13942
13500
|
pythonVersion,
|
|
13943
13501
|
hasCustomCommand,
|
|
13944
|
-
alwaysBundlePackages
|
|
13945
|
-
...quirksResult.alwaysBundlePackages ?? [],
|
|
13946
|
-
...shouldInstallVercelWorkers ? ["vercel-workers", "vercel_workers"] : []
|
|
13947
|
-
]
|
|
13502
|
+
alwaysBundlePackages
|
|
13948
13503
|
});
|
|
13949
13504
|
const depAnalysis = await depExternalizer.analyze(files, {
|
|
13950
13505
|
onSized: ({ totalSizeBytes, runtimeInstallEnabled }) => {
|
|
@@ -13958,11 +13513,11 @@ var build = async ({
|
|
|
13958
13513
|
});
|
|
13959
13514
|
const compileAllOptions = compileAllEnabled ? {
|
|
13960
13515
|
pythonBin: getVenvPythonBin(venvPath),
|
|
13961
|
-
env:
|
|
13516
|
+
env: compileEnv
|
|
13962
13517
|
} : null;
|
|
13963
13518
|
const compileSources = async ({
|
|
13964
13519
|
includePackages,
|
|
13965
|
-
pycachePrefix
|
|
13520
|
+
pycachePrefix: pycachePrefixArg
|
|
13966
13521
|
}) => {
|
|
13967
13522
|
if (!compileAllOptions)
|
|
13968
13523
|
return void 0;
|
|
@@ -13973,7 +13528,7 @@ var build = async ({
|
|
|
13973
13528
|
const result = await runCompileAll({
|
|
13974
13529
|
...compileAllOptions,
|
|
13975
13530
|
sourceFiles: [...appPythonSourceFiles, ...vendorSourceFiles],
|
|
13976
|
-
pycachePrefix
|
|
13531
|
+
pycachePrefix: pycachePrefixArg
|
|
13977
13532
|
});
|
|
13978
13533
|
timings = result.timings;
|
|
13979
13534
|
compileSpan.setAttributes({
|
|
@@ -13998,13 +13553,8 @@ var build = async ({
|
|
|
13998
13553
|
getImportClosureOptions({
|
|
13999
13554
|
workPath,
|
|
14000
13555
|
entrypoint,
|
|
14001
|
-
|
|
14002
|
-
|
|
14003
|
-
subscriberDeclarations,
|
|
14004
|
-
subscribers,
|
|
14005
|
-
workflows,
|
|
14006
|
-
workflowMode,
|
|
14007
|
-
sitePackageDirs
|
|
13556
|
+
sitePackageDirs,
|
|
13557
|
+
...importClosureContext
|
|
14008
13558
|
})
|
|
14009
13559
|
),
|
|
14010
13560
|
IMPORT_CLOSURE_TIMEOUT_MS,
|
|
@@ -14158,7 +13708,7 @@ var build = async ({
|
|
|
14158
13708
|
timings
|
|
14159
13709
|
});
|
|
14160
13710
|
if (bytesAdded > 0) {
|
|
14161
|
-
|
|
13711
|
+
pycachePrefix = RUNTIME_PYCACHE_PREFIX;
|
|
14162
13712
|
}
|
|
14163
13713
|
} catch (err) {
|
|
14164
13714
|
console.log(
|
|
@@ -14168,7 +13718,7 @@ var build = async ({
|
|
|
14168
13718
|
}
|
|
14169
13719
|
};
|
|
14170
13720
|
const announceLargeFunction = () => console.log(
|
|
14171
|
-
`Function "${
|
|
13721
|
+
`Function "${largeFunctionLabel}" exceeds the standard size limit; enabling large functions (beta).`
|
|
14172
13722
|
);
|
|
14173
13723
|
let packingMode;
|
|
14174
13724
|
let runtimeToolingBytes = 0;
|
|
@@ -14235,6 +13785,730 @@ var build = async ({
|
|
|
14235
13785
|
"python.bundle.packingMode": packingMode
|
|
14236
13786
|
});
|
|
14237
13787
|
});
|
|
13788
|
+
return { pycachePrefix, vendorDir, files };
|
|
13789
|
+
}
|
|
13790
|
+
async function buildProxyMiddleware({
|
|
13791
|
+
workPath,
|
|
13792
|
+
repoRootPath,
|
|
13793
|
+
files: originalFiles,
|
|
13794
|
+
entrypoint,
|
|
13795
|
+
config,
|
|
13796
|
+
meta,
|
|
13797
|
+
builderSpan
|
|
13798
|
+
}) {
|
|
13799
|
+
const target = getTargetPlatform(meta.isDev ?? false);
|
|
13800
|
+
(0, import_build_utils24.debug)(`workPath: ${workPath}`);
|
|
13801
|
+
workPath = await downloadFilesInWorkPath({
|
|
13802
|
+
workPath,
|
|
13803
|
+
files: originalFiles,
|
|
13804
|
+
entrypoint,
|
|
13805
|
+
meta
|
|
13806
|
+
});
|
|
13807
|
+
const proxyHandlerFunction = config.handlerFunction;
|
|
13808
|
+
if (typeof proxyHandlerFunction !== "string" || !proxyHandlerFunction) {
|
|
13809
|
+
throw new Error(
|
|
13810
|
+
'Python proxy build requires "config.handlerFunction" to be set'
|
|
13811
|
+
);
|
|
13812
|
+
}
|
|
13813
|
+
const proxySource = await import_fs20.default.promises.readFile(
|
|
13814
|
+
(0, import_path21.join)(workPath, entrypoint),
|
|
13815
|
+
"utf-8"
|
|
13816
|
+
);
|
|
13817
|
+
if (!await (0, import_python_analysis12.containsTopLevelCallable)(proxySource, proxyHandlerFunction)) {
|
|
13818
|
+
throw new import_build_utils24.NowBuildError({
|
|
13819
|
+
code: "PYTHON_HANDLER_NOT_FOUND",
|
|
13820
|
+
message: `Handler function "${proxyHandlerFunction}" not found in ${entrypoint}. Ensure it is defined at the module's top level.`
|
|
13821
|
+
});
|
|
13822
|
+
}
|
|
13823
|
+
const rootDir = repoRootPath ?? workPath;
|
|
13824
|
+
const venvPath = (0, import_path21.join)(workPath, ".vercel", "python", "vercel.proxy", ".venv");
|
|
13825
|
+
const { pythonPackage, pythonVersion, uv, uvCacheDir, restoredCache } = await setupPythonToolchain({
|
|
13826
|
+
builderSpan,
|
|
13827
|
+
workPath,
|
|
13828
|
+
entrypointDir: (0, import_path21.join)(workPath, (0, import_path21.dirname)(entrypoint)),
|
|
13829
|
+
rootDir,
|
|
13830
|
+
venvPath,
|
|
13831
|
+
meta
|
|
13832
|
+
});
|
|
13833
|
+
const { projectDir, lockPath: uvLockPath } = await builderSpan.child(import_build_utils24.BUILDER_INSTALLER_STEP, {
|
|
13834
|
+
runtime: "python",
|
|
13835
|
+
"python.cache.restored": restoredCache
|
|
13836
|
+
}).trace(
|
|
13837
|
+
() => runUvManagedInstall({
|
|
13838
|
+
workPath,
|
|
13839
|
+
rootDir,
|
|
13840
|
+
venvPath,
|
|
13841
|
+
pythonPackage,
|
|
13842
|
+
pythonVersion,
|
|
13843
|
+
uv,
|
|
13844
|
+
uvCacheDir,
|
|
13845
|
+
lockCacheKey: "uv.lock",
|
|
13846
|
+
pythonPlatform: target.uvPlatform,
|
|
13847
|
+
// Install only the proxy's dependency group into the proxy venv;
|
|
13848
|
+
// the project itself is neither built nor installed.
|
|
13849
|
+
// If the group is absent the proxy has no extra deps — skip sync.
|
|
13850
|
+
extraSyncParams: "vercel.proxy" in (pythonPackage?.manifest?.data?.["dependency-groups"] ?? {}) ? { onlyGroup: "vercel.proxy", noInstallProject: true } : void 0
|
|
13851
|
+
})
|
|
13852
|
+
);
|
|
13853
|
+
const pipPlatformArgs = target.uvPlatform ? ["--python-platform", target.uvPlatform] : [];
|
|
13854
|
+
await installInjectedPackage({
|
|
13855
|
+
name: "vercel-runtime",
|
|
13856
|
+
requirement: `vercel-runtime==${VERCEL_RUNTIME_VERSION}`,
|
|
13857
|
+
envOverride: process.env.VERCEL_RUNTIME_PYTHON,
|
|
13858
|
+
allowLocalSource: true,
|
|
13859
|
+
uv,
|
|
13860
|
+
venvPath,
|
|
13861
|
+
projectDir,
|
|
13862
|
+
pipPlatformArgs
|
|
13863
|
+
});
|
|
13864
|
+
const projectName = pythonPackage?.manifest?.data?.project?.name;
|
|
13865
|
+
const compileAllEnabled = shouldCompileAll({
|
|
13866
|
+
isDev: meta.isDev ?? false,
|
|
13867
|
+
hasCustomCommand: false
|
|
13868
|
+
});
|
|
13869
|
+
const pythonEnv = createVenvEnv(venvPath, process.env, uvCacheDir);
|
|
13870
|
+
const functionConfig = getMatchingFunction(
|
|
13871
|
+
config,
|
|
13872
|
+
entrypoint
|
|
13873
|
+
)?.functionConfig;
|
|
13874
|
+
const includeFilesPatterns = [
|
|
13875
|
+
...normalizeGlobs(config?.includeFiles),
|
|
13876
|
+
...normalizeGlobs(functionConfig?.includeFiles)
|
|
13877
|
+
];
|
|
13878
|
+
const excludeFilesPatterns = [
|
|
13879
|
+
...normalizeGlobs(config?.excludeFiles),
|
|
13880
|
+
...normalizeGlobs(functionConfig?.excludeFiles)
|
|
13881
|
+
];
|
|
13882
|
+
const initialFiles = {};
|
|
13883
|
+
for (const pattern of includeFilesPatterns) {
|
|
13884
|
+
Object.assign(initialFiles, await (0, import_build_utils24.glob)(pattern, workPath));
|
|
13885
|
+
}
|
|
13886
|
+
const { pycachePrefix, vendorDir, files } = await packFunctionBundle({
|
|
13887
|
+
builderSpan,
|
|
13888
|
+
workPath,
|
|
13889
|
+
uvLockPath,
|
|
13890
|
+
uvProjectDir: projectDir,
|
|
13891
|
+
projectName,
|
|
13892
|
+
pythonVersion,
|
|
13893
|
+
hasCustomCommand: false,
|
|
13894
|
+
alwaysBundlePackages: [],
|
|
13895
|
+
initialFiles,
|
|
13896
|
+
additionalExcludes: excludeFilesPatterns,
|
|
13897
|
+
compileAllEnabled,
|
|
13898
|
+
compileEnv: pythonEnv,
|
|
13899
|
+
venvPath,
|
|
13900
|
+
entrypoint,
|
|
13901
|
+
importClosureContext: {
|
|
13902
|
+
frameworkSeeds: [],
|
|
13903
|
+
extraPythonPath: void 0,
|
|
13904
|
+
subscriberDeclarations: [],
|
|
13905
|
+
subscribers: [],
|
|
13906
|
+
workflows: [],
|
|
13907
|
+
workflowMode: "workers"
|
|
13908
|
+
},
|
|
13909
|
+
largeFunctionLabel: entrypoint
|
|
13910
|
+
});
|
|
13911
|
+
const moduleName = entrypointToModule(entrypoint);
|
|
13912
|
+
const variableName = proxyHandlerFunction;
|
|
13913
|
+
const handlerPyFilename = "vc__handler__python";
|
|
13914
|
+
const runtimeTrampoline = createRuntimeTrampoline({
|
|
13915
|
+
moduleName,
|
|
13916
|
+
entrypoint,
|
|
13917
|
+
vendorDir,
|
|
13918
|
+
variableName,
|
|
13919
|
+
extraEnv: []
|
|
13920
|
+
});
|
|
13921
|
+
files[`${handlerPyFilename}.py`] = new import_build_utils24.FileBlob({ data: runtimeTrampoline });
|
|
13922
|
+
const lambdaOptions = await getPythonLambdaOptions({ config, entrypoint });
|
|
13923
|
+
const output = new import_build_utils24.Lambda({
|
|
13924
|
+
files,
|
|
13925
|
+
handler: `${handlerPyFilename}.vc_handler`,
|
|
13926
|
+
runtime: pythonVersion.runtime,
|
|
13927
|
+
...lambdaOptions,
|
|
13928
|
+
architecture: target.architecture,
|
|
13929
|
+
environment: {
|
|
13930
|
+
PYTHONPATH: vendorDir,
|
|
13931
|
+
PYTHONDONTWRITEBYTECODE: "1",
|
|
13932
|
+
...pycachePrefix ? { PYTHONPYCACHEPREFIX: pycachePrefix } : {}
|
|
13933
|
+
},
|
|
13934
|
+
supportsResponseStreaming: true
|
|
13935
|
+
});
|
|
13936
|
+
const matcher = (0, import_build_utils25.resolveMiddlewareMatcher)(
|
|
13937
|
+
config.middlewareMatcher,
|
|
13938
|
+
void 0,
|
|
13939
|
+
entrypoint
|
|
13940
|
+
);
|
|
13941
|
+
const src = (0, import_build_utils25.getRegExpFromMatchers)(matcher);
|
|
13942
|
+
const middlewareRawSrc = !matcher ? [] : Array.isArray(matcher) ? [...matcher] : [matcher];
|
|
13943
|
+
return {
|
|
13944
|
+
resultVersion: 3,
|
|
13945
|
+
result: {
|
|
13946
|
+
output,
|
|
13947
|
+
routes: [
|
|
13948
|
+
{
|
|
13949
|
+
src,
|
|
13950
|
+
middlewareRawSrc,
|
|
13951
|
+
middlewarePath: entrypoint.replace(/\.py$/i, ""),
|
|
13952
|
+
continue: true,
|
|
13953
|
+
override: true
|
|
13954
|
+
}
|
|
13955
|
+
]
|
|
13956
|
+
}
|
|
13957
|
+
};
|
|
13958
|
+
}
|
|
13959
|
+
var build = async ({
|
|
13960
|
+
workPath,
|
|
13961
|
+
repoRootPath,
|
|
13962
|
+
files: originalFiles,
|
|
13963
|
+
entrypoint: rawEntrypoint,
|
|
13964
|
+
meta = {},
|
|
13965
|
+
config,
|
|
13966
|
+
span: parentSpan,
|
|
13967
|
+
service,
|
|
13968
|
+
registerPreDeploy
|
|
13969
|
+
}) => {
|
|
13970
|
+
let entrypoint = rawEntrypoint === "<detect>" ? void 0 : rawEntrypoint;
|
|
13971
|
+
const builderSpan = parentSpan ?? new import_build_utils24.Span({ name: "vc.builder" });
|
|
13972
|
+
if (config?.middleware === true && entrypoint) {
|
|
13973
|
+
return buildProxyMiddleware({
|
|
13974
|
+
workPath,
|
|
13975
|
+
repoRootPath,
|
|
13976
|
+
files: originalFiles,
|
|
13977
|
+
entrypoint,
|
|
13978
|
+
config,
|
|
13979
|
+
meta,
|
|
13980
|
+
builderSpan
|
|
13981
|
+
});
|
|
13982
|
+
}
|
|
13983
|
+
const isPyprojectEntrypoint = entrypoint !== void 0 && (0, import_path21.basename)(entrypoint) === "pyproject.toml";
|
|
13984
|
+
if (isPyprojectEntrypoint && entrypoint !== "pyproject.toml") {
|
|
13985
|
+
throw new import_build_utils24.NowBuildError({
|
|
13986
|
+
code: "PYTHON_INVALID_PYPROJECT_ENTRYPOINT",
|
|
13987
|
+
message: `A "pyproject.toml" entrypoint must sit at the service root. Set the service "root" to "${(0, import_path21.dirname)(entrypoint)}" and use entrypoint "pyproject.toml".`
|
|
13988
|
+
});
|
|
13989
|
+
}
|
|
13990
|
+
const framework = config?.framework;
|
|
13991
|
+
let subscriberDeclarations = [];
|
|
13992
|
+
let subscribers = [];
|
|
13993
|
+
let workflows = [];
|
|
13994
|
+
let legacyWorkersProject = false;
|
|
13995
|
+
let workflowMode = "workers";
|
|
13996
|
+
let spawnEnv;
|
|
13997
|
+
let projectInstallCommand;
|
|
13998
|
+
let hasCustomCommand = false;
|
|
13999
|
+
const target = getTargetPlatform(meta.isDev ?? false);
|
|
14000
|
+
(0, import_build_utils24.debug)(`workPath: ${workPath}`);
|
|
14001
|
+
workPath = await downloadFilesInWorkPath({
|
|
14002
|
+
workPath,
|
|
14003
|
+
files: originalFiles,
|
|
14004
|
+
entrypoint,
|
|
14005
|
+
meta
|
|
14006
|
+
});
|
|
14007
|
+
legacyWorkersProject = await isLegacyWorkersProject(workPath);
|
|
14008
|
+
if (isPyprojectEntrypoint || !service && (0, import_build_utils24.isPythonFramework)(framework)) {
|
|
14009
|
+
subscriberDeclarations = await getPyprojectSubscribers(workPath, {
|
|
14010
|
+
legacySchema: legacyWorkersProject
|
|
14011
|
+
});
|
|
14012
|
+
workflows = await getPyprojectWorkflows(workPath);
|
|
14013
|
+
}
|
|
14014
|
+
try {
|
|
14015
|
+
if (meta.isDev) {
|
|
14016
|
+
const setupCfg = (0, import_path21.join)(workPath, "setup.cfg");
|
|
14017
|
+
await writeFile(setupCfg, "[install]\nprefix=\n");
|
|
14018
|
+
}
|
|
14019
|
+
} catch (err) {
|
|
14020
|
+
console.log('Failed to create "setup.cfg" file');
|
|
14021
|
+
throw err;
|
|
14022
|
+
}
|
|
14023
|
+
let detected;
|
|
14024
|
+
const handlerFunction = typeof config?.handlerFunction === "string" ? config.handlerFunction : void 0;
|
|
14025
|
+
if (isPyprojectEntrypoint) {
|
|
14026
|
+
const declared = await getVercelToolsEntrypoint(workPath, repoRootPath);
|
|
14027
|
+
if (declared) {
|
|
14028
|
+
detected = { entrypoint: declared };
|
|
14029
|
+
} else if (subscriberDeclarations.length === 0 && workflows.length === 0) {
|
|
14030
|
+
throw new import_build_utils24.NowBuildError({
|
|
14031
|
+
code: "PYTHON_PYPROJECT_NOTHING_TO_BUILD",
|
|
14032
|
+
message: 'Entrypoint "pyproject.toml" declares nothing to build. Set "tool.vercel.entrypoint" for a web app and/or declare "[[tool.vercel.subscribers]]" or "[[tool.vercel.workflows]]" entries in pyproject.toml.'
|
|
14033
|
+
});
|
|
14034
|
+
}
|
|
14035
|
+
entrypoint = void 0;
|
|
14036
|
+
} else {
|
|
14037
|
+
detected = await detectPythonEntrypoint(
|
|
14038
|
+
config.framework,
|
|
14039
|
+
workPath,
|
|
14040
|
+
entrypoint ? {
|
|
14041
|
+
filePath: entrypoint,
|
|
14042
|
+
// For schedule-triggered jobs, the WSGI variable is always 'app' (created dynamically).
|
|
14043
|
+
// For other services, handlerFunction is used as the entrypoint variable name.
|
|
14044
|
+
varName: service && (0, import_build_utils24.isScheduleTriggeredService)(service) ? void 0 : handlerFunction
|
|
14045
|
+
} : void 0,
|
|
14046
|
+
service,
|
|
14047
|
+
repoRootPath
|
|
14048
|
+
) ?? void 0;
|
|
14049
|
+
}
|
|
14050
|
+
if (detected?.error && detected?.baseDir === void 0) {
|
|
14051
|
+
throw detected?.error;
|
|
14052
|
+
}
|
|
14053
|
+
const entryDirectory = detected?.baseDir ?? (entrypoint ? (0, import_path21.dirname)(entrypoint) : ".");
|
|
14054
|
+
const entrypointAbsDir = (0, import_path21.join)(workPath, entryDirectory);
|
|
14055
|
+
const rootDir = repoRootPath ?? workPath;
|
|
14056
|
+
const venvPath = service?.name ? (0, import_path21.join)(workPath, ".vercel", "python", "services", service.name, ".venv") : (0, import_path21.join)(workPath, ".vercel", "python", ".venv");
|
|
14057
|
+
const { pythonPackage, pythonVersion, uv, uvCacheDir, restoredCache } = await setupPythonToolchain({
|
|
14058
|
+
builderSpan,
|
|
14059
|
+
workPath,
|
|
14060
|
+
entrypointDir: entrypointAbsDir,
|
|
14061
|
+
rootDir,
|
|
14062
|
+
venvPath,
|
|
14063
|
+
meta
|
|
14064
|
+
});
|
|
14065
|
+
if ((0, import_build_utils24.isPythonFramework)(framework)) {
|
|
14066
|
+
const {
|
|
14067
|
+
cliType,
|
|
14068
|
+
lockfileVersion,
|
|
14069
|
+
packageJsonPackageManager,
|
|
14070
|
+
packageJsonDevEngines,
|
|
14071
|
+
turboSupportsCorepackHome
|
|
14072
|
+
} = await (0, import_build_utils24.scanParentDirs)(workPath, true);
|
|
14073
|
+
spawnEnv = (0, import_build_utils24.getEnvForPackageManager)({
|
|
14074
|
+
cliType,
|
|
14075
|
+
lockfileVersion,
|
|
14076
|
+
packageJsonPackageManager,
|
|
14077
|
+
packageJsonDevEngines,
|
|
14078
|
+
env: process.env,
|
|
14079
|
+
turboSupportsCorepackHome,
|
|
14080
|
+
projectCreatedAt: config?.projectSettings?.createdAt
|
|
14081
|
+
});
|
|
14082
|
+
const installCommand = config?.projectSettings?.installCommand;
|
|
14083
|
+
if (typeof installCommand === "string") {
|
|
14084
|
+
const trimmed = installCommand.trim();
|
|
14085
|
+
if (trimmed) {
|
|
14086
|
+
projectInstallCommand = trimmed;
|
|
14087
|
+
} else {
|
|
14088
|
+
console.log('Skipping "install" command...');
|
|
14089
|
+
}
|
|
14090
|
+
}
|
|
14091
|
+
}
|
|
14092
|
+
const baseEnv = spawnEnv || process.env;
|
|
14093
|
+
const pythonEnv = createVenvEnv(venvPath, baseEnv, uvCacheDir);
|
|
14094
|
+
pythonEnv.VERCEL_PYTHON_VENV_PATH = venvPath;
|
|
14095
|
+
let assumeDepsInstalled = false;
|
|
14096
|
+
let uvLockPath = null;
|
|
14097
|
+
let uvProjectDir = null;
|
|
14098
|
+
let projectName;
|
|
14099
|
+
let usedUvManagedInstall = false;
|
|
14100
|
+
await builderSpan.child(import_build_utils24.BUILDER_INSTALLER_STEP, {
|
|
14101
|
+
installCommand: projectInstallCommand || void 0,
|
|
14102
|
+
runtime: "python",
|
|
14103
|
+
"python.cache.restored": restoredCache
|
|
14104
|
+
}).trace(async () => {
|
|
14105
|
+
if (projectInstallCommand) {
|
|
14106
|
+
await import_fs20.default.promises.rm(venvPath, { recursive: true, force: true });
|
|
14107
|
+
await ensureVenv({
|
|
14108
|
+
pythonVersion,
|
|
14109
|
+
venvPath,
|
|
14110
|
+
uvPath: uv.getPath(),
|
|
14111
|
+
uvCacheDir,
|
|
14112
|
+
quiet: true
|
|
14113
|
+
});
|
|
14114
|
+
console.log(
|
|
14115
|
+
`Running "install" command: \`${projectInstallCommand}\`...`
|
|
14116
|
+
);
|
|
14117
|
+
await (0, import_build_utils24.execCommand)(projectInstallCommand, {
|
|
14118
|
+
env: pythonEnv,
|
|
14119
|
+
cwd: workPath
|
|
14120
|
+
});
|
|
14121
|
+
assumeDepsInstalled = true;
|
|
14122
|
+
hasCustomCommand = true;
|
|
14123
|
+
} else {
|
|
14124
|
+
const hasCustomScript = await runPyprojectScript(
|
|
14125
|
+
workPath,
|
|
14126
|
+
["vercel-install", "now-install", "install"],
|
|
14127
|
+
pythonEnv,
|
|
14128
|
+
/* useUserVirtualEnv */
|
|
14129
|
+
false
|
|
14130
|
+
);
|
|
14131
|
+
if (hasCustomScript) {
|
|
14132
|
+
assumeDepsInstalled = true;
|
|
14133
|
+
hasCustomCommand = true;
|
|
14134
|
+
}
|
|
14135
|
+
}
|
|
14136
|
+
if (!assumeDepsInstalled) {
|
|
14137
|
+
const { projectDir, lockPath } = await runUvManagedInstall({
|
|
14138
|
+
workPath,
|
|
14139
|
+
rootDir,
|
|
14140
|
+
venvPath,
|
|
14141
|
+
pythonPackage,
|
|
14142
|
+
pythonVersion,
|
|
14143
|
+
uv,
|
|
14144
|
+
uvCacheDir,
|
|
14145
|
+
lockCacheKey: service?.name ? `uv.lock.${service.name}` : "uv.lock",
|
|
14146
|
+
pythonPlatform: target.uvPlatform,
|
|
14147
|
+
extraSyncParams: {}
|
|
14148
|
+
});
|
|
14149
|
+
uvLockPath = lockPath;
|
|
14150
|
+
uvProjectDir = projectDir;
|
|
14151
|
+
projectName = pythonPackage?.manifest?.data?.project?.name;
|
|
14152
|
+
usedUvManagedInstall = true;
|
|
14153
|
+
}
|
|
14154
|
+
});
|
|
14155
|
+
if ((0, import_build_utils24.isPythonFramework)(framework)) {
|
|
14156
|
+
const projectBuildCommand = config?.projectSettings?.buildCommand ?? // fallback if provided directly on config (some callers set this)
|
|
14157
|
+
config?.buildCommand;
|
|
14158
|
+
await builderSpan.child(import_build_utils24.BUILDER_COMPILE_STEP, {
|
|
14159
|
+
buildCommand: projectBuildCommand || void 0
|
|
14160
|
+
}).trace(async () => {
|
|
14161
|
+
if (projectBuildCommand) {
|
|
14162
|
+
console.log(`Running "${projectBuildCommand}"`);
|
|
14163
|
+
await (0, import_build_utils24.execCommand)(projectBuildCommand, {
|
|
14164
|
+
env: pythonEnv,
|
|
14165
|
+
cwd: workPath
|
|
14166
|
+
});
|
|
14167
|
+
} else {
|
|
14168
|
+
await runPyprojectScript(
|
|
14169
|
+
workPath,
|
|
14170
|
+
["vercel-build", "now-build", "build"],
|
|
14171
|
+
pythonEnv
|
|
14172
|
+
);
|
|
14173
|
+
}
|
|
14174
|
+
});
|
|
14175
|
+
}
|
|
14176
|
+
const hookResult = await runFrameworkHook(framework, {
|
|
14177
|
+
pythonEnv,
|
|
14178
|
+
workPath,
|
|
14179
|
+
venvPath,
|
|
14180
|
+
entrypoint,
|
|
14181
|
+
detected,
|
|
14182
|
+
pyprojectData: pythonPackage.manifest?.data
|
|
14183
|
+
});
|
|
14184
|
+
const resolved = isPyprojectEntrypoint ? detected?.entrypoint : hookResult?.entrypoint ?? detected?.entrypoint;
|
|
14185
|
+
if (!resolved && detected?.error) {
|
|
14186
|
+
throw detected?.error;
|
|
14187
|
+
}
|
|
14188
|
+
entrypoint = resolved?.entrypoint;
|
|
14189
|
+
const isWorkersOnly = !entrypoint && isPyprojectEntrypoint && (subscriberDeclarations.length > 0 || workflows.length > 0);
|
|
14190
|
+
if (!entrypoint && !isWorkersOnly) {
|
|
14191
|
+
throw new import_build_utils24.NowBuildError({
|
|
14192
|
+
code: "PYTHON_ENTRYPOINT_NOT_FOUND",
|
|
14193
|
+
message: "No Python entrypoint could be detected. Please specify an entrypoint file."
|
|
14194
|
+
});
|
|
14195
|
+
}
|
|
14196
|
+
const djangoStatic = hookResult?.djangoStatic ?? null;
|
|
14197
|
+
const fastapiStatic = hookResult?.fastapiStatic ?? null;
|
|
14198
|
+
const importSeeds = hookResult?.importSeeds ?? [];
|
|
14199
|
+
const cdnOutputDir = djangoStatic?.cdnOutputDir ?? fastapiStatic?.cdnOutputDir ?? null;
|
|
14200
|
+
const pipPlatformArgs = target.uvPlatform ? ["--python-platform", target.uvPlatform] : [];
|
|
14201
|
+
await installInjectedPackage({
|
|
14202
|
+
name: "vercel-runtime",
|
|
14203
|
+
requirement: `vercel-runtime==${VERCEL_RUNTIME_VERSION}`,
|
|
14204
|
+
envOverride: baseEnv.VERCEL_RUNTIME_PYTHON,
|
|
14205
|
+
allowLocalSource: true,
|
|
14206
|
+
uv,
|
|
14207
|
+
venvPath,
|
|
14208
|
+
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
14209
|
+
pipPlatformArgs
|
|
14210
|
+
});
|
|
14211
|
+
const queueAdapterBootstrap = await getQueueAdapterBootstrap({
|
|
14212
|
+
pythonPackage,
|
|
14213
|
+
env: baseEnv,
|
|
14214
|
+
legacyWorkersProject,
|
|
14215
|
+
hasDeclaredSubscribers: await hasPyprojectSubscribers(workPath)
|
|
14216
|
+
});
|
|
14217
|
+
const queueAdapterInjectedPackages = usedUvManagedInstall ? queueAdapterBootstrap.injectedPackages : [];
|
|
14218
|
+
for (const injectedPackage of queueAdapterInjectedPackages) {
|
|
14219
|
+
await installInjectedPackage({
|
|
14220
|
+
...injectedPackage,
|
|
14221
|
+
uv,
|
|
14222
|
+
venvPath,
|
|
14223
|
+
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
14224
|
+
pipPlatformArgs
|
|
14225
|
+
});
|
|
14226
|
+
}
|
|
14227
|
+
const localSdkSourcePaths = await getLocalSdkSourcePaths({
|
|
14228
|
+
pythonPackage,
|
|
14229
|
+
env: baseEnv
|
|
14230
|
+
});
|
|
14231
|
+
if (localSdkSourcePaths.length > 0) {
|
|
14232
|
+
(0, import_build_utils24.debug)(
|
|
14233
|
+
`Installing vercel SDK override from ${baseEnv.VERCEL_SDK_PYTHON}: ` + localSdkSourcePaths.join(", ")
|
|
14234
|
+
);
|
|
14235
|
+
await uv.pip({
|
|
14236
|
+
venvPath,
|
|
14237
|
+
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
14238
|
+
args: [
|
|
14239
|
+
"install",
|
|
14240
|
+
"--link-mode",
|
|
14241
|
+
"copy",
|
|
14242
|
+
// Without --no-sources, uv resolves the checkout's workspace
|
|
14243
|
+
// dependencies as editable .pth installs pointing at the (build
|
|
14244
|
+
// only) checkout mount — invisible to bundling and dangling at
|
|
14245
|
+
// runtime. Explicit paths stay real installs; the remaining
|
|
14246
|
+
// workspace siblings resolve from PyPI.
|
|
14247
|
+
"--no-sources",
|
|
14248
|
+
...pipPlatformArgs,
|
|
14249
|
+
...localSdkSourcePaths
|
|
14250
|
+
]
|
|
14251
|
+
});
|
|
14252
|
+
}
|
|
14253
|
+
if (workflows.length > 0) {
|
|
14254
|
+
workflowMode = await resolveWorkflowServingMode({
|
|
14255
|
+
pythonPackage,
|
|
14256
|
+
uv,
|
|
14257
|
+
venvPath,
|
|
14258
|
+
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
14259
|
+
uvLockPath
|
|
14260
|
+
});
|
|
14261
|
+
if (workflowMode === "workers" && workflows.length > 1) {
|
|
14262
|
+
throw new import_build_utils24.NowBuildError({
|
|
14263
|
+
code: "PYTHON_INVALID_WORKFLOW_CONFIG",
|
|
14264
|
+
message: `"tool.vercel.workflows" declares multiple entrypoints, which requires ${QUEUE_WORKFLOW_SDK_REQUIREMENT} with a distinct namespace per Workflows registry; the installed SDK serves every workflow on the shared __wkf_* topic`
|
|
14265
|
+
});
|
|
14266
|
+
}
|
|
14267
|
+
}
|
|
14268
|
+
const shouldInstallVercelWorkers = legacyWorkersProject || workflows.length > 0 && workflowMode === "workers";
|
|
14269
|
+
if (shouldInstallVercelWorkers) {
|
|
14270
|
+
await installInjectedPackage({
|
|
14271
|
+
name: "vercel-workers",
|
|
14272
|
+
requirement: `vercel-workers==${VERCEL_WORKERS_VERSION}`,
|
|
14273
|
+
envOverride: baseEnv.VERCEL_WORKERS_PYTHON,
|
|
14274
|
+
allowLocalSource: true,
|
|
14275
|
+
uv,
|
|
14276
|
+
venvPath,
|
|
14277
|
+
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
14278
|
+
pipPlatformArgs
|
|
14279
|
+
});
|
|
14280
|
+
}
|
|
14281
|
+
const quirksResult = await runQuirks({ venvPath, pythonEnv, workPath });
|
|
14282
|
+
if (quirksResult.buildEnv) {
|
|
14283
|
+
Object.assign(pythonEnv, quirksResult.buildEnv);
|
|
14284
|
+
}
|
|
14285
|
+
const queueIntegrations = queueAdapterBootstrap.integrations;
|
|
14286
|
+
const writeGeneratedQueueHandler = async (outputPath, declaration) => {
|
|
14287
|
+
const generatedPath = getGeneratedQueueHandlerPath(outputPath);
|
|
14288
|
+
await import_fs20.default.promises.mkdir((0, import_path21.dirname)((0, import_path21.join)(workPath, generatedPath)), {
|
|
14289
|
+
recursive: true
|
|
14290
|
+
});
|
|
14291
|
+
await import_fs20.default.promises.writeFile(
|
|
14292
|
+
(0, import_path21.join)(workPath, generatedPath),
|
|
14293
|
+
createQueueHandlerModule(declaration, queueIntegrations)
|
|
14294
|
+
);
|
|
14295
|
+
};
|
|
14296
|
+
if (subscriberDeclarations.length > 0 && !legacyWorkersProject) {
|
|
14297
|
+
subscribers = await resolveQueueSubscribers({
|
|
14298
|
+
declarations: subscriberDeclarations,
|
|
14299
|
+
uv,
|
|
14300
|
+
venvPath,
|
|
14301
|
+
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
14302
|
+
integrations: queueIntegrations
|
|
14303
|
+
});
|
|
14304
|
+
if (workflowMode === "queue") {
|
|
14305
|
+
for (const subscriber of subscribers) {
|
|
14306
|
+
if (!subscriber.topicPatterns) {
|
|
14307
|
+
subscriber.subscriptions = subscriber.subscriptions.filter(
|
|
14308
|
+
(subscription) => !isWorkflowQueueTopic(subscription.topic)
|
|
14309
|
+
);
|
|
14310
|
+
}
|
|
14311
|
+
}
|
|
14312
|
+
}
|
|
14313
|
+
for (const subscriber of subscribers) {
|
|
14314
|
+
await writeGeneratedQueueHandler(
|
|
14315
|
+
getSubscriberOutputPath(subscriber.name),
|
|
14316
|
+
subscriber
|
|
14317
|
+
);
|
|
14318
|
+
}
|
|
14319
|
+
}
|
|
14320
|
+
const workflowQueueSubscriptions = /* @__PURE__ */ new Map();
|
|
14321
|
+
if (workflows.length > 0 && workflowMode === "queue") {
|
|
14322
|
+
const resolved2 = await resolveQueueSubscribers({
|
|
14323
|
+
declarations: workflows.map((workflow) => ({
|
|
14324
|
+
name: workflow.name,
|
|
14325
|
+
entrypoint: workflow.entrypoint,
|
|
14326
|
+
moduleName: workflow.moduleName,
|
|
14327
|
+
variableName: workflow.variableName
|
|
14328
|
+
})),
|
|
14329
|
+
uv,
|
|
14330
|
+
venvPath,
|
|
14331
|
+
projectDir: (0, import_path21.join)(workPath, entryDirectory),
|
|
14332
|
+
kind: "workflow",
|
|
14333
|
+
integrations: queueIntegrations
|
|
14334
|
+
});
|
|
14335
|
+
for (let i = 0; i < resolved2.length; i++) {
|
|
14336
|
+
for (let j = i + 1; j < resolved2.length; j++) {
|
|
14337
|
+
const overlaps = resolved2[i].subscriptions.some(
|
|
14338
|
+
(left) => resolved2[j].subscriptions.some(
|
|
14339
|
+
(right) => queueTopicPatternsOverlap(left.topic, right.topic)
|
|
14340
|
+
)
|
|
14341
|
+
);
|
|
14342
|
+
if (overlaps) {
|
|
14343
|
+
throw new import_build_utils24.NowBuildError({
|
|
14344
|
+
code: "PYTHON_INVALID_WORKFLOW_CONFIG",
|
|
14345
|
+
message: `workflow entrypoints "${resolved2[i].moduleName}:${resolved2[i].variableName}" and "${resolved2[j].moduleName}:${resolved2[j].variableName}" subscribe to overlapping queue topics; construct each vercel.workflow.Workflows registry with a distinct namespace`
|
|
14346
|
+
});
|
|
14347
|
+
}
|
|
14348
|
+
}
|
|
14349
|
+
}
|
|
14350
|
+
for (const workflow of resolved2) {
|
|
14351
|
+
workflowQueueSubscriptions.set(workflow.name, workflow.subscriptions);
|
|
14352
|
+
await writeGeneratedQueueHandler(
|
|
14353
|
+
getWorkflowOutputPath(workflow.name),
|
|
14354
|
+
workflow
|
|
14355
|
+
);
|
|
14356
|
+
}
|
|
14357
|
+
}
|
|
14358
|
+
const preDeployCommand = config?.preDeployCommand;
|
|
14359
|
+
if (registerPreDeploy && typeof preDeployCommand === "string") {
|
|
14360
|
+
const capturedEnv = { ...pythonEnv };
|
|
14361
|
+
const capturedCwd = workPath;
|
|
14362
|
+
registerPreDeploy(async () => {
|
|
14363
|
+
await builderSpan.child(import_build_utils24.BUILDER_PRE_DEPLOY_STEP, {
|
|
14364
|
+
preDeployCommand
|
|
14365
|
+
}).trace(async () => {
|
|
14366
|
+
console.log(`Running pre-deploy command: \`${preDeployCommand}\``);
|
|
14367
|
+
await (0, import_build_utils24.execCommand)(preDeployCommand, {
|
|
14368
|
+
env: capturedEnv,
|
|
14369
|
+
cwd: capturedCwd
|
|
14370
|
+
});
|
|
14371
|
+
});
|
|
14372
|
+
});
|
|
14373
|
+
}
|
|
14374
|
+
const vendorDir = resolveVendorDir();
|
|
14375
|
+
let crons;
|
|
14376
|
+
let runtimeTrampoline;
|
|
14377
|
+
if (entrypoint) {
|
|
14378
|
+
(0, import_build_utils24.debug)("Entrypoint is", entrypoint);
|
|
14379
|
+
const moduleName = entrypointToModule(entrypoint);
|
|
14380
|
+
if (handlerFunction) {
|
|
14381
|
+
const entrypointPath = (0, import_path21.join)(workPath, entrypoint);
|
|
14382
|
+
const source = await import_fs20.default.promises.readFile(entrypointPath, "utf-8");
|
|
14383
|
+
const found = await (0, import_python_analysis12.containsTopLevelCallable)(source, handlerFunction);
|
|
14384
|
+
if (!found) {
|
|
14385
|
+
throw new import_build_utils24.NowBuildError({
|
|
14386
|
+
code: "PYTHON_HANDLER_NOT_FOUND",
|
|
14387
|
+
message: `Handler function "${handlerFunction}" not found in ${entrypoint}. Ensure it is defined at the module's top level.`
|
|
14388
|
+
});
|
|
14389
|
+
}
|
|
14390
|
+
}
|
|
14391
|
+
const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
|
|
14392
|
+
const entrypointWithSuffix = `${entrypoint}${suffix}`;
|
|
14393
|
+
(0, import_build_utils24.debug)("Entrypoint with suffix is", entrypointWithSuffix);
|
|
14394
|
+
crons = await getServiceCrons({
|
|
14395
|
+
service,
|
|
14396
|
+
entrypoint,
|
|
14397
|
+
rawEntrypoint,
|
|
14398
|
+
handlerFunction,
|
|
14399
|
+
pythonBin: getVenvPythonBin(venvPath),
|
|
14400
|
+
env: pythonEnv,
|
|
14401
|
+
workPath
|
|
14402
|
+
});
|
|
14403
|
+
const extraTrampolineEnv = [];
|
|
14404
|
+
if (crons?.length) {
|
|
14405
|
+
const json = JSON.stringify(buildCronRouteTable(crons));
|
|
14406
|
+
(0, import_assert.default)(!json.includes("\\"), `backslash in cron route table: ${json}`);
|
|
14407
|
+
extraTrampolineEnv.push(`"__VC_CRON_ROUTES": '${json}'`);
|
|
14408
|
+
}
|
|
14409
|
+
const variableName = resolved?.variableName ?? "";
|
|
14410
|
+
runtimeTrampoline = createRuntimeTrampoline({
|
|
14411
|
+
moduleName,
|
|
14412
|
+
entrypoint: entrypointWithSuffix,
|
|
14413
|
+
vendorDir,
|
|
14414
|
+
variableName,
|
|
14415
|
+
extraEnv: extraTrampolineEnv
|
|
14416
|
+
});
|
|
14417
|
+
}
|
|
14418
|
+
const compileAllEnabled = shouldCompileAll({
|
|
14419
|
+
isDev: meta.isDev,
|
|
14420
|
+
hasCustomCommand,
|
|
14421
|
+
// A pre-deploy command can rewrite source after the build, which would make
|
|
14422
|
+
// unchecked-hash precompiled bytecode stale; skip precompilation to avoid serving it.
|
|
14423
|
+
hasPreDeployCommand: typeof preDeployCommand === "string"
|
|
14424
|
+
});
|
|
14425
|
+
const lambdaEnv = {};
|
|
14426
|
+
lambdaEnv.PYTHONPATH = vendorDir;
|
|
14427
|
+
lambdaEnv.PYTHONDONTWRITEBYTECODE = "1";
|
|
14428
|
+
Object.assign(lambdaEnv, quirksResult.env);
|
|
14429
|
+
if (shouldInstallVercelWorkers) {
|
|
14430
|
+
lambdaEnv.VERCEL_HAS_WORKER_SERVICES = "1";
|
|
14431
|
+
}
|
|
14432
|
+
if (queueIntegrations.length > 0) {
|
|
14433
|
+
lambdaEnv.VERCEL_QUEUE_INTEGRATIONS = queueIntegrations.map(
|
|
14434
|
+
({ module: module2, installer, servingActivator }) => `${module2}:${installer}` + (servingActivator ? `:${servingActivator}` : "")
|
|
14435
|
+
).join(",");
|
|
14436
|
+
}
|
|
14437
|
+
const apschedulerSubscribers = apschedulerSubscriberIdentities(subscribers);
|
|
14438
|
+
if (apschedulerSubscribers.length > 0) {
|
|
14439
|
+
lambdaEnv.VERCEL_APSCHEDULER_SUBSCRIBERS = JSON.stringify(
|
|
14440
|
+
apschedulerSubscribers
|
|
14441
|
+
);
|
|
14442
|
+
const previewConfig = await getApschedulerPreviewConfig(workPath);
|
|
14443
|
+
if (previewConfig) {
|
|
14444
|
+
lambdaEnv.VERCEL_APSCHEDULER_PREVIEW_IDLE_TIMEOUT_SECONDS = String(
|
|
14445
|
+
previewConfig.idleTimeoutSeconds
|
|
14446
|
+
);
|
|
14447
|
+
}
|
|
14448
|
+
}
|
|
14449
|
+
const functionConfig = getMatchingFunction(
|
|
14450
|
+
config,
|
|
14451
|
+
entrypoint
|
|
14452
|
+
)?.functionConfig;
|
|
14453
|
+
const includeFilesPatterns = [
|
|
14454
|
+
...normalizeGlobs(config?.includeFiles),
|
|
14455
|
+
...normalizeGlobs(functionConfig?.includeFiles)
|
|
14456
|
+
];
|
|
14457
|
+
const excludeFilesPatterns = [
|
|
14458
|
+
...normalizeGlobs(config?.excludeFiles),
|
|
14459
|
+
...normalizeGlobs(functionConfig?.excludeFiles)
|
|
14460
|
+
];
|
|
14461
|
+
const cdnBundle = getFastAPICdnBundle(
|
|
14462
|
+
fastapiStatic?.collectedMounts ?? [],
|
|
14463
|
+
workPath,
|
|
14464
|
+
pythonPackage.manifest?.data?.tool?.vercel?.fastapi
|
|
14465
|
+
);
|
|
14466
|
+
const initialFiles = {};
|
|
14467
|
+
for (const pattern of includeFilesPatterns) {
|
|
14468
|
+
Object.assign(initialFiles, await (0, import_build_utils24.glob)(pattern, workPath));
|
|
14469
|
+
}
|
|
14470
|
+
Object.assign(initialFiles, cdnBundle.directoryStubs);
|
|
14471
|
+
if (djangoStatic?.manifestRelPath) {
|
|
14472
|
+
initialFiles[djangoStatic.manifestRelPath] = new import_build_utils24.FileFsRef({
|
|
14473
|
+
fsPath: (0, import_path21.join)(workPath, djangoStatic.manifestRelPath)
|
|
14474
|
+
});
|
|
14475
|
+
}
|
|
14476
|
+
const handlerPyFilename = "vc__handler__python";
|
|
14477
|
+
if (config.framework === "fasthtml") {
|
|
14478
|
+
const { SESSKEY = "" } = process.env;
|
|
14479
|
+
initialFiles[".sesskey"] = new import_build_utils24.FileBlob({ data: `"${SESSKEY}"` });
|
|
14480
|
+
}
|
|
14481
|
+
const { pycachePrefix, files } = await packFunctionBundle({
|
|
14482
|
+
builderSpan,
|
|
14483
|
+
workPath,
|
|
14484
|
+
uvLockPath,
|
|
14485
|
+
uvProjectDir,
|
|
14486
|
+
projectName,
|
|
14487
|
+
pythonVersion,
|
|
14488
|
+
hasCustomCommand,
|
|
14489
|
+
alwaysBundlePackages: [
|
|
14490
|
+
...quirksResult.alwaysBundlePackages ?? [],
|
|
14491
|
+
...shouldInstallVercelWorkers ? ["vercel-workers", "vercel_workers"] : []
|
|
14492
|
+
],
|
|
14493
|
+
initialFiles,
|
|
14494
|
+
additionalExcludes: [...excludeFilesPatterns, ...cdnBundle.excludePatterns],
|
|
14495
|
+
compileAllEnabled,
|
|
14496
|
+
compileEnv: pythonEnv,
|
|
14497
|
+
venvPath,
|
|
14498
|
+
entrypoint,
|
|
14499
|
+
importClosureContext: {
|
|
14500
|
+
frameworkSeeds: importSeeds,
|
|
14501
|
+
extraPythonPath: hookResult?.extraPythonPath,
|
|
14502
|
+
subscriberDeclarations,
|
|
14503
|
+
subscribers,
|
|
14504
|
+
workflows,
|
|
14505
|
+
workflowMode
|
|
14506
|
+
},
|
|
14507
|
+
largeFunctionLabel: entrypoint ?? rawEntrypoint
|
|
14508
|
+
});
|
|
14509
|
+
if (pycachePrefix) {
|
|
14510
|
+
lambdaEnv.PYTHONPYCACHEPREFIX = pycachePrefix;
|
|
14511
|
+
}
|
|
14238
14512
|
let output;
|
|
14239
14513
|
if (entrypoint && runtimeTrampoline) {
|
|
14240
14514
|
const webFiles = {
|