vercel 54.9.0 → 54.10.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 (57) hide show
  1. package/dist/chunks/{add-PFVGXHF2.js → add-5DY5F6KR.js} +5 -5
  2. package/dist/chunks/{chunk-BLSNH6GW.js → chunk-3QEUKH37.js} +1 -1
  3. package/dist/chunks/{chunk-ZEG75UDS.js → chunk-6B7TYTF6.js} +4 -4
  4. package/dist/chunks/{chunk-MHQ3YMRD.js → chunk-6ESIT3CL.js} +1 -1
  5. package/dist/chunks/{chunk-2KRTC3Z6.js → chunk-6UWHSMGM.js} +2 -2
  6. package/dist/chunks/{chunk-PQ6FQ427.js → chunk-7V42ARD4.js} +6 -6
  7. package/dist/chunks/{chunk-5QPKXSAQ.js → chunk-ERHL5CQY.js} +80 -12
  8. package/dist/chunks/{chunk-QED7VSDY.js → chunk-GPBBIDQ5.js} +1 -1
  9. package/dist/chunks/{chunk-CNZVD6AY.js → chunk-GSR2GQLJ.js} +2247 -191
  10. package/dist/chunks/{chunk-WHVOX5C7.js → chunk-IUBY6GNH.js} +1 -1
  11. package/dist/chunks/{chunk-DPXUXH7G.js → chunk-J5273CSE.js} +2 -2
  12. package/dist/chunks/{chunk-XK2FJELV.js → chunk-J763BFOA.js} +1 -1
  13. package/dist/chunks/{chunk-4XMJHCJ5.js → chunk-JK7NBOHR.js} +1 -1
  14. package/dist/chunks/{chunk-RM5VGLCD.js → chunk-LFHOOCSD.js} +2 -2
  15. package/dist/chunks/{chunk-GHIWUCX4.js → chunk-MBDHDIBC.js} +6 -6
  16. package/dist/chunks/{chunk-FRCPMIYP.js → chunk-PAB6JAI7.js} +1 -1
  17. package/dist/chunks/{chunk-KV23GR7J.js → chunk-PV533MBH.js} +1 -1
  18. package/dist/chunks/{chunk-3XKN4LMN.js → chunk-R3OUWO35.js} +10 -3
  19. package/dist/chunks/{chunk-2LJ4CNBS.js → chunk-SHWTWKFP.js} +130 -95
  20. package/dist/chunks/{chunk-ZBDCE356.js → chunk-TMD7R76P.js} +1 -1
  21. package/dist/chunks/{chunk-5ZJHY4AC.js → chunk-VNUNCNPE.js} +1 -1
  22. package/dist/chunks/{chunk-AW3VO6AO.js → chunk-WBFTHBNH.js} +1 -1
  23. package/dist/chunks/{chunk-TAHQ6VAS.js → chunk-WFRHKZFI.js} +2 -1
  24. package/dist/chunks/{chunk-BBJUIDZF.js → chunk-YI3JV6GM.js} +3 -3
  25. package/dist/chunks/{chunk-27O5ZTLD.js → chunk-YSBVITVJ.js} +8 -5
  26. package/dist/chunks/{compile-vercel-config-7U2LIW43.js → compile-vercel-config-E3BX5VFO.js} +2 -2
  27. package/dist/chunks/{delete-DE3UHP2L.js → delete-RKFK2KFA.js} +4 -4
  28. package/dist/chunks/{disable-B6GG7O7J.js → disable-RD33Y4KE.js} +4 -4
  29. package/dist/chunks/{discard-MGA5ZYKO.js → discard-ITS7653Z.js} +4 -4
  30. package/dist/chunks/{edit-L4Y2YIBV.js → edit-ANQBSFXA.js} +6 -6
  31. package/dist/chunks/{enable-O7FEPQAF.js → enable-7WGWM77Y.js} +4 -4
  32. package/dist/chunks/{exec-JSOL4CYJ.js → exec-HI4HF4GY.js} +1 -1
  33. package/dist/chunks/{export-UB7HUJAY.js → export-VTGALJ7L.js} +4 -4
  34. package/dist/chunks/{inspect-IV2WSOKU.js → inspect-3CNYVFQE.js} +4 -4
  35. package/dist/chunks/{list-IRG73TQ7.js → list-B4QVO4HZ.js} +4 -4
  36. package/dist/chunks/{list-7S77FPG6.js → list-G634SMGU.js} +3 -3
  37. package/dist/chunks/{ls-FP6I5BJ4.js → ls-OY7LDCQP.js} +5 -5
  38. package/dist/chunks/{publish-ZEXEMS6A.js → publish-VATWAP53.js} +4 -4
  39. package/dist/chunks/{query-F5RJNYCZ.js → query-S26UM5S4.js} +3 -3
  40. package/dist/chunks/{reorder-JJY5X5NU.js → reorder-7WO5ZX6S.js} +4 -4
  41. package/dist/chunks/{restore-753XEXA7.js → restore-WXOV5IWA.js} +4 -4
  42. package/dist/chunks/{rm-5DVLPTLD.js → rm-FT6BU2BM.js} +5 -5
  43. package/dist/chunks/{routes-3OHKNMGT.js → routes-EAMQVFU2.js} +2 -2
  44. package/dist/chunks/{rule-inspect-BA25TI3G.js → rule-inspect-7WQCBK25.js} +5 -5
  45. package/dist/chunks/{rules-JL4NLPIC.js → rules-J5RKONBR.js} +6 -6
  46. package/dist/chunks/{schema-NL2KEDWL.js → schema-7W6TY5ST.js} +3 -3
  47. package/dist/chunks/{update-3LTUTJJB.js → update-GKAXCULF.js} +5 -5
  48. package/dist/commands/build/index.js +334 -110
  49. package/dist/commands/deploy/index.js +13 -13
  50. package/dist/commands/dev/index.js +40 -18
  51. package/dist/commands/env/index.js +8 -8
  52. package/dist/commands/link/index.js +10 -10
  53. package/dist/commands/list/index.js +5 -5
  54. package/dist/commands-bulk.js +697 -89
  55. package/dist/index.js +12 -12
  56. package/dist/version.mjs +1 -1
  57. package/package.json +20 -20
