vercel 54.6.0 → 54.7.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.
Files changed (68) hide show
  1. package/dist/chunks/{add-4JTZ2IN2.js → add-ACM2FI4N.js} +8 -8
  2. package/dist/chunks/{chunk-3TDGMELF.js → chunk-2R5WYHZW.js} +2 -2
  3. package/dist/chunks/{chunk-YP423QYK.js → chunk-3EOZ4ZDJ.js} +2 -2
  4. package/dist/chunks/{chunk-V23PMSXG.js → chunk-5K6XFQBY.js} +45 -777
  5. package/dist/chunks/{chunk-6PVIXIDG.js → chunk-6PSM4YC3.js} +3 -3
  6. package/dist/chunks/{chunk-TM2USC5N.js → chunk-7HAY2TY5.js} +3 -3
  7. package/dist/chunks/{chunk-ULXHXZCZ.js → chunk-7OUZIPHA.js} +1 -1
  8. package/dist/chunks/{chunk-KNTWCQDY.js → chunk-7Q62DZEF.js} +9 -7
  9. package/dist/chunks/{chunk-SRVNEJVN.js → chunk-CMQXECHW.js} +2 -2
  10. package/dist/chunks/{chunk-5EKBCYHA.js → chunk-CPWI2SWV.js} +2 -2
  11. package/dist/chunks/{chunk-XFSFHTAB.js → chunk-DDORH57D.js} +2 -2
  12. package/dist/chunks/{chunk-B43F7BHW.js → chunk-ERQAMRRQ.js} +2 -2
  13. package/dist/chunks/{chunk-LT7RPFRM.js → chunk-FO7QBAVZ.js} +4 -4
  14. package/dist/chunks/{chunk-TPCECDGK.js → chunk-FQ2EU7QM.js} +7 -7
  15. package/dist/chunks/{chunk-NYJXGEIR.js → chunk-FV5RQPKY.js} +1 -1
  16. package/dist/chunks/{chunk-JD4N3RDP.js → chunk-HW6MMF4G.js} +4 -4
  17. package/dist/chunks/{chunk-UGXBNJMO.js → chunk-IDFKAJW3.js} +1 -0
  18. package/dist/chunks/{chunk-7O3VXZBW.js → chunk-K5ISROJF.js} +1 -1
  19. package/dist/chunks/{chunk-MOA7PCJA.js → chunk-KFVFRVDK.js} +2 -2
  20. package/dist/chunks/{chunk-IZ6WAFPZ.js → chunk-L552VUSW.js} +2 -2
  21. package/dist/chunks/{chunk-TTOZFGDX.js → chunk-LOQRUMOE.js} +2 -2
  22. package/dist/chunks/{chunk-DJA3IN2X.js → chunk-O7SEN4RY.js} +2 -2
  23. package/dist/chunks/{chunk-PKUYGVBJ.js → chunk-QAHIBMRJ.js} +1513 -172
  24. package/dist/chunks/chunk-RKLHR2YE.js +152 -0
  25. package/dist/chunks/{chunk-XR64AS27.js → chunk-T4I25SRE.js} +66 -10
  26. package/dist/chunks/{chunk-C2V6DCWN.js → chunk-TIJBJ7EO.js} +2 -2
  27. package/dist/chunks/{chunk-YAOSNCGO.js → chunk-TJQZGB6S.js} +2 -2
  28. package/dist/chunks/{chunk-BT4S267X.js → chunk-TSUZWPXS.js} +4 -4
  29. package/dist/chunks/{chunk-C7WFNC2H.js → chunk-TVXUA533.js} +2 -2
  30. package/dist/chunks/{chunk-KSWKCPMW.js → chunk-UOYAPQ6P.js} +10 -14
  31. package/dist/chunks/{chunk-AQMLIXGD.js → chunk-WAGY7TO7.js} +1 -1
  32. package/dist/chunks/{chunk-ZINNI4TC.js → chunk-WWLVPUED.js} +1 -1
  33. package/dist/chunks/{chunk-OLXE4TRH.js → chunk-XC4VCXLN.js} +7 -7
  34. package/dist/chunks/{chunk-H33IJ7OP.js → chunk-XQUJUKTN.js} +1 -1
  35. package/dist/chunks/{chunk-OM5Z2KO5.js → chunk-ZTHVV4KB.js} +1 -1
  36. package/dist/chunks/{compile-vercel-config-TJYP77GR.js → compile-vercel-config-UMMPRYHE.js} +4 -4
  37. package/dist/chunks/{delete-KMJUZ2FR.js → delete-ZIUHVZKU.js} +6 -6
  38. package/dist/chunks/{disable-JNVD32GK.js → disable-3I6Y3PMB.js} +6 -6
  39. package/dist/chunks/{discard-IHJUBIIP.js → discard-P4QEYWQI.js} +6 -6
  40. package/dist/chunks/{edit-SHG24GD3.js → edit-C7W4II4F.js} +7 -7
  41. package/dist/chunks/{enable-BPPOFBS5.js → enable-YLFEOJHC.js} +6 -6
  42. package/dist/chunks/{export-NXMANIFJ.js → export-AEWPAFG5.js} +6 -6
  43. package/dist/chunks/{inspect-3QUNVUYY.js → inspect-UTKNO4PH.js} +8 -8
  44. package/dist/chunks/{list-DIFVR5IT.js → list-G2JFMLAP.js} +6 -6
  45. package/dist/chunks/{list-3EEABCQ5.js → list-K6T37XX7.js} +9 -9
  46. package/dist/chunks/{ls-W3EW6GXH.js → ls-SDUUITFJ.js} +8 -8
  47. package/dist/chunks/{publish-MJWCDLBZ.js → publish-CVDJGN4U.js} +6 -6
  48. package/dist/chunks/{query-C6RJSZM3.js → query-NZR7YNV5.js} +8 -8
  49. package/dist/chunks/{reorder-PPF7SVNU.js → reorder-XXHIOZ4E.js} +6 -6
  50. package/dist/chunks/{restore-EOJNTA2T.js → restore-SCM6T5BD.js} +6 -6
  51. package/dist/chunks/{rm-WEZ4K7UG.js → rm-I24CJRZY.js} +8 -8
  52. package/dist/chunks/{rule-inspect-PXCF73V3.js → rule-inspect-3K5RYFGG.js} +8 -8
  53. package/dist/chunks/{rules-DF7IFF4R.js → rules-T2VAUOFG.js} +8 -8
  54. package/dist/chunks/{schema-3UFDQZFG.js → schema-F6W32I35.js} +9 -9
  55. package/dist/chunks/{types-V6KTYGWP.js → types-LU2G5DD3.js} +4 -4
  56. package/dist/chunks/{update-FNAEWCUN.js → update-ZYQWTTCL.js} +8 -8
  57. package/dist/commands/build/index.js +534 -394
  58. package/dist/commands/deploy/index.js +23 -24
  59. package/dist/commands/dev/index.js +14 -14
  60. package/dist/commands/env/index.js +160 -95
  61. package/dist/commands/link/index.js +20 -21
  62. package/dist/commands/list/index.js +10 -10
  63. package/dist/commands-bulk.js +1503 -1277
  64. package/dist/index.js +20 -21
  65. package/dist/version.mjs +1 -1
  66. package/package.json +17 -17
  67. package/dist/chunks/chunk-76ZNZKIN.js +0 -17
  68. package/dist/chunks/chunk-HXXKDZQ6.js +0 -680
