vercel 54.6.0 → 54.6.1

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