@@ -9,36 +9,37 @@ import {
9
9
  getStaticServiceSchedules,
10
10
  importBuilders,
11
11
  isLambda,
12
+ relocateRootBuildOutputToService,
12
13
  staticFiles,
13
14
  writeBuildResult
14
- } from "../../chunks/chunk-5QPKXSAQ.js";
15
+ } from "../../chunks/chunk-ERHL5CQY.js";
15
16
  import {
16
17
  require_semver
17
18
  } from "../../chunks/chunk-IB5L4LKZ.js";
18
19
  import {
19
20
  pullCommandLogic
20
- } from "../../chunks/chunk-PQ6FQ427.js";
21
+ } from "../../chunks/chunk-7V42ARD4.js";
21
22
  import {
22
23
  pickOverrides,
23
24
  readProjectSettings
24
- } from "../../chunks/chunk-FRCPMIYP.js";
25
- import "../../chunks/chunk-BBJUIDZF.js";
26
- import "../../chunks/chunk-2KRTC3Z6.js";
25
+ } from "../../chunks/chunk-PAB6JAI7.js";
26
+ import "../../chunks/chunk-YI3JV6GM.js";
27
+ import "../../chunks/chunk-6UWHSMGM.js";
27
28
  import {
28
29
  printProjectNotFoundError
29
- } from "../../chunks/chunk-27O5ZTLD.js";
30
+ } from "../../chunks/chunk-YSBVITVJ.js";
30
31
  import {
31
32
  AGENT_REASON,
32
33
  AGENT_STATUS
33
34
  } from "../../chunks/chunk-LJ5WXXG6.js";
34
- import "../../chunks/chunk-AW3VO6AO.js";
35
+ import "../../chunks/chunk-WBFTHBNH.js";
35
36
  import {
36
37
  buildCommand
37
- } from "../../chunks/chunk-QED7VSDY.js";
38
- import "../../chunks/chunk-XK2FJELV.js";
38
+ } from "../../chunks/chunk-GPBBIDQ5.js";
39
+ import "../../chunks/chunk-J763BFOA.js";
39
40
  import {
40
41
  help
41
- } from "../../chunks/chunk-5ZJHY4AC.js";
42
+ } from "../../chunks/chunk-VNUNCNPE.js";
42
43
  import {
43
44
  DEFAULT_VERCEL_CONFIG_FILENAME,
44
45
  VERCEL_DIR,
@@ -60,10 +61,10 @@ import {
60
61
  resolveProjectCwd,
61
62
  ua_default,
62
63
  validateConfig
63
- } from "../../chunks/chunk-CNZVD6AY.js";
64
+ } from "../../chunks/chunk-GSR2GQLJ.js";
64
65
  import {
65
66
  TelemetryClient
66
- } from "../../chunks/chunk-DPXUXH7G.js";
67
+ } from "../../chunks/chunk-J5273CSE.js";
67
68
  import {
68
69
  outputAgentError
69
70
  } from "../../chunks/chunk-NHGCQRK5.js";