@@ -11,37 +11,34 @@ import {
11
11
  isLambda,
12
12
  staticFiles,
13
13
  writeBuildResult
14
- } from "../../chunks/chunk-XFSFHTAB.js";
14
+ } from "../../chunks/chunk-DDORH57D.js";
15
15
  import {
16
16
  require_semver
17
17
  } from "../../chunks/chunk-IB5L4LKZ.js";
18
18
  import {
19
19
  pullCommandLogic
20
- } from "../../chunks/chunk-OLXE4TRH.js";
20
+ } from "../../chunks/chunk-XC4VCXLN.js";
21
21
  import {
22
22
  pickOverrides,
23
23
  readProjectSettings
24
- } from "../../chunks/chunk-7O3VXZBW.js";
25
- import {
26
- ua_default
27
- } from "../../chunks/chunk-76ZNZKIN.js";
24
+ } from "../../chunks/chunk-K5ISROJF.js";
28
25
  import "../../chunks/chunk-N733ZD4W.js";
29
- import "../../chunks/chunk-BT4S267X.js";
26
+ import "../../chunks/chunk-TSUZWPXS.js";
30
27
  import {
31
28
  printProjectNotFoundError
32
- } from "../../chunks/chunk-TPCECDGK.js";
29
+ } from "../../chunks/chunk-FQ2EU7QM.js";
33
30
  import {
34
31
  AGENT_REASON,
35
32
  AGENT_STATUS
36
33
  } from "../../chunks/chunk-L6Q2EQPI.js";
37
- import "../../chunks/chunk-6PVIXIDG.js";
34
+ import "../../chunks/chunk-6PSM4YC3.js";
38
35
  import {
39
36
  buildCommand
40
- } from "../../chunks/chunk-HXXKDZQ6.js";
41
- import "../../chunks/chunk-C7WFNC2H.js";
37
+ } from "../../chunks/chunk-RKLHR2YE.js";
38
+ import "../../chunks/chunk-TVXUA533.js";
42
39
  import {
43
40
  help
44
- } from "../../chunks/chunk-TTOZFGDX.js";
41
+ } from "../../chunks/chunk-LOQRUMOE.js";
45
42
  import {
46
43
  DEFAULT_VERCEL_CONFIG_FILENAME,
47
44
  VERCEL_DIR,
@@ -61,26 +58,27 @@ import {
61
58
  require_main,
62
59
  require_minimatch,
63
60
  resolveProjectCwd,
61
+ ua_default,
64
62
  validateConfig
65
- } from "../../chunks/chunk-PKUYGVBJ.js";
63
+ } from "../../chunks/chunk-QAHIBMRJ.js";
66
64
  import {
67
65
  TelemetryClient
68
66
  } from "../../chunks/chunk-4CIXZOP4.js";
69
67
  import {
70
68
  outputAgentError
71
- } from "../../chunks/chunk-ULXHXZCZ.js";
69
+ } from "../../chunks/chunk-7OUZIPHA.js";
72
70
  import {
73
71
  stamp_default
74
72
  } from "../../chunks/chunk-CO5D46AG.js";
75
73
  import "../../chunks/chunk-N2T234LO.js";
76
- import "../../chunks/chunk-OM5Z2KO5.js";
74
+ import "../../chunks/chunk-ZTHVV4KB.js";
77
75
  import {
78
76
  getFlagsSpecification,
79
77
  getGlobalFlagsOnlyFromArgs,
80
78
  parseArguments,
81
79
  printError,
82
80
  toEnumerableError
83
- } from "../../chunks/chunk-H33IJ7OP.js";
81
+ } from "../../chunks/chunk-XQUJUKTN.js";
84
82
  import {
85
83
  CantParseJSONFile,
86
84
  cmd,
@@ -88,7 +86,7 @@ import {
88
86
  getCommandNamePlain,
89
87
  packageName,
90
88
  require_lib as require_lib2
91
- } from "../../chunks/chunk-UGXBNJMO.js";
89
+ } from "../../chunks/chunk-IDFKAJW3.js";
92
90
  import {
93
91
  pkg_default
94
92
  } from "../../chunks/chunk-P4QNYOFB.js";