@@ -130,6 +131,7 @@ import {
130
131
  Span,
131
132
  validateNpmrc,
132
133
  glob,
134
+ isExperimentalService,
133
135
  getInternalServiceCronPath,
134
136
  getInternalServiceFunctionPath,
135
137
  getServiceQueueTopicConfigs,
@@ -888,10 +890,19 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
888
890
  let zeroConfigRoutes = [];
889
891
  let zeroConfigFallbackRoutes = [];
890
892
  let detectedServices;
891
- const hasExperimentalServicesConfiguredInVercelConfig = hasNonEmptyObject(
893
+ let detectedResolvedServices;
894
+ const localConfigWithServicesV2 = localConfig;
895
+ const hasExperimentalServicesV1ConfiguredInVercelConfig = hasNonEmptyObject(
892
896
  localConfig.experimentalServices
893
897
  );
894
- let detectedExperimentalServicesConfig;
898
+ const hasExperimentalServicesV2ConfiguredInVercelConfig = hasNonEmptyObject(
899
+ localConfigWithServicesV2.experimentalServicesV2
900
+ );
901
+ const configuredExperimentalServicesV2 = hasExperimentalServicesV2ConfiguredInVercelConfig && localConfigWithServicesV2.experimentalServicesV2 ? localConfigWithServicesV2.experimentalServicesV2 : void 0;
902
+ let nestExperimentalServicesV2Output = hasExperimentalServicesV2ConfiguredInVercelConfig;
903
+ let detectedExperimentalServicesV1Config;
904
+ let detectedExperimentalServicesV2Config = configuredExperimentalServicesV2;
905
+ let detectedExperimentalServicesV2RootRoutes;
895
906
  let isZeroConfig = false;
896
907
  if (builds.length > 0) {
897
908
  output_manager_default.warn(
@@ -903,6 +914,9 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
903
914
  const detectedBuilders = await span.child("vc.detectBuilders").trace(
904
915
  () => (0, import_fs_detectors2.detectBuilders)(files, pkg, {
905
916
  ...localConfig,
917
+ ...configuredExperimentalServicesV2 && {
918
+ experimentalServicesV2: configuredExperimentalServicesV2
919
+ },
906
920
  projectSettings,
907
921
  ignoreBuildScript: true,
908
922
  featHandleMiss: true,
@@ -920,7 +934,8 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
920
934
  } else {
921
935
  builds = [{ src: "**", use: "@vercel/static" }];
922
936
  }
923
- detectedServices = detectedBuilders.services;
937
+ detectedResolvedServices = detectedBuilders.services;
938
+ detectedServices = detectedBuilders.services?.filter(isExperimentalService);
924
939
  if (detectedBuilders.useImplicitEnvInjection && detectedServices && detectedServices.length > 0) {
925
940
  const serviceUrlEnvVars = getExperimentalServiceUrlEnvVars({
926
941
  services: detectedServices,
@@ -940,10 +955,11 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
940
955
  newRoutes: detectedHostRewriteRoutes ?? null,
941
956
  phase: null
942
957
  });
958
+ const detectedServiceRewriteRoutes = nestExperimentalServicesV2Output ? [] : detectedBuilders.rewriteRoutes;
943
959
  zeroConfigRoutes.push(
944
960
  ...(0, import_routing_utils2.appendRoutesToPhase)({
945
961
  routes: [],
946
- newRoutes: detectedBuilders.rewriteRoutes,
962
+ newRoutes: detectedServiceRewriteRoutes,
947
963
  phase: "filesystem"
948
964
  })
949
965
  );
@@ -952,8 +968,10 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
952
968
  newRoutes: detectedBuilders.errorRoutes,
953
969
  phase: "error"
954
970
  });
955
- zeroConfigRoutes.push(...detectedBuilders.defaultRoutes || []);
956
- zeroConfigFallbackRoutes = detectedBuilders.fallbackRoutes || [];
971
+ if (!nestExperimentalServicesV2Output) {
972
+ zeroConfigRoutes.push(...detectedBuilders.defaultRoutes || []);
973
+ zeroConfigFallbackRoutes = detectedBuilders.fallbackRoutes || [];
974
+ }
957
975
  }
958
976
  const builderSpecs = new Set(builds.map((b) => b.use));
959
977
  let buildersWithPkgs = await span.child("vc.importBuilders").trace(() => importBuilders(builderSpecs, cwd, span));
@@ -1012,12 +1030,14 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1012
1030
  }
1013
1031
  const diagnostics = {};
1014
1032
  const packageManifests = [];
1015
- const getHasDetectedServices = () => detectedServices !== void 0 && detectedServices.length > 0;
1016
- const getHasQueueServices = () => getHasDetectedServices() && detectedServices.some(isQueueBackedService);
1033
+ const getHasDetectedServices = () => detectedResolvedServices !== void 0 && detectedResolvedServices.length > 0;
1034
+ const getHasQueueServices = () => detectedServices?.some(isQueueBackedService);
1017
1035
  const synthesizedServiceCrons = [];
1018
1036
  const serviceByBuilder = /* @__PURE__ */ new Map();
1037
+ const workPathByBuilder = /* @__PURE__ */ new Map();
1038
+ const serviceFileOverrides = /* @__PURE__ */ new Map();
1019
1039
  if (getHasDetectedServices()) {
1020
- for (const service of detectedServices) {
1040
+ for (const service of detectedResolvedServices) {
1021
1041
  serviceByBuilder.set(service.builder, service);
1022
1042
  }
1023
1043
  }
@@ -1034,13 +1054,15 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1034
1054
  try {
1035
1055
  const { builder, pkg: builderPkg } = builderWithPkg;
1036
1056
  const service = getHasDetectedServices() ? serviceByBuilder.get(build) : void 0;
1037
- const stripServiceRoutePrefix = !!service?.routePrefix && service.routePrefix !== "/";
1057
+ const legacyExperimentalService = service && isExperimentalService(service) ? service : void 0;
1058
+ const serviceWorkspace = service ? isExperimentalService(service) ? service.workspace : service.root : void 0;
1059
+ const stripServiceRoutePrefix = !!legacyExperimentalService?.routePrefix && legacyExperimentalService.routePrefix !== "/";
1038
1060
  let buildWorkPath = workPath;
1039
1061
  let buildEntrypoint = build.src;
1040
1062
  let buildFiles = filesMap;
1041
- if (service && service.workspace !== ".") {
1042
- const wsPrefix = service.workspace + "/";
1043
- buildWorkPath = join2(workPath, service.workspace);
1063
+ if (service && serviceWorkspace && serviceWorkspace !== ".") {
1064
+ const wsPrefix = serviceWorkspace + "/";
1065
+ buildWorkPath = join2(workPath, serviceWorkspace);
1044
1066
  buildEntrypoint = build.src.startsWith(wsPrefix) ? build.src.slice(wsPrefix.length) : build.src;
1045
1067
  buildFiles = {};
1046
1068
  for (const [filePath, file] of Object.entries(filesMap)) {
@@ -1052,6 +1074,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1052
1074
  `Service "${service.name}": workspace-rooted build at "${buildWorkPath}", entrypoint "${buildEntrypoint}" (original: "${build.src}")`
1053
1075
  );
1054
1076
  }
1077
+ workPathByBuilder.set(build, buildWorkPath);
1055
1078
  const settingsForEnv = service ? {
1056
1079
  buildCommand: service.buildCommand ?? void 0,
1057
1080
  installCommand: service.installCommand ?? void 0,
@@ -1092,7 +1115,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1092
1115
  },
1093
1116
  installCommand: service.installCommand ?? void 0,
1094
1117
  buildCommand: service.buildCommand ?? void 0,
1095
- preDeployCommand: service.preDeployCommand ?? void 0,
1118
+ preDeployCommand: legacyExperimentalService?.preDeployCommand ?? void 0,
1096
1119
  framework: builderFramework,
1097
1120
  nodeVersion: projectSettings.nodeVersion,
1098
1121
  bunVersion: localConfig.bunVersion ?? void 0
@@ -1124,8 +1147,8 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1124
1147
  )
1125
1148
  });
1126
1149
  const serviceRoutePrefix = build.config?.routePrefix;
1127
- const serviceWorkspace = build.config?.workspace;
1128
- const preDeployCmd = service?.preDeployCommand?.trim();
1150
+ const serviceConfigWorkspace = build.config?.workspace;
1151
+ const preDeployCmd = legacyExperimentalService?.preDeployCommand?.trim();
1129
1152
  const preDeployEntry = preDeployCmd && service ? { service: service.name } : void 0;
1130
1153
  if (preDeployEntry) {
1131
1154
  preDeployEntries.push(preDeployEntry);
@@ -1146,11 +1169,13 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1146
1169
  ...service ? {
1147
1170
  service: {
1148
1171
  name: service.name,
1149
- type: service.type,
1150
- trigger: service.trigger,
1172
+ ...legacyExperimentalService ? {
1173
+ type: legacyExperimentalService.type,
1174
+ trigger: legacyExperimentalService.trigger
1175
+ } : void 0,
1151
1176
  routePrefix: typeof serviceRoutePrefix === "string" ? serviceRoutePrefix : void 0,
1152
- workspace: typeof serviceWorkspace === "string" ? serviceWorkspace : void 0,
1153
- schedule: service.schedule
1177
+ workspace: typeof serviceConfigWorkspace === "string" ? serviceConfigWorkspace : serviceWorkspace,
1178
+ ...legacyExperimentalService ? { schedule: legacyExperimentalService.schedule } : void 0
1154
1179
  }
1155
1180
  } : void 0
1156
1181
  };
@@ -1158,10 +1183,10 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1158
1183
  `Building entrypoint "${build.src}" with "${builderPkg.name}"`
1159
1184
  );
1160
1185
  const restoreEnv = /* @__PURE__ */ new Map();
1161
- if (detectedServices && service?.env) {
1186
+ if (detectedServices && legacyExperimentalService?.env) {
1162
1187
  const perServiceEnv = getServiceUrlEnvVars({
1163
- requestedEnv: service.env,
1164
- consumerService: service,
1188
+ requestedEnv: legacyExperimentalService.env,
1189
+ consumerService: legacyExperimentalService,
1165
1190
  services: detectedServices,
1166
1191
  frameworkList: import_frameworks2.frameworkList,
1167
1192
  currentEnv: process.env,
@@ -1210,7 +1235,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1210
1235
  return await builder.diagnostics?.(buildOptions);
1211
1236
  });
1212
1237
  if (builderDiagnostics) {
1213
- const prefix = service && service.workspace !== "." ? service.workspace + "/" + builderPkg.name + "/" : "";
1238
+ const prefix = service && serviceWorkspace && serviceWorkspace !== "." ? serviceWorkspace + "/" + builderPkg.name + "/" : "";
1214
1239
  for (const [key, value] of Object.entries(builderDiagnostics)) {
1215
1240
  const fullKey = prefix + key;
1216
1241
  if (key.endsWith("package-manifest.json")) {
@@ -1228,7 +1253,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1228
1253
  `Invalid package-manifest.json from ${fullKey}: ${validationError}`
1229
1254
  );
1230
1255
  } else {
1231
- const workspace = service && service.workspace !== "." ? service.workspace : ".";
1256
+ const workspace = service && serviceWorkspace && serviceWorkspace !== "." ? serviceWorkspace : ".";
1232
1257
  packageManifests.push({
1233
1258
  workspace,
1234
1259
  key: fullKey,
@@ -1305,26 +1330,31 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1305
1330
  }
1306
1331
  }
1307
1332
  }
1308
- if (getHasDetectedServices() && service && "routes" in buildResult && Array.isArray(buildResult.routes) && detectedServices) {
1333
+ if (getHasDetectedServices() && service && legacyExperimentalService && "routes" in buildResult && Array.isArray(buildResult.routes) && detectedServices) {
1309
1334
  buildResult.routes = scopeRoutesToServiceOwnership({
1310
1335
  routes: buildResult.routes,
1311
- owner: service,
1336
+ owner: legacyExperimentalService,
1312
1337
  allServices: detectedServices
1313
1338
  });
1314
1339
  }
1315
- if (service && isQueueBackedService(service) && "output" in buildResult) {
1316
- attachQueueServiceTrigger(buildResult.output, service);
1340
+ if (legacyExperimentalService && isQueueBackedService(legacyExperimentalService) && "output" in buildResult) {
1341
+ attachQueueServiceTrigger(
1342
+ buildResult.output,
1343
+ legacyExperimentalService
1344
+ );
1317
1345
  }
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";
1346
+ if (legacyExperimentalService && isScheduleTriggeredService(legacyExperimentalService) && !("crons" in buildResult && buildResult.crons?.length)) {
1347
+ const staticSchedules = getStaticServiceSchedules(
1348
+ legacyExperimentalService.schedule
1349
+ );
1350
+ if (typeof legacyExperimentalService.runtime === "string" && staticSchedules.length > 0) {
1351
+ const cronEntrypoint = legacyExperimentalService.entrypoint || legacyExperimentalService.builder.src || "index";
1322
1352
  for (const schedule of staticSchedules) {
1323
1353
  synthesizedServiceCrons.push({
1324
1354
  path: getInternalServiceCronPath(
1325
- service.name,
1355
+ legacyExperimentalService.name,
1326
1356
  cronEntrypoint,
1327
- service.handlerFunction || "cron"
1357
+ legacyExperimentalService.handlerFunction || "cron"
1328
1358
  ),
1329
1359
  schedule
1330
1360
  });
@@ -1332,7 +1362,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1332
1362
  } else {
1333
1363
  throw new NowBuildError2({
1334
1364
  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.`
1365
+ message: `Scheduled service "${legacyExperimentalService.name}" did not produce any cron entries. The builder "${builderPkg.name}" may not support scheduled services.`
1336
1366
  });
1337
1367
  }
1338
1368
  }
@@ -1349,7 +1379,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1349
1379
  throw buildOutputConfig;
1350
1380
  }
1351
1381
  if (buildOutputConfig) {
1352
- if (!hasExperimentalServicesConfiguredInVercelConfig) {
1382
+ if (!hasExperimentalServicesV1ConfiguredInVercelConfig && !hasExperimentalServicesV2ConfiguredInVercelConfig) {
1353
1383
  const outputConfigPath = join2(outputDir, "config.json");
1354
1384
  const outputConfig = await readJSONFile(outputConfigPath);
1355
1385
  if (outputConfig instanceof CantParseJSONFile) {
@@ -1357,18 +1387,20 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1357
1387
  }
1358
1388
  if (hasNonEmptyObject(outputConfig?.experimentalServices) && !hasNonEmptyObject(buildOutputConfig.experimentalServices)) {
1359
1389
  buildOutputConfig.experimentalServices = outputConfig.experimentalServices;
1390
+ }
1391
+ if (hasNonEmptyObject(outputConfig?.experimentalServicesV2) && !hasNonEmptyObject(buildOutputConfig.experimentalServicesV2)) {
1392
+ buildOutputConfig.experimentalServicesV2 = outputConfig.experimentalServicesV2;
1393
+ }
1394
+ if (hasNonEmptyObject(buildOutputConfig.experimentalServices) || hasNonEmptyObject(buildOutputConfig.experimentalServicesV2)) {
1360
1395
  await import_fs_extra2.default.writeJSON(buildOutputConfigPath, buildOutputConfig, {
1361
1396
  spaces: 2
1362
1397
  });
1363
1398
  }
1364
1399
  }
1365
- if (buildOutputConfig.overrides) {
1366
- overrides.push(buildOutputConfig.overrides);
1367
- }
1368
- if (getHasDetectedServices() && service && Array.isArray(buildOutputConfig.routes) && detectedServices) {
1400
+ if (getHasDetectedServices() && service && legacyExperimentalService && Array.isArray(buildOutputConfig.routes) && detectedServices) {
1369
1401
  buildOutputConfig.routes = scopeRoutesToServiceOwnership({
1370
1402
  routes: buildOutputConfig.routes,
1371
- owner: service,
1403
+ owner: legacyExperimentalService,
1372
1404
  allServices: detectedServices
1373
1405
  });
1374
1406
  }
@@ -1381,31 +1413,39 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1381
1413
  if ("output" in buildResult) {
1382
1414
  buildOutputLength = Array.isArray(buildResult.output) ? buildResult.output.length : 1;
1383
1415
  }
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
- )
1416
+ const writeBuildResultPromise = builderSpan.child("vc.builder.writeBuildResult", {
1417
+ buildOutputLength: String(buildOutputLength)
1418
+ }).trace(
1419
+ () => writeBuildResult({
1420
+ repoRootPath,
1421
+ outputDir,
1422
+ buildResult: rawBuildResult,
1423
+ build,
1424
+ builder,
1425
+ builderPkg,
1426
+ vercelConfig: localConfig,
1427
+ standalone,
1428
+ workPath: buildWorkPath,
1429
+ service,
1430
+ nestServiceOutput: nestExperimentalServicesV2Output,
1431
+ stripServiceRoutePrefix
1432
+ })
1408
1433
  );
1434
+ if (service && nestExperimentalServicesV2Output) {
1435
+ const override = await writeBuildResultPromise;
1436
+ if (override)
1437
+ serviceFileOverrides.set(build, override);
1438
+ } else {
1439
+ ops.push(
1440
+ writeBuildResultPromise.then(
1441
+ (override) => {
1442
+ if (override)
1443
+ overrides.push(override);
1444
+ },
1445
+ (err) => err
1446
+ )
1447
+ );
1448
+ }
1409
1449
  } catch (err) {
1410
1450
  const buildJsonBuild = buildsJsonBuilds.get(build);
1411
1451
  if (buildJsonBuild) {
@@ -1443,41 +1483,61 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1443
1483
  (build) => getBuilderIdentity(build) === candidateIdentity
1444
1484
  );
1445
1485
  };
1446
- const appendServiceRoutes = (services) => {
1486
+ const appendExperimentalServicesV1Routes = (services) => {
1447
1487
  const serviceRoutes = (0, import_fs_detectors2.generateServicesRoutes)(services);
1448
1488
  zeroConfigRoutes = (0, import_routing_utils2.appendRoutesToPhase)({
1449
1489
  routes: zeroConfigRoutes,
1450
1490
  newRoutes: serviceRoutes.hostRewrites.length ? serviceRoutes.hostRewrites : null,
1451
1491
  phase: null
1452
1492
  });
1493
+ const serviceRewriteRoutes = nestExperimentalServicesV2Output ? [] : [
1494
+ ...serviceRoutes.rewrites,
1495
+ ...serviceRoutes.workers,
1496
+ ...serviceRoutes.crons
1497
+ ];
1453
1498
  zeroConfigRoutes.push(
1454
1499
  ...(0, import_routing_utils2.appendRoutesToPhase)({
1455
1500
  routes: [],
1456
- newRoutes: [
1457
- ...serviceRoutes.rewrites,
1458
- ...serviceRoutes.workers,
1459
- ...serviceRoutes.crons
1460
- ],
1501
+ newRoutes: serviceRewriteRoutes,
1461
1502
  phase: "filesystem"
1462
1503
  })
1463
1504
  );
1464
- zeroConfigRoutes.push(...serviceRoutes.defaults);
1465
- zeroConfigFallbackRoutes.push(...serviceRoutes.fallbacks);
1505
+ if (!nestExperimentalServicesV2Output) {
1506
+ zeroConfigRoutes.push(...serviceRoutes.defaults);
1507
+ zeroConfigFallbackRoutes.push(...serviceRoutes.fallbacks);
1508
+ }
1466
1509
  };
1467
1510
  await runBuilders(builds);
1468
1511
  await flushOps();
1469
- if (!hasExperimentalServicesConfiguredInVercelConfig) {
1512
+ if (!hasExperimentalServicesV1ConfiguredInVercelConfig && !hasExperimentalServicesV2ConfiguredInVercelConfig) {
1470
1513
  const generatedConfigPath = join2(outputDir, "config.json");
1471
1514
  const generatedConfig = await readJSONFile(generatedConfigPath);
1472
1515
  if (generatedConfig instanceof CantParseJSONFile) {
1473
1516
  throw generatedConfig;
1474
1517
  }
1475
- if (hasNonEmptyObject(generatedConfig?.experimentalServices)) {
1476
- detectedExperimentalServicesConfig = generatedConfig.experimentalServices;
1518
+ const generatedExperimentalServicesV2Config = getGeneratedExperimentalServicesV2Config([
1519
+ generatedConfig,
1520
+ ...buildResults.values()
1521
+ ]);
1522
+ const generatedExperimentalServicesV1Config = getGeneratedExperimentalServicesV1Config([
1523
+ generatedConfig,
1524
+ ...buildResults.values()
1525
+ ]);
1526
+ if (generatedExperimentalServicesV2Config || generatedExperimentalServicesV1Config) {
1527
+ if (generatedExperimentalServicesV2Config) {
1528
+ nestExperimentalServicesV2Output = true;
1529
+ }
1530
+ detectedExperimentalServicesV1Config = generatedExperimentalServicesV1Config;
1531
+ detectedExperimentalServicesV2Config = generatedExperimentalServicesV2Config;
1532
+ detectedExperimentalServicesV2RootRoutes = generatedExperimentalServicesV2Config && Array.isArray(generatedConfig?.routes) ? generatedConfig.routes : void 0;
1477
1533
  const generatedBuilders = await span.child("vc.detectGeneratedServices").trace(
1478
1534
  () => (0, import_fs_detectors2.detectBuilders)(files, pkg, {
1479
1535
  ...localConfig,
1480
- experimentalServices: generatedConfig.experimentalServices,
1536
+ ...generatedExperimentalServicesV2Config ? {
1537
+ experimentalServicesV2: generatedExperimentalServicesV2Config
1538
+ } : {
1539
+ experimentalServices: generatedExperimentalServicesV1Config
1540
+ },
1481
1541
  projectSettings,
1482
1542
  ignoreBuildScript: true,
1483
1543
  featHandleMiss: true,
@@ -1490,13 +1550,19 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1490
1550
  for (const w of generatedBuilders.warnings) {
1491
1551
  output_manager_default.warn(w.message, null, w.link, w.action || "Learn More");
1492
1552
  }
1493
- detectedServices = generatedBuilders.services;
1494
- if (!detectedServices || detectedServices.length === 0) {
1553
+ detectedResolvedServices = generatedBuilders.services;
1554
+ if (!detectedResolvedServices || detectedResolvedServices.length === 0) {
1555
+ detectedResolvedServices = void 0;
1495
1556
  detectedServices = void 0;
1496
1557
  } else {
1497
- appendServiceRoutes(detectedServices);
1558
+ detectedServices = detectedResolvedServices.filter(
1559
+ isExperimentalService
1560
+ );
1561
+ if (detectedServices.length > 0) {
1562
+ appendExperimentalServicesV1Routes(detectedServices);
1563
+ }
1498
1564
  }
1499
- if (detectedServices && generatedBuilders.useImplicitEnvInjection) {
1565
+ if (detectedServices && detectedServices.length > 0 && generatedBuilders.useImplicitEnvInjection) {
1500
1566
  const serviceUrlEnvVars = getExperimentalServiceUrlEnvVars({
1501
1567
  services: detectedServices,
1502
1568
  frameworkList: import_frameworks2.frameworkList,
@@ -1510,11 +1576,20 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1510
1576
  }
1511
1577
  const buildsToRun = [];
1512
1578
  const seenBuildsToRun = /* @__PURE__ */ new Set();
1513
- for (const service of detectedServices || []) {
1579
+ const relocatedGeneratedServiceBuilds = /* @__PURE__ */ new Set();
1580
+ for (const service of detectedResolvedServices || []) {
1514
1581
  serviceByBuilder.set(service.builder, service);
1515
1582
  const alreadyExecutedBuild = getAlreadyExecutedBuild(service.builder);
1516
1583
  if (alreadyExecutedBuild) {
1517
1584
  serviceByBuilder.set(alreadyExecutedBuild, service);
1585
+ if (generatedExperimentalServicesV2Config && nestExperimentalServicesV2Output && !relocatedGeneratedServiceBuilds.has(alreadyExecutedBuild)) {
1586
+ await relocateRootBuildOutputToService({
1587
+ outputDir,
1588
+ service,
1589
+ workPath: workPathByBuilder.get(alreadyExecutedBuild) ?? workPath
1590
+ });
1591
+ relocatedGeneratedServiceBuilds.add(alreadyExecutedBuild);
1592
+ }
1518
1593
  continue;
1519
1594
  }
1520
1595
  const serviceBuilderIdentity = getBuilderIdentity(service.builder);
@@ -1551,8 +1626,8 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1551
1626
  builder: builderUse,
1552
1627
  framework: service?.framework,
1553
1628
  serviceName: service?.name,
1554
- serviceType: service?.type,
1555
- routePrefix: service?.routePrefix
1629
+ serviceType: service && isExperimentalService(service) ? service.type : void 0,
1630
+ routePrefix: service && isExperimentalService(service) ? service.routePrefix : void 0
1556
1631
  };
1557
1632
  }
1558
1633
  if (Object.keys(projectManifest).length > 0) {
@@ -1621,19 +1696,24 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1621
1696
  });
1622
1697
  }
1623
1698
  }
1624
- if (existingConfig.overrides) {
1699
+ if (existingConfig.overrides && !nestExperimentalServicesV2Output) {
1625
1700
  overrides.push(existingConfig.overrides);
1626
1701
  }
1627
1702
  }
1703
+ const topLevelBuildResults = nestExperimentalServicesV2Output ? new Map(
1704
+ Array.from(buildResults.entries()).filter(
1705
+ ([build]) => !serviceByBuilder.has(build)
1706
+ )
1707
+ ) : buildResults;
1628
1708
  const builderRoutes = Array.from(
1629
- buildResults.entries()
1709
+ topLevelBuildResults.entries()
1630
1710
  ).filter((b) => "routes" in b[1] && Array.isArray(b[1].routes)).map((b) => {
1631
1711
  const build = b[0];
1632
1712
  const buildResult = b[1];
1633
1713
  let entrypoint = build.src;
1634
1714
  if (getHasDetectedServices() && typeof build.src === "string") {
1635
1715
  const service = serviceByBuilder.get(build);
1636
- if (service && service.type === "web" && typeof service.routePrefix === "string") {
1716
+ if (service && isExperimentalService(service) && service.type === "web" && typeof service.routePrefix === "string") {
1637
1717
  entrypoint = getServicesMergeEntrypoint(service, build.src);
1638
1718
  }
1639
1719
  }
@@ -1661,15 +1741,18 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1661
1741
  phase: "filesystem"
1662
1742
  });
1663
1743
  }
1664
- const mergedImages = mergeImages(localConfig.images, buildResults.values());
1744
+ const mergedImages = mergeImages(
1745
+ localConfig.images,
1746
+ topLevelBuildResults.values()
1747
+ );
1665
1748
  const mergedCrons = mergeCrons(
1666
1749
  [...localConfig.crons || [], ...synthesizedServiceCrons],
1667
- buildResults.values()
1750
+ topLevelBuildResults.values()
1668
1751
  );
1669
- const mergedWildcard = mergeWildcard(buildResults.values());
1752
+ const mergedWildcard = mergeWildcard(topLevelBuildResults.values());
1670
1753
  const mergedDeploymentId = await mergeDeploymentId(
1671
1754
  existingConfig?.deploymentId,
1672
- buildResults.values(),
1755
+ topLevelBuildResults.values(),
1673
1756
  workPath
1674
1757
  );
1675
1758
  if (mergedDeploymentId) {
@@ -1688,23 +1771,41 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1688
1771
  });
1689
1772
  }
1690
1773
  }
1691
- const mergedOverrides = overrides.length > 0 ? Object.assign({}, ...overrides) : void 0;
1692
- const framework = await getFramework(workPath, buildResults);
1774
+ const topLevelBuildResultOverrides = Array.from(topLevelBuildResults.values()).map((result) => "overrides" in result ? result.overrides : void 0).filter((value) => Boolean(value));
1775
+ const mergedOverrides = overrides.length > 0 || topLevelBuildResultOverrides.length > 0 ? Object.assign({}, ...overrides, ...topLevelBuildResultOverrides) : void 0;
1776
+ const framework = topLevelBuildResults.size > 0 ? await getFramework(workPath, topLevelBuildResults) : void 0;
1777
+ const explicitRootRoutes = appendBuildOutputRouteTables(
1778
+ routesResult.routes,
1779
+ detectedExperimentalServicesV2RootRoutes,
1780
+ existingConfig?.routes
1781
+ );
1693
1782
  const config = {
1694
1783
  version: 3,
1695
- routes: mergedRoutes,
1784
+ routes: nestExperimentalServicesV2Output ? explicitRootRoutes : mergedRoutes,
1696
1785
  images: mergedImages,
1697
1786
  wildcard: mergedWildcard,
1698
1787
  overrides: mergedOverrides,
1699
1788
  framework,
1700
1789
  crons: mergedCrons,
1701
- ...detectedExperimentalServicesConfig && Object.keys(detectedExperimentalServicesConfig).length > 0 && {
1702
- experimentalServices: detectedExperimentalServicesConfig
1790
+ ...detectedExperimentalServicesV1Config && Object.keys(detectedExperimentalServicesV1Config).length > 0 && {
1791
+ experimentalServices: detectedExperimentalServicesV1Config
1792
+ },
1793
+ ...detectedExperimentalServicesV2Config && Object.keys(detectedExperimentalServicesV2Config).length > 0 && {
1794
+ experimentalServicesV2: detectedExperimentalServicesV2Config
1703
1795
  },
1704
- ...!detectedExperimentalServicesConfig && detectedServices && detectedServices.length > 0 && { services: detectedServices },
1796
+ ...!detectedExperimentalServicesV1Config && detectedServices && detectedServices.length > 0 && { services: detectedServices },
1705
1797
  ...mergedDeploymentId && { deploymentId: mergedDeploymentId }
1706
1798
  };
1707
1799
  await import_fs_extra2.default.writeJSON(join2(outputDir, "config.json"), config, { spaces: 2 });
1800
+ if (nestExperimentalServicesV2Output) {
1801
+ await writeServiceConfigs(
1802
+ outputDir,
1803
+ buildResults,
1804
+ serviceByBuilder,
1805
+ serviceFileOverrides,
1806
+ detectedExperimentalServicesV2Config
1807
+ );
1808
+ }
1708
1809
  await writeFlagsJSON(buildResults.values(), outputDir);
1709
1810
  collectSpan.stop();
1710
1811
  const relOutputDir = relative2(cwd, outputDir);
@@ -1967,6 +2068,129 @@ function mergeWildcard(buildResults) {
1967
2068
  }
1968
2069
  return wildcard;
1969
2070
  }
2071
+ function appendBuildOutputRouteTables(...routeTables) {
2072
+ let routes = [];
2073
+ for (const routeTable of routeTables) {
2074
+ if (!Array.isArray(routeTable) || routeTable.length === 0)
2075
+ continue;
2076
+ let phase = null;
2077
+ let phaseRoutes = [];
2078
+ const flushPhase = () => {
2079
+ if (phaseRoutes.length === 0)
2080
+ return;
2081
+ routes = (0, import_routing_utils2.appendRoutesToPhase)({
2082
+ routes,
2083
+ newRoutes: phaseRoutes,
2084
+ phase
2085
+ });
2086
+ phaseRoutes = [];
2087
+ };
2088
+ for (const route of routeTable) {
2089
+ if ((0, import_routing_utils2.isHandler)(route)) {
2090
+ flushPhase();
2091
+ phase = route.handle;
2092
+ } else {
2093
+ phaseRoutes.push(route);
2094
+ }
2095
+ }
2096
+ flushPhase();
2097
+ }
2098
+ return routes.length > 0 ? routes : void 0;
2099
+ }
2100
+ async function writeServiceConfigs(outputDir, buildResults, serviceByBuilder, serviceFileOverrides, experimentalServicesV2) {
2101
+ const serviceResults = /* @__PURE__ */ new Map();
2102
+ const serviceOverrides = /* @__PURE__ */ new Map();
2103
+ for (const [build, buildResult] of buildResults) {
2104
+ const service = serviceByBuilder.get(build);
2105
+ if (!service)
2106
+ continue;
2107
+ const results = serviceResults.get(service.name) || [];
2108
+ results.push(buildResult);
2109
+ serviceResults.set(service.name, results);
2110
+ const fileOverrides = serviceFileOverrides.get(build);
2111
+ if (fileOverrides) {
2112
+ const overrides = serviceOverrides.get(service.name) || [];
2113
+ overrides.push(fileOverrides);
2114
+ serviceOverrides.set(service.name, overrides);
2115
+ }
2116
+ }
2117
+ await Promise.all(
2118
+ Array.from(serviceResults.entries()).map(async ([serviceName, results]) => {
2119
+ const configPath = join2(
2120
+ outputDir,
2121
+ "services",
2122
+ serviceName,
2123
+ "config.json"
2124
+ );
2125
+ const existingConfig = await readJSONFile(configPath);
2126
+ if (existingConfig instanceof CantParseJSONFile) {
2127
+ throw existingConfig;
2128
+ }
2129
+ const routes = results.flatMap(
2130
+ (result) => "routes" in result && Array.isArray(result.routes) ? result.routes : []
2131
+ );
2132
+ const configuredRoutes = experimentalServicesV2?.[serviceName] ? getExperimentalServicesV2Routes(experimentalServicesV2[serviceName]) : [];
2133
+ const overrides = [
2134
+ ...results.map((result) => "overrides" in result ? result.overrides : void 0).filter(
2135
+ (value) => Boolean(value)
2136
+ ),
2137
+ ...serviceOverrides.get(serviceName) || []
2138
+ ];
2139
+ const framework = results.find(
2140
+ (result) => "framework" in result && Boolean(result.framework)
2141
+ )?.framework;
2142
+ const mergedRoutes = appendBuildOutputRouteTables(
2143
+ configuredRoutes,
2144
+ routes,
2145
+ existingConfig?.routes
2146
+ );
2147
+ const config = {
2148
+ ...existingConfig,
2149
+ version: 3,
2150
+ routes: mergedRoutes,
2151
+ images: mergeImages(existingConfig?.images, results),
2152
+ wildcard: mergeWildcard(results) || existingConfig?.wildcard,
2153
+ overrides: overrides.length > 0 ? Object.assign({}, existingConfig?.overrides, ...overrides) : existingConfig?.overrides,
2154
+ framework: framework || existingConfig?.framework,
2155
+ crons: mergeCrons(existingConfig?.crons, results),
2156
+ services: void 0,
2157
+ experimentalServices: void 0,
2158
+ experimentalServicesV2: void 0
2159
+ };
2160
+ await import_fs_extra2.default.writeJSON(configPath, config, { spaces: 2 });
2161
+ })
2162
+ );
2163
+ }
2164
+ function getExperimentalServicesV2Routes(serviceConfig) {
2165
+ const routesResult = (0, import_routing_utils2.getTransformedRoutes)({
2166
+ routes: serviceConfig.routes,
2167
+ cleanUrls: serviceConfig.cleanUrls,
2168
+ trailingSlash: serviceConfig.trailingSlash,
2169
+ headers: serviceConfig.headers,
2170
+ redirects: serviceConfig.redirects,
2171
+ rewrites: serviceConfig.rewrites
2172
+ });
2173
+ if (routesResult.error) {
2174
+ throw routesResult.error;
2175
+ }
2176
+ return routesResult.routes ?? [];
2177
+ }
2178
+ function getGeneratedExperimentalServicesV1Config(buildResults) {
2179
+ for (const result of buildResults) {
2180
+ if (result && "experimentalServices" in result && hasNonEmptyObject(result.experimentalServices)) {
2181
+ return result.experimentalServices;
2182
+ }
2183
+ }
2184
+ return void 0;
2185
+ }
2186
+ function getGeneratedExperimentalServicesV2Config(buildResults) {
2187
+ for (const result of buildResults) {
2188
+ if (result && "experimentalServicesV2" in result && hasNonEmptyObject(result.experimentalServicesV2)) {
2189
+ return result.experimentalServicesV2;
2190
+ }
2191
+ }
2192
+ return void 0;
2193
+ }
1970
2194
  async function mergeDeploymentId(existingDeploymentId, buildResults, workPath) {
1971
2195
  if (existingDeploymentId) {
1972
2196
  return existingDeploymentId;