@@ -121,7 +119,7 @@ import {
121
119
  FileBlob,
122
120
  FileFsRef,
123
121
  getDiscontinuedNodeVersions,
124
- getInstalledPackageVersion as getInstalledPackageVersion2,
122
+ getInstalledPackageVersion,
125
123
  getServiceUrlEnvVars,
126
124
  getExperimentalServiceUrlEnvVars,
127
125
  normalizePath,
@@ -427,7 +425,7 @@ function validatePackageManifest(data) {
427
425
  }
428
426
 
429
427
  // src/util/flags/build-embedding.ts
430
- import { getInstalledPackageVersion } from "@vercel/build-utils";
428
+ import { isPackageInstalled } from "@vercel/build-utils";
431
429
  function isFlagsEmbedOption(input) {
432
430
  return input === "force-on" || input === "force-off";
433
431
  }
@@ -449,9 +447,9 @@ async function shouldEmbedFlagsDefinitions(cwd) {
449
447
  if (envHasSdkKey()) {
450
448
  return true;
451
449
  }
452
- const vercelFlagsVersion = await getInstalledPackageVersion("@flags-sdk/vercel");
453
- const vercelFlagsCoreVersion = await getInstalledPackageVersion("@vercel/flags-core");
454
- if (vercelFlagsVersion || vercelFlagsCoreVersion) {
450
+ const hasVercelFlags = await isPackageInstalled("@flags-sdk/vercel", cwd);
451
+ const hasFlagsCore = await isPackageInstalled("@vercel/flags-core", cwd);
452
+ if (hasVercelFlags || hasFlagsCore) {
455
453
  return true;
456
454
  }
457
455
  return false;
@@ -463,6 +461,9 @@ function buildCommandWithGlobalFlags(baseSubcommand, argv) {
463
461
  const full = globalFlags.length ? `${baseSubcommand} ${globalFlags.join(" ")}` : baseSubcommand;
464
462
  return getCommandNamePlain(full);
465
463
  }
464
+ function hasNonEmptyObject(value) {
465
+ return value != null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length > 0;
466
+ }
466
467
  async function main(client) {
467
468
  const telemetryClient = new BuildTelemetryClient({
468
469
  opts: {
@@ -887,6 +888,10 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
887
888
  let zeroConfigRoutes = [];
888
889
  let zeroConfigFallbackRoutes = [];
889
890
  let detectedServices;
891
+ const hasExperimentalServicesConfiguredInVercelConfig = hasNonEmptyObject(
892
+ localConfig.experimentalServices
893
+ );
894
+ let detectedExperimentalServicesConfig;
890
895
  let isZeroConfig = false;
891
896
  if (builds.length > 0) {
892
897
  output_manager_default.warn(
@@ -951,7 +956,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
951
956
  zeroConfigFallbackRoutes = detectedBuilders.fallbackRoutes || [];
952
957
  }
953
958
  const builderSpecs = new Set(builds.map((b) => b.use));
954
- const buildersWithPkgs = await span.child("vc.importBuilders").trace(() => importBuilders(builderSpecs, cwd, span));
959
+ let buildersWithPkgs = await span.child("vc.importBuilders").trace(() => importBuilders(builderSpecs, cwd, span));
955
960
  const filesMap = {};
956
961
  for (const path of files) {
957
962
  const fsPath = join2(workPath, path);
@@ -961,31 +966,44 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
961
966
  const buildStamp = stamp_default();
962
967
  await import_fs_extra2.default.mkdirp(outputDir);
963
968
  const ops = [];
964
- const buildsJsonBuilds = new Map(
965
- builds.map((build) => {
969
+ const buildsJsonBuilds = /* @__PURE__ */ new Map();
970
+ const ensureBuildersImported = async (buildsToImport) => {
971
+ const missingBuilderSpecs = new Set(
972
+ buildsToImport.map((build) => build.use).filter((builderSpec) => !buildersWithPkgs.has(builderSpec))
973
+ );
974
+ if (missingBuilderSpecs.size === 0)
975
+ return;
976
+ const importedBuilders = await span.child("vc.importBuilders").trace(() => importBuilders(missingBuilderSpecs, cwd, span));
977
+ buildersWithPkgs = new Map([
978
+ ...buildersWithPkgs.entries(),
979
+ ...importedBuilders.entries()
980
+ ]);
981
+ };
982
+ const addBuildsToBuildJson = async (buildsToAdd) => {
983
+ await ensureBuildersImported(buildsToAdd);
984
+ for (const build of buildsToAdd) {
985
+ if (buildsJsonBuilds.has(build))
986
+ continue;
966
987
  const builderWithPkg = buildersWithPkgs.get(build.use);
967
988
  if (!builderWithPkg) {
968
989
  throw new Error(`Failed to load Builder "${build.use}"`);
969
990
  }
970
991
  const { builder, pkg: builderPkg } = builderWithPkg;
971
- return [
972
- build,
973
- {
974
- require: builderPkg.name,
975
- requirePath: builderWithPkg.path,
976
- apiVersion: builder.version,
977
- ...build
978
- }
979
- ];
980
- })
981
- );
982
- buildsJson.builds = Array.from(buildsJsonBuilds.values());
983
- await writeBuildJson(buildsJson, outputDir);
992
+ buildsJsonBuilds.set(build, {
993
+ require: builderPkg.name,
994
+ requirePath: builderWithPkg.path,
995
+ apiVersion: builder.version,
996
+ ...build
997
+ });
998
+ }
999
+ buildsJson.builds = Array.from(buildsJsonBuilds.values());
1000
+ await writeBuildJson(buildsJson, outputDir);
1001
+ };
984
1002
  const meta = {
985
1003
  skipDownload: true,
986
1004
  cliVersion: pkg_default.version
987
1005
  };
988
- const sortedBuilders = sortBuilders(builds);
1006
+ const executedBuilds = [];
989
1007
  const buildResults = /* @__PURE__ */ new Map();
990
1008
  const overrides = [];
991
1009
  const repoRootPath = cwd;
@@ -994,397 +1012,521 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
994
1012
  }
995
1013
  const diagnostics = {};
996
1014
  const packageManifests = [];
997
- const hasDetectedServices = detectedServices !== void 0 && detectedServices.length > 0;
998
- const hasQueueServices = hasDetectedServices && detectedServices.some(isQueueBackedService);
1015
+ const getHasDetectedServices = () => detectedServices !== void 0 && detectedServices.length > 0;
1016
+ const getHasQueueServices = () => getHasDetectedServices() && detectedServices.some(isQueueBackedService);
999
1017
  const synthesizedServiceCrons = [];
1000
1018
  const serviceByBuilder = /* @__PURE__ */ new Map();
1001
- if (hasDetectedServices) {
1019
+ if (getHasDetectedServices()) {
1002
1020
  for (const service of detectedServices) {
1003
1021
  serviceByBuilder.set(service.builder, service);
1004
1022
  }
1005
1023
  }
1006
1024
  const preDeployEntries = [];
1007
- for (const build of sortedBuilders) {
1008
- if (typeof build.src !== "string")
1009
- continue;
1010
- const builderWithPkg = buildersWithPkgs.get(build.use);
1011
- if (!builderWithPkg) {
1012
- throw new Error(`Failed to load Builder "${build.use}"`);
1013
- }
1014
- try {
1015
- const { builder, pkg: builderPkg } = builderWithPkg;
1016
- const service = hasDetectedServices ? serviceByBuilder.get(build) : void 0;
1017
- const stripServiceRoutePrefix = !!service?.routePrefix && service.routePrefix !== "/";
1018
- let buildWorkPath = workPath;
1019
- let buildEntrypoint = build.src;
1020
- let buildFiles = filesMap;
1021
- if (service && service.workspace !== ".") {
1022
- const wsPrefix = service.workspace + "/";
1023
- buildWorkPath = join2(workPath, service.workspace);
1024
- buildEntrypoint = build.src.startsWith(wsPrefix) ? build.src.slice(wsPrefix.length) : build.src;
1025
- buildFiles = {};
1026
- for (const [filePath, file] of Object.entries(filesMap)) {
1027
- if (filePath.startsWith(wsPrefix)) {
1028
- buildFiles[filePath.slice(wsPrefix.length)] = file;
1025
+ const runBuilders = async (buildsToRun) => {
1026
+ await addBuildsToBuildJson(buildsToRun);
1027
+ for (const build of sortBuilders(buildsToRun)) {
1028
+ if (typeof build.src !== "string")
1029
+ continue;
1030
+ const builderWithPkg = buildersWithPkgs.get(build.use);
1031
+ if (!builderWithPkg) {
1032
+ throw new Error(`Failed to load Builder "${build.use}"`);
1033
+ }
1034
+ try {
1035
+ const { builder, pkg: builderPkg } = builderWithPkg;
1036
+ const service = getHasDetectedServices() ? serviceByBuilder.get(build) : void 0;
1037
+ const stripServiceRoutePrefix = !!service?.routePrefix && service.routePrefix !== "/";
1038
+ let buildWorkPath = workPath;
1039
+ let buildEntrypoint = build.src;
1040
+ let buildFiles = filesMap;
1041
+ if (service && service.workspace !== ".") {
1042
+ const wsPrefix = service.workspace + "/";
1043
+ buildWorkPath = join2(workPath, service.workspace);
1044
+ buildEntrypoint = build.src.startsWith(wsPrefix) ? build.src.slice(wsPrefix.length) : build.src;
1045
+ buildFiles = {};
1046
+ for (const [filePath, file] of Object.entries(filesMap)) {
1047
+ if (filePath.startsWith(wsPrefix)) {
1048
+ buildFiles[filePath.slice(wsPrefix.length)] = file;
1049
+ }
1029
1050
  }
1051
+ output_manager_default.debug(
1052
+ `Service "${service.name}": workspace-rooted build at "${buildWorkPath}", entrypoint "${buildEntrypoint}" (original: "${build.src}")`
1053
+ );
1030
1054
  }
1031
- output_manager_default.debug(
1032
- `Service "${service.name}": workspace-rooted build at "${buildWorkPath}", entrypoint "${buildEntrypoint}" (original: "${build.src}")`
1033
- );
1034
- }
1035
- const settingsForEnv = service ? {
1036
- buildCommand: service.buildCommand ?? void 0,
1037
- installCommand: service.installCommand ?? void 0,
1038
- outputDirectory: projectSettings.outputDirectory ?? void 0,
1039
- nodeVersion: projectSettings.nodeVersion ?? void 0
1040
- } : projectSettings;
1041
- for (const key of [
1042
- "buildCommand",
1043
- "installCommand",
1044
- "outputDirectory",
1045
- "nodeVersion"
1046
- ]) {
1047
- const value = settingsForEnv[key];
1048
- const envKey = `VERCEL_PROJECT_SETTINGS_` + key.replace(/[A-Z]/g, (letter) => `_${letter}`).toUpperCase();
1049
- if (typeof value === "string") {
1050
- process.env[envKey] = value;
1051
- output_manager_default.debug(`Setting env ${envKey} to "${value}"`);
1052
- } else {
1053
- delete process.env[envKey];
1055
+ const settingsForEnv = service ? {
1056
+ buildCommand: service.buildCommand ?? void 0,
1057
+ installCommand: service.installCommand ?? void 0,
1058
+ outputDirectory: projectSettings.outputDirectory ?? void 0,
1059
+ nodeVersion: projectSettings.nodeVersion ?? void 0
1060
+ } : projectSettings;
1061
+ for (const key of [
1062
+ "buildCommand",
1063
+ "installCommand",
1064
+ "outputDirectory",
1065
+ "nodeVersion"
1066
+ ]) {
1067
+ const value = settingsForEnv[key];
1068
+ const envKey = `VERCEL_PROJECT_SETTINGS_` + key.replace(/[A-Z]/g, (letter) => `_${letter}`).toUpperCase();
1069
+ if (typeof value === "string") {
1070
+ process.env[envKey] = value;
1071
+ output_manager_default.debug(`Setting env ${envKey} to "${value}"`);
1072
+ } else {
1073
+ delete process.env[envKey];
1074
+ }
1054
1075
  }
1055
- }
1056
- const isFrontendBuilder = build.config && "framework" in build.config;
1057
- const builderFramework = build.config?.framework ?? projectSettings.framework;
1058
- let buildConfig;
1059
- if (isZeroConfig) {
1060
- if (service) {
1061
- buildConfig = {
1062
- ...build.config,
1063
- ...hasQueueServices ? { hasWorkerServices: true } : void 0,
1064
- // Override project-level settings with service-specific ones.
1065
- // The project-level framework is "services" which must NOT be
1066
- // propagated to individual builders.
1067
- projectSettings: {
1068
- ...projectSettings,
1069
- framework: service.framework ?? null,
1070
- buildCommand: service.buildCommand ?? null,
1071
- installCommand: service.installCommand ?? null
1072
- },
1073
- installCommand: service.installCommand ?? void 0,
1074
- buildCommand: service.buildCommand ?? void 0,
1075
- preDeployCommand: service.preDeployCommand ?? void 0,
1076
- framework: builderFramework,
1077
- nodeVersion: projectSettings.nodeVersion,
1078
- bunVersion: localConfig.bunVersion ?? void 0
1079
- };
1076
+ const isFrontendBuilder = build.config && "framework" in build.config;
1077
+ const builderFramework = build.config?.framework ?? projectSettings.framework;
1078
+ let buildConfig;
1079
+ if (isZeroConfig) {
1080
+ if (service) {
1081
+ buildConfig = {
1082
+ ...build.config,
1083
+ ...getHasQueueServices() ? { hasWorkerServices: true } : void 0,
1084
+ // Override project-level settings with service-specific ones.
1085
+ // The project-level framework is "services" which must NOT be
1086
+ // propagated to individual builders.
1087
+ projectSettings: {
1088
+ ...projectSettings,
1089
+ framework: service.framework ?? null,
1090
+ buildCommand: service.buildCommand ?? null,
1091
+ installCommand: service.installCommand ?? null
1092
+ },
1093
+ installCommand: service.installCommand ?? void 0,
1094
+ buildCommand: service.buildCommand ?? void 0,
1095
+ preDeployCommand: service.preDeployCommand ?? void 0,
1096
+ framework: builderFramework,
1097
+ nodeVersion: projectSettings.nodeVersion,
1098
+ bunVersion: localConfig.bunVersion ?? void 0
1099
+ };
1100
+ } else {
1101
+ buildConfig = {
1102
+ outputDirectory: projectSettings.outputDirectory ?? void 0,
1103
+ ...build.config,
1104
+ projectSettings,
1105
+ installCommand: projectSettings.installCommand ?? void 0,
1106
+ devCommand: projectSettings.devCommand ?? void 0,
1107
+ buildCommand: projectSettings.buildCommand ?? void 0,
1108
+ framework: projectSettings.framework,
1109
+ nodeVersion: projectSettings.nodeVersion,
1110
+ bunVersion: localConfig.bunVersion ?? void 0
1111
+ };
1112
+ }
1080
1113
  } else {
1081
1114
  buildConfig = {
1082
- outputDirectory: projectSettings.outputDirectory ?? void 0,
1083
- ...build.config,
1084
- projectSettings,
1085
- installCommand: projectSettings.installCommand ?? void 0,
1086
- devCommand: projectSettings.devCommand ?? void 0,
1087
- buildCommand: projectSettings.buildCommand ?? void 0,
1088
- framework: projectSettings.framework,
1089
- nodeVersion: projectSettings.nodeVersion,
1115
+ ...build.config || {},
1090
1116
  bunVersion: localConfig.bunVersion ?? void 0
1091
1117
  };
1092
1118
  }
1093
- } else {
1094
- buildConfig = {
1095
- ...build.config || {},
1096
- bunVersion: localConfig.bunVersion ?? void 0
1097
- };
1098
- }
1099
- const builderSpan = span.child("vc.builder", {
1100
- "builder.name": builderPkg.name,
1101
- "builder.version": builderPkg.version,
1102
- "builder.dynamicallyInstalled": String(
1103
- builderWithPkg.dynamicallyInstalled
1104
- )
1105
- });
1106
- const serviceRoutePrefix = build.config?.routePrefix;
1107
- const serviceWorkspace = build.config?.workspace;
1108
- const preDeployCmd = service?.preDeployCommand?.trim();
1109
- const preDeployEntry = preDeployCmd && service ? { service: service.name } : void 0;
1110
- if (preDeployEntry) {
1111
- preDeployEntries.push(preDeployEntry);
1112
- }
1113
- const buildOptions = {
1114
- files: buildFiles,
1115
- entrypoint: buildEntrypoint,
1116
- workPath: buildWorkPath,
1117
- repoRootPath,
1118
- config: buildConfig,
1119
- meta,
1120
- span: builderSpan,
1121
- ...preDeployCmd ? {
1122
- registerPreDeploy: (callback) => {
1123
- preDeployEntry.callback = callback;
1124
- }
1125
- } : void 0,
1126
- ...service ? {
1127
- service: {
1128
- name: service.name,
1129
- type: service.type,
1130
- trigger: service.trigger,
1131
- routePrefix: typeof serviceRoutePrefix === "string" ? serviceRoutePrefix : void 0,
1132
- workspace: typeof serviceWorkspace === "string" ? serviceWorkspace : void 0,
1133
- schedule: service.schedule
1134
- }
1135
- } : void 0
1136
- };
1137
- output_manager_default.debug(
1138
- `Building entrypoint "${build.src}" with "${builderPkg.name}"`
1139
- );
1140
- const restoreEnv = /* @__PURE__ */ new Map();
1141
- if (detectedServices && service?.env) {
1142
- const perServiceEnv = getServiceUrlEnvVars({
1143
- requestedEnv: service.env,
1144
- consumerService: service,
1145
- services: detectedServices,
1146
- frameworkList: import_frameworks2.frameworkList,
1147
- currentEnv: process.env,
1148
- deploymentUrl: process.env.VERCEL_URL
1119
+ const builderSpan = span.child("vc.builder", {
1120
+ "builder.name": builderPkg.name,
1121
+ "builder.version": builderPkg.version,
1122
+ "builder.dynamicallyInstalled": String(
1123
+ builderWithPkg.dynamicallyInstalled
1124
+ )
1149
1125
  });
1150
- for (const [key, value] of Object.entries(perServiceEnv)) {
1151
- if (key in process.env)
1152
- continue;
1153
- restoreEnv.set(key, process.env[key]);
1154
- process.env[key] = value;
1155
- output_manager_default.debug(`Injected service URL env var: ${key}=${value}`);
1156
- }
1157
- }
1158
- let buildResult;
1159
- let rawBuildResult;
1160
- try {
1161
- rawBuildResult = await builderSpan.trace(async () => builder.build(buildOptions));
1162
- if (builder.version === -1) {
1163
- const vx = rawBuildResult;
1164
- buildResult = vx.result;
1165
- } else {
1166
- buildResult = rawBuildResult;
1126
+ const serviceRoutePrefix = build.config?.routePrefix;
1127
+ const serviceWorkspace = build.config?.workspace;
1128
+ const preDeployCmd = service?.preDeployCommand?.trim();
1129
+ const preDeployEntry = preDeployCmd && service ? { service: service.name } : void 0;
1130
+ if (preDeployEntry) {
1131
+ preDeployEntries.push(preDeployEntry);
1167
1132
  }
1168
- if (!hasDetectedServices && buildConfig.zeroConfig && isFrontendBuilder && "output" in buildResult && !buildResult.routes) {
1169
- const framework2 = import_frameworks2.frameworkList.find(
1170
- (f) => f.slug === buildConfig.framework
1171
- );
1172
- if (framework2) {
1173
- const defaultRoutes = await getFrameworkRoutes(
1174
- framework2,
1175
- buildWorkPath
1176
- );
1177
- buildResult.routes = defaultRoutes;
1133
+ const buildOptions = {
1134
+ files: buildFiles,
1135
+ entrypoint: buildEntrypoint,
1136
+ workPath: buildWorkPath,
1137
+ repoRootPath,
1138
+ config: buildConfig,
1139
+ meta,
1140
+ span: builderSpan,
1141
+ ...preDeployCmd ? {
1142
+ registerPreDeploy: (callback) => {
1143
+ preDeployEntry.callback = callback;
1144
+ }
1145
+ } : void 0,
1146
+ ...service ? {
1147
+ service: {
1148
+ name: service.name,
1149
+ type: service.type,
1150
+ trigger: service.trigger,
1151
+ routePrefix: typeof serviceRoutePrefix === "string" ? serviceRoutePrefix : void 0,
1152
+ workspace: typeof serviceWorkspace === "string" ? serviceWorkspace : void 0,
1153
+ schedule: service.schedule
1154
+ }
1155
+ } : void 0
1156
+ };
1157
+ output_manager_default.debug(
1158
+ `Building entrypoint "${build.src}" with "${builderPkg.name}"`
1159
+ );
1160
+ const restoreEnv = /* @__PURE__ */ new Map();
1161
+ if (detectedServices && service?.env) {
1162
+ const perServiceEnv = getServiceUrlEnvVars({
1163
+ requestedEnv: service.env,
1164
+ consumerService: service,
1165
+ services: detectedServices,
1166
+ frameworkList: import_frameworks2.frameworkList,
1167
+ currentEnv: process.env,
1168
+ deploymentUrl: process.env.VERCEL_URL
1169
+ });
1170
+ for (const [key, value] of Object.entries(perServiceEnv)) {
1171
+ if (key in process.env)
1172
+ continue;
1173
+ restoreEnv.set(key, process.env[key]);
1174
+ process.env[key] = value;
1175
+ output_manager_default.debug(`Injected service URL env var: ${key}=${value}`);
1178
1176
  }
1179
1177
  }
1180
- } finally {
1181
- for (const [key, prior] of restoreEnv) {
1182
- if (prior === void 0) {
1183
- delete process.env[key];
1178
+ let buildResult;
1179
+ let rawBuildResult;
1180
+ try {
1181
+ rawBuildResult = await builderSpan.trace(async () => builder.build(buildOptions));
1182
+ if (builder.version === -1) {
1183
+ const vx = rawBuildResult;
1184
+ buildResult = vx.result;
1184
1185
  } else {
1185
- process.env[key] = prior;
1186
+ buildResult = rawBuildResult;
1186
1187
  }
1187
- }
1188
- try {
1189
- const builderDiagnostics = await builderSpan.child("vc.builder.diagnostics").trace(async () => {
1190
- return await builder.diagnostics?.(buildOptions);
1191
- });
1192
- if (builderDiagnostics) {
1193
- const prefix = service && service.workspace !== "." ? service.workspace + "/" + builderPkg.name + "/" : "";
1194
- for (const [key, value] of Object.entries(builderDiagnostics)) {
1195
- const fullKey = prefix + key;
1196
- if (key.endsWith("package-manifest.json")) {
1197
- try {
1198
- let data;
1199
- if (value.type === "FileBlob") {
1200
- data = value.data.toString();
1201
- } else {
1202
- data = await streamToString(value.toStream());
1203
- }
1204
- const packageManifest = JSON.parse(data);
1205
- const validationError = validatePackageManifest(packageManifest);
1206
- if (validationError) {
1207
- output_manager_default.warn(
1208
- `Invalid package-manifest.json from ${fullKey}: ${validationError}`
1188
+ if (!getHasDetectedServices() && buildConfig.zeroConfig && isFrontendBuilder && "output" in buildResult && !buildResult.routes) {
1189
+ const framework2 = import_frameworks2.frameworkList.find(
1190
+ (f) => f.slug === buildConfig.framework
1191
+ );
1192
+ if (framework2) {
1193
+ const defaultRoutes = await getFrameworkRoutes(
1194
+ framework2,
1195
+ buildWorkPath
1196
+ );
1197
+ buildResult.routes = defaultRoutes;
1198
+ }
1199
+ }
1200
+ } finally {
1201
+ for (const [key, prior] of restoreEnv) {
1202
+ if (prior === void 0) {
1203
+ delete process.env[key];
1204
+ } else {
1205
+ process.env[key] = prior;
1206
+ }
1207
+ }
1208
+ try {
1209
+ const builderDiagnostics = await builderSpan.child("vc.builder.diagnostics").trace(async () => {
1210
+ return await builder.diagnostics?.(buildOptions);
1211
+ });
1212
+ if (builderDiagnostics) {
1213
+ const prefix = service && service.workspace !== "." ? service.workspace + "/" + builderPkg.name + "/" : "";
1214
+ for (const [key, value] of Object.entries(builderDiagnostics)) {
1215
+ const fullKey = prefix + key;
1216
+ if (key.endsWith("package-manifest.json")) {
1217
+ try {
1218
+ let data;
1219
+ if (value.type === "FileBlob") {
1220
+ data = value.data.toString();
1221
+ } else {
1222
+ data = await streamToString(value.toStream());
1223
+ }
1224
+ const packageManifest = JSON.parse(data);
1225
+ const validationError = validatePackageManifest(packageManifest);
1226
+ if (validationError) {
1227
+ output_manager_default.warn(
1228
+ `Invalid package-manifest.json from ${fullKey}: ${validationError}`
1229
+ );
1230
+ } else {
1231
+ const workspace = service && service.workspace !== "." ? service.workspace : ".";
1232
+ packageManifests.push({
1233
+ workspace,
1234
+ key: fullKey,
1235
+ manifest: packageManifest,
1236
+ service,
1237
+ builderUse: builderPkg.name
1238
+ });
1239
+ }
1240
+ } catch (e) {
1241
+ output_manager_default.debug(
1242
+ `Failed to parse ${fullKey}: ${e instanceof Error ? e.message : String(e)}`
1209
1243
  );
1210
- } else {
1211
- const workspace = service && service.workspace !== "." ? service.workspace : ".";
1212
- packageManifests.push({
1213
- workspace,
1214
- key: fullKey,
1215
- manifest: packageManifest,
1216
- service,
1217
- builderUse: builderPkg.name
1218
- });
1219
1244
  }
1220
- } catch (e) {
1221
- output_manager_default.debug(
1222
- `Failed to parse ${fullKey}: ${e instanceof Error ? e.message : String(e)}`
1223
- );
1245
+ } else {
1246
+ diagnostics[fullKey] = value;
1224
1247
  }
1225
- } else {
1226
- diagnostics[fullKey] = value;
1227
1248
  }
1228
1249
  }
1250
+ } catch (error) {
1251
+ output_manager_default.error("Collecting diagnostics failed");
1252
+ output_manager_default.debug(error);
1229
1253
  }
1230
- } catch (error) {
1231
- output_manager_default.error("Collecting diagnostics failed");
1232
- output_manager_default.debug(error);
1233
1254
  }
1234
- }
1235
- if (buildResult && "output" in buildResult && "runtime" in buildResult.output && "type" in buildResult.output && buildResult.output.type === "Lambda") {
1236
- const lambdaRuntime = buildResult.output.runtime;
1237
- if (getDiscontinuedNodeVersions().some((o) => o.runtime === lambdaRuntime)) {
1238
- throw new NowBuildError2({
1239
- code: "NODEJS_DISCONTINUED_VERSION",
1240
- message: `The Runtime "${build.use}" is using "${lambdaRuntime}", which is discontinued. Please upgrade your Runtime to a more recent version or consult the author for more details.`,
1241
- link: "https://vercel.link/function-runtimes"
1242
- });
1255
+ if (buildResult && "output" in buildResult && "runtime" in buildResult.output && "type" in buildResult.output && buildResult.output.type === "Lambda") {
1256
+ const lambdaRuntime = buildResult.output.runtime;
1257
+ if (getDiscontinuedNodeVersions().some((o) => o.runtime === lambdaRuntime)) {
1258
+ throw new NowBuildError2({
1259
+ code: "NODEJS_DISCONTINUED_VERSION",
1260
+ message: `The Runtime "${build.use}" is using "${lambdaRuntime}", which is discontinued. Please upgrade your Runtime to a more recent version or consult the author for more details.`,
1261
+ link: "https://vercel.link/function-runtimes"
1262
+ });
1263
+ }
1243
1264
  }
1244
- }
1245
- if ("output" in buildResult && buildResult.output && (isBackendBuilder(build) || build.use === "@vercel/python")) {
1246
- const routesJsonPath = join2(buildWorkPath, ".vercel", "routes.json");
1247
- if ((0, import_fs_extra2.existsSync)(routesJsonPath)) {
1248
- try {
1249
- const routesJson = await readJSONFile(routesJsonPath);
1250
- if (routesJson && typeof routesJson === "object" && "routes" in routesJson && Array.isArray(routesJson.routes)) {
1251
- const indexLambda = "index" in buildResult.output ? buildResult.output["index"] : void 0;
1252
- const convertedRoutes = [];
1253
- const convertedOutputs = indexLambda ? { index: indexLambda } : {};
1254
- for (const route of routesJson.routes) {
1255
- if (typeof route.source !== "string") {
1256
- continue;
1257
- }
1258
- const { src } = (0, import_routing_utils2.sourceToRegex)(route.source);
1259
- const newRoute = {
1260
- src,
1261
- dest: route.source
1262
- };
1263
- if (route.methods) {
1264
- newRoute.methods = route.methods;
1265
- }
1266
- if (route.source === "/") {
1267
- continue;
1265
+ if ("output" in buildResult && buildResult.output && (isBackendBuilder(build) || build.use === "@vercel/python")) {
1266
+ const routesJsonPath = join2(buildWorkPath, ".vercel", "routes.json");
1267
+ if ((0, import_fs_extra2.existsSync)(routesJsonPath)) {
1268
+ try {
1269
+ const routesJson = await readJSONFile(routesJsonPath);
1270
+ if (routesJson && typeof routesJson === "object" && "routes" in routesJson && Array.isArray(routesJson.routes)) {
1271
+ const indexLambda = "index" in buildResult.output ? buildResult.output["index"] : void 0;
1272
+ const convertedRoutes = [];
1273
+ const convertedOutputs = indexLambda ? { index: indexLambda } : {};
1274
+ for (const route of routesJson.routes) {
1275
+ if (typeof route.source !== "string") {
1276
+ continue;
1277
+ }
1278
+ const { src } = (0, import_routing_utils2.sourceToRegex)(route.source);
1279
+ const newRoute = {
1280
+ src,
1281
+ dest: route.source
1282
+ };
1283
+ if (route.methods) {
1284
+ newRoute.methods = route.methods;
1285
+ }
1286
+ if (route.source === "/") {
1287
+ continue;
1288
+ }
1289
+ if (indexLambda) {
1290
+ convertedOutputs[route.source] = indexLambda;
1291
+ }
1292
+ convertedRoutes.push(newRoute);
1268
1293
  }
1294
+ buildResult.routes = [
1295
+ { handle: "filesystem" },
1296
+ ...convertedRoutes,
1297
+ { src: "/(.*)", dest: "/" }
1298
+ ];
1269
1299
  if (indexLambda) {
1270
- convertedOutputs[route.source] = indexLambda;
1300
+ buildResult.output = convertedOutputs;
1271
1301
  }
1272
- convertedRoutes.push(newRoute);
1273
- }
1274
- buildResult.routes = [
1275
- { handle: "filesystem" },
1276
- ...convertedRoutes,
1277
- { src: "/(.*)", dest: "/" }
1278
- ];
1279
- if (indexLambda) {
1280
- buildResult.output = convertedOutputs;
1281
1302
  }
1303
+ } catch (error) {
1304
+ output_manager_default.error(`Failed to read routes.json: ${error}`);
1282
1305
  }
1283
- } catch (error) {
1284
- output_manager_default.error(`Failed to read routes.json: ${error}`);
1285
1306
  }
1286
1307
  }
1287
- }
1288
- if (hasDetectedServices && service && "routes" in buildResult && Array.isArray(buildResult.routes) && detectedServices) {
1289
- buildResult.routes = scopeRoutesToServiceOwnership({
1290
- routes: buildResult.routes,
1291
- owner: service,
1292
- allServices: detectedServices
1293
- });
1294
- }
1295
- if (service && isQueueBackedService(service) && "output" in buildResult) {
1296
- attachQueueServiceTrigger(buildResult.output, service);
1297
- }
1298
- if (service && isScheduleTriggeredService(service) && !("crons" in buildResult && buildResult.crons?.length)) {
1299
- const staticSchedules = getStaticServiceSchedules(service.schedule);
1300
- if (typeof service.runtime === "string" && staticSchedules.length > 0) {
1301
- const cronEntrypoint = service.entrypoint || service.builder.src || "index";
1302
- for (const schedule of staticSchedules) {
1303
- synthesizedServiceCrons.push({
1304
- path: getInternalServiceCronPath(
1305
- service.name,
1306
- cronEntrypoint,
1307
- service.handlerFunction || "cron"
1308
- ),
1309
- schedule
1310
- });
1311
- }
1312
- } else {
1313
- throw new NowBuildError2({
1314
- code: "CRON_SERVICE_NO_CRONS",
1315
- message: `Scheduled service "${service.name}" did not produce any cron entries. The builder "${builderPkg.name}" may not support scheduled services.`
1308
+ if (getHasDetectedServices() && service && "routes" in buildResult && Array.isArray(buildResult.routes) && detectedServices) {
1309
+ buildResult.routes = scopeRoutesToServiceOwnership({
1310
+ routes: buildResult.routes,
1311
+ owner: service,
1312
+ allServices: detectedServices
1316
1313
  });
1317
1314
  }
1318
- }
1319
- let mergedBuildResult = buildResult;
1320
- if ("buildOutputPath" in buildResult) {
1321
- const buildOutputConfigPath = join2(
1322
- buildResult.buildOutputPath,
1323
- "config.json"
1324
- );
1325
- const buildOutputConfig = await readJSONFile(
1326
- buildOutputConfigPath
1327
- );
1328
- if (buildOutputConfig instanceof CantParseJSONFile) {
1329
- throw buildOutputConfig;
1315
+ if (service && isQueueBackedService(service) && "output" in buildResult) {
1316
+ attachQueueServiceTrigger(buildResult.output, service);
1330
1317
  }
1331
- if (buildOutputConfig) {
1332
- if (buildOutputConfig.overrides) {
1333
- overrides.push(buildOutputConfig.overrides);
1334
- }
1335
- if (hasDetectedServices && service && Array.isArray(buildOutputConfig.routes) && detectedServices) {
1336
- buildOutputConfig.routes = scopeRoutesToServiceOwnership({
1337
- routes: buildOutputConfig.routes,
1338
- owner: service,
1339
- allServices: detectedServices
1318
+ if (service && isScheduleTriggeredService(service) && !("crons" in buildResult && buildResult.crons?.length)) {
1319
+ const staticSchedules = getStaticServiceSchedules(service.schedule);
1320
+ if (typeof service.runtime === "string" && staticSchedules.length > 0) {
1321
+ const cronEntrypoint = service.entrypoint || service.builder.src || "index";
1322
+ for (const schedule of staticSchedules) {
1323
+ synthesizedServiceCrons.push({
1324
+ path: getInternalServiceCronPath(
1325
+ service.name,
1326
+ cronEntrypoint,
1327
+ service.handlerFunction || "cron"
1328
+ ),
1329
+ schedule
1330
+ });
1331
+ }
1332
+ } else {
1333
+ throw new NowBuildError2({
1334
+ code: "CRON_SERVICE_NO_CRONS",
1335
+ message: `Scheduled service "${service.name}" did not produce any cron entries. The builder "${builderPkg.name}" may not support scheduled services.`
1340
1336
  });
1341
1337
  }
1342
- mergedBuildResult = buildOutputConfig;
1343
1338
  }
1339
+ let mergedBuildResult = buildResult;
1340
+ if ("buildOutputPath" in buildResult) {
1341
+ const buildOutputConfigPath = join2(
1342
+ buildResult.buildOutputPath,
1343
+ "config.json"
1344
+ );
1345
+ const buildOutputConfig = await readJSONFile(
1346
+ buildOutputConfigPath
1347
+ );
1348
+ if (buildOutputConfig instanceof CantParseJSONFile) {
1349
+ throw buildOutputConfig;
1350
+ }
1351
+ if (buildOutputConfig) {
1352
+ if (!hasExperimentalServicesConfiguredInVercelConfig) {
1353
+ const outputConfigPath = join2(outputDir, "config.json");
1354
+ const outputConfig = await readJSONFile(outputConfigPath);
1355
+ if (outputConfig instanceof CantParseJSONFile) {
1356
+ throw outputConfig;
1357
+ }
1358
+ if (hasNonEmptyObject(outputConfig?.experimentalServices) && !hasNonEmptyObject(buildOutputConfig.experimentalServices)) {
1359
+ buildOutputConfig.experimentalServices = outputConfig.experimentalServices;
1360
+ await import_fs_extra2.default.writeJSON(buildOutputConfigPath, buildOutputConfig, {
1361
+ spaces: 2
1362
+ });
1363
+ }
1364
+ }
1365
+ if (buildOutputConfig.overrides) {
1366
+ overrides.push(buildOutputConfig.overrides);
1367
+ }
1368
+ if (getHasDetectedServices() && service && Array.isArray(buildOutputConfig.routes) && detectedServices) {
1369
+ buildOutputConfig.routes = scopeRoutesToServiceOwnership({
1370
+ routes: buildOutputConfig.routes,
1371
+ owner: service,
1372
+ allServices: detectedServices
1373
+ });
1374
+ }
1375
+ mergedBuildResult = buildOutputConfig;
1376
+ }
1377
+ }
1378
+ buildResults.set(build, mergedBuildResult);
1379
+ executedBuilds.push(build);
1380
+ let buildOutputLength = 0;
1381
+ if ("output" in buildResult) {
1382
+ buildOutputLength = Array.isArray(buildResult.output) ? buildResult.output.length : 1;
1383
+ }
1384
+ ops.push(
1385
+ builderSpan.child("vc.builder.writeBuildResult", {
1386
+ buildOutputLength: String(buildOutputLength)
1387
+ }).trace(
1388
+ () => writeBuildResult({
1389
+ repoRootPath,
1390
+ outputDir,
1391
+ buildResult: rawBuildResult,
1392
+ build,
1393
+ builder,
1394
+ builderPkg,
1395
+ vercelConfig: localConfig,
1396
+ standalone,
1397
+ workPath: buildWorkPath,
1398
+ service,
1399
+ stripServiceRoutePrefix
1400
+ })
1401
+ ).then(
1402
+ (override) => {
1403
+ if (override)
1404
+ overrides.push(override);
1405
+ },
1406
+ (err) => err
1407
+ )
1408
+ );
1409
+ } catch (err) {
1410
+ const buildJsonBuild = buildsJsonBuilds.get(build);
1411
+ if (buildJsonBuild) {
1412
+ buildJsonBuild.error = toEnumerableError(err);
1413
+ }
1414
+ throw err;
1415
+ } finally {
1416
+ ops.push(
1417
+ download(diagnostics, join2(outputDir, "diagnostics")).then(
1418
+ () => void 0,
1419
+ (err) => err
1420
+ )
1421
+ );
1344
1422
  }
1345
- buildResults.set(build, mergedBuildResult);
1346
- let buildOutputLength = 0;
1347
- if ("output" in buildResult) {
1348
- buildOutputLength = Array.isArray(buildResult.output) ? buildResult.output.length : 1;
1423
+ }
1424
+ };
1425
+ const flushOps = async () => {
1426
+ const errors = await Promise.all(ops.splice(0));
1427
+ for (const error of errors) {
1428
+ if (error) {
1429
+ throw error;
1349
1430
  }
1350
- ops.push(
1351
- builderSpan.child("vc.builder.writeBuildResult", {
1352
- buildOutputLength: String(buildOutputLength)
1353
- }).trace(
1354
- () => writeBuildResult({
1355
- repoRootPath,
1356
- outputDir,
1357
- buildResult: rawBuildResult,
1358
- build,
1359
- builder,
1360
- builderPkg,
1361
- vercelConfig: localConfig,
1362
- standalone,
1363
- workPath: buildWorkPath,
1364
- service,
1365
- stripServiceRoutePrefix
1366
- })
1367
- ).then(
1368
- (override) => {
1369
- if (override)
1370
- overrides.push(override);
1371
- },
1372
- (err) => err
1373
- )
1431
+ }
1432
+ };
1433
+ const normalizeBuilderSrc = (src) => typeof src === "string" ? normalizePath(src).replace(/^\.\//, "") : void 0;
1434
+ const getBuilderIdentity = (build) => {
1435
+ const normalizedSrc = normalizeBuilderSrc(build.src);
1436
+ return normalizedSrc ? `${build.use}:${normalizedSrc}` : void 0;
1437
+ };
1438
+ const getAlreadyExecutedBuild = (candidate) => {
1439
+ const candidateIdentity = getBuilderIdentity(candidate);
1440
+ if (!candidateIdentity)
1441
+ return void 0;
1442
+ return executedBuilds.find(
1443
+ (build) => getBuilderIdentity(build) === candidateIdentity
1444
+ );
1445
+ };
1446
+ const appendServiceRoutes = (services) => {
1447
+ const serviceRoutes = (0, import_fs_detectors2.generateServicesRoutes)(services);
1448
+ zeroConfigRoutes = (0, import_routing_utils2.appendRoutesToPhase)({
1449
+ routes: zeroConfigRoutes,
1450
+ newRoutes: serviceRoutes.hostRewrites.length ? serviceRoutes.hostRewrites : null,
1451
+ phase: null
1452
+ });
1453
+ zeroConfigRoutes.push(
1454
+ ...(0, import_routing_utils2.appendRoutesToPhase)({
1455
+ routes: [],
1456
+ newRoutes: [
1457
+ ...serviceRoutes.rewrites,
1458
+ ...serviceRoutes.workers,
1459
+ ...serviceRoutes.crons
1460
+ ],
1461
+ phase: "filesystem"
1462
+ })
1463
+ );
1464
+ zeroConfigRoutes.push(...serviceRoutes.defaults);
1465
+ zeroConfigFallbackRoutes.push(...serviceRoutes.fallbacks);
1466
+ };
1467
+ await runBuilders(builds);
1468
+ await flushOps();
1469
+ if (!hasExperimentalServicesConfiguredInVercelConfig) {
1470
+ const generatedConfigPath = join2(outputDir, "config.json");
1471
+ const generatedConfig = await readJSONFile(generatedConfigPath);
1472
+ if (generatedConfig instanceof CantParseJSONFile) {
1473
+ throw generatedConfig;
1474
+ }
1475
+ if (hasNonEmptyObject(generatedConfig?.experimentalServices)) {
1476
+ detectedExperimentalServicesConfig = generatedConfig.experimentalServices;
1477
+ const generatedBuilders = await span.child("vc.detectGeneratedServices").trace(
1478
+ () => (0, import_fs_detectors2.detectBuilders)(files, pkg, {
1479
+ ...localConfig,
1480
+ services: void 0,
1481
+ experimentalServices: generatedConfig.experimentalServices,
1482
+ projectSettings,
1483
+ ignoreBuildScript: true,
1484
+ featHandleMiss: true,
1485
+ workPath
1486
+ })
1374
1487
  );
1375
- } catch (err) {
1376
- const buildJsonBuild = buildsJsonBuilds.get(build);
1377
- if (buildJsonBuild) {
1378
- buildJsonBuild.error = toEnumerableError(err);
1488
+ if (generatedBuilders.errors && generatedBuilders.errors.length > 0) {
1489
+ throw generatedBuilders.errors[0];
1490
+ }
1491
+ for (const w of generatedBuilders.warnings) {
1492
+ output_manager_default.warn(w.message, null, w.link, w.action || "Learn More");
1493
+ }
1494
+ detectedServices = generatedBuilders.services;
1495
+ if (!detectedServices || detectedServices.length === 0) {
1496
+ detectedServices = void 0;
1497
+ } else {
1498
+ appendServiceRoutes(detectedServices);
1499
+ }
1500
+ if (detectedServices && generatedBuilders.useImplicitEnvInjection) {
1501
+ const serviceUrlEnvVars = getExperimentalServiceUrlEnvVars({
1502
+ services: detectedServices,
1503
+ frameworkList: import_frameworks2.frameworkList,
1504
+ currentEnv: process.env,
1505
+ deploymentUrl: process.env.VERCEL_URL
1506
+ });
1507
+ for (const [key, value] of Object.entries(serviceUrlEnvVars)) {
1508
+ process.env[key] = value;
1509
+ output_manager_default.debug(`Injected service URL env var: ${key}=${value}`);
1510
+ }
1511
+ }
1512
+ const buildsToRun = [];
1513
+ const seenBuildsToRun = /* @__PURE__ */ new Set();
1514
+ for (const service of detectedServices || []) {
1515
+ serviceByBuilder.set(service.builder, service);
1516
+ const alreadyExecutedBuild = getAlreadyExecutedBuild(service.builder);
1517
+ if (alreadyExecutedBuild) {
1518
+ serviceByBuilder.set(alreadyExecutedBuild, service);
1519
+ continue;
1520
+ }
1521
+ const serviceBuilderIdentity = getBuilderIdentity(service.builder);
1522
+ if (serviceBuilderIdentity && !seenBuildsToRun.has(serviceBuilderIdentity)) {
1523
+ seenBuildsToRun.add(serviceBuilderIdentity);
1524
+ buildsToRun.push(service.builder);
1525
+ }
1526
+ }
1527
+ if (buildsToRun.length > 0) {
1528
+ await runBuilders(buildsToRun);
1379
1529
  }
1380
- throw err;
1381
- } finally {
1382
- ops.push(
1383
- download(diagnostics, join2(outputDir, "diagnostics")).then(
1384
- () => void 0,
1385
- (err) => err
1386
- )
1387
- );
1388
1530
  }
1389
1531
  }
1390
1532
  for (const entry of preDeployEntries) {
@@ -1434,14 +1576,9 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1434
1576
  cleanupCorepack(corepackShimDir);
1435
1577
  }
1436
1578
  const collectSpan = span.child("vc.finalizeBuildOutput");
1437
- const errors = await Promise.all(ops);
1438
- for (const error of errors) {
1439
- if (error) {
1440
- throw error;
1441
- }
1442
- }
1579
+ await flushOps();
1443
1580
  let needBuildsJsonOverride = false;
1444
- const speedInsightsVersion = await getInstalledPackageVersion2(
1581
+ const speedInsightsVersion = await getInstalledPackageVersion(
1445
1582
  "@vercel/speed-insights"
1446
1583
  );
1447
1584
  if (speedInsightsVersion) {
@@ -1451,7 +1588,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1451
1588
  };
1452
1589
  needBuildsJsonOverride = true;
1453
1590
  }
1454
- const webAnalyticsVersion = await getInstalledPackageVersion2("@vercel/analytics");
1591
+ const webAnalyticsVersion = await getInstalledPackageVersion("@vercel/analytics");
1455
1592
  if (webAnalyticsVersion) {
1456
1593
  buildsJson.features = {
1457
1594
  ...buildsJson.features ?? {},
@@ -1495,7 +1632,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1495
1632
  const build = b[0];
1496
1633
  const buildResult = b[1];
1497
1634
  let entrypoint = build.src;
1498
- if (hasDetectedServices && typeof build.src === "string") {
1635
+ if (getHasDetectedServices() && typeof build.src === "string") {
1499
1636
  const service = serviceByBuilder.get(build);
1500
1637
  if (service && service.type === "web" && typeof service.routePrefix === "string") {
1501
1638
  entrypoint = getServicesMergeEntrypoint(service, build.src);
@@ -1562,7 +1699,10 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1562
1699
  overrides: mergedOverrides,
1563
1700
  framework,
1564
1701
  crons: mergedCrons,
1565
- ...detectedServices && detectedServices.length > 0 && { services: detectedServices },
1702
+ ...detectedExperimentalServicesConfig && Object.keys(detectedExperimentalServicesConfig).length > 0 && {
1703
+ experimentalServices: detectedExperimentalServicesConfig
1704
+ },
1705
+ ...!detectedExperimentalServicesConfig && detectedServices && detectedServices.length > 0 && { services: detectedServices },
1566
1706
  ...mergedDeploymentId && { deploymentId: mergedDeploymentId }
1567
1707
  };
1568
1708
  await import_fs_extra2.default.writeJSON(join2(outputDir, "config.json"), config, { spaces: 2 });