vercel 54.9.1 → 54.10.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 (57) hide show
  1. package/dist/chunks/{add-DLK472F2.js → add-GWMRXCPO.js} +5 -5
  2. package/dist/chunks/{chunk-CSYB45VZ.js → chunk-2QPZXMJE.js} +67 -9
  3. package/dist/chunks/{chunk-BR7Z2MXT.js → chunk-4J5CBI5E.js} +6 -6
  4. package/dist/chunks/{chunk-2WIR65ZA.js → chunk-4WWFHUVW.js} +127 -93
  5. package/dist/chunks/{chunk-OZLTZQ6G.js → chunk-5LI3PLS3.js} +10 -3
  6. package/dist/chunks/{chunk-TS7YAK5A.js → chunk-6UAZGWVF.js} +1 -1
  7. package/dist/chunks/{chunk-WA3URLW4.js → chunk-6ULI5CCZ.js} +1 -1
  8. package/dist/chunks/{chunk-NHT3AQHJ.js → chunk-6YOW32LL.js} +4 -4
  9. package/dist/chunks/{chunk-7BNN27HP.js → chunk-DMKETFQS.js} +1 -1
  10. package/dist/chunks/{chunk-LZQB35VT.js → chunk-FKD3R5S7.js} +1 -1
  11. package/dist/chunks/{chunk-SZB6YXTE.js → chunk-GVYAYUAT.js} +2 -2
  12. package/dist/chunks/{chunk-KXIQF76V.js → chunk-HD23APLQ.js} +1 -1
  13. package/dist/chunks/{chunk-DPXUXH7G.js → chunk-J5273CSE.js} +2 -2
  14. package/dist/chunks/{chunk-6TKGW3ER.js → chunk-KCQWKLFD.js} +1 -1
  15. package/dist/chunks/{chunk-J5JWEUV2.js → chunk-OPAWD6UK.js} +1 -1
  16. package/dist/chunks/{chunk-5MNBLHCW.js → chunk-PB37FIFM.js} +1 -1
  17. package/dist/chunks/{chunk-KV23GR7J.js → chunk-PV533MBH.js} +1 -1
  18. package/dist/chunks/{chunk-5DEFO6LE.js → chunk-Q3ZD22HR.js} +2 -2
  19. package/dist/chunks/{chunk-ZOEYFRYV.js → chunk-QUU263YC.js} +3 -3
  20. package/dist/chunks/{chunk-BTHBAHZ7.js → chunk-RIDTMO6P.js} +1 -1
  21. package/dist/chunks/{chunk-WBGELPB3.js → chunk-SASCGHJW.js} +6 -6
  22. package/dist/chunks/{chunk-H3M6DIPE.js → chunk-T77OYIET.js} +1946 -191
  23. package/dist/chunks/{chunk-5ZJHY4AC.js → chunk-VNUNCNPE.js} +1 -1
  24. package/dist/chunks/{chunk-TAHQ6VAS.js → chunk-WFRHKZFI.js} +2 -1
  25. package/dist/chunks/{chunk-BBJUIDZF.js → chunk-YI3JV6GM.js} +3 -3
  26. package/dist/chunks/{compile-vercel-config-6DRMFWMC.js → compile-vercel-config-Y7NCY4TH.js} +2 -2
  27. package/dist/chunks/{delete-IJ6VXN3J.js → delete-53LWNN3R.js} +4 -4
  28. package/dist/chunks/{disable-YD3NZSGK.js → disable-PB4E5RT2.js} +4 -4
  29. package/dist/chunks/{discard-VFWKNLCW.js → discard-XJPKRCEX.js} +4 -4
  30. package/dist/chunks/{edit-3UMHPT2N.js → edit-LWDFUOJX.js} +6 -6
  31. package/dist/chunks/{enable-OM55GDFZ.js → enable-DBP5ARSO.js} +4 -4
  32. package/dist/chunks/{exec-JSOL4CYJ.js → exec-HI4HF4GY.js} +1 -1
  33. package/dist/chunks/{export-LSEMLHHU.js → export-LNTUARTL.js} +4 -4
  34. package/dist/chunks/{inspect-ZMNYUC4I.js → inspect-MLAWEGMC.js} +4 -4
  35. package/dist/chunks/{list-ZBRTOAFQ.js → list-74DI6236.js} +4 -4
  36. package/dist/chunks/{list-GIAM3YSQ.js → list-FIZTMQ44.js} +3 -3
  37. package/dist/chunks/{ls-NDRKV5AX.js → ls-3WF6K6R5.js} +5 -5
  38. package/dist/chunks/{publish-T3LIYYM2.js → publish-BLJ4Z47H.js} +4 -4
  39. package/dist/chunks/{query-ZPH4RM2S.js → query-N6O4SKZE.js} +3 -3
  40. package/dist/chunks/{reorder-E53AAA3P.js → reorder-TGFBUZO6.js} +4 -4
  41. package/dist/chunks/{restore-4HJU6B2V.js → restore-RQB3RYLR.js} +4 -4
  42. package/dist/chunks/{rm-ZOVPEOPT.js → rm-RY7JBRD5.js} +5 -5
  43. package/dist/chunks/{routes-3OHKNMGT.js → routes-EAMQVFU2.js} +2 -2
  44. package/dist/chunks/{rule-inspect-UMFXT335.js → rule-inspect-ENVJZ4PJ.js} +5 -5
  45. package/dist/chunks/{rules-LUJB7CCT.js → rules-3SSZZT7O.js} +6 -6
  46. package/dist/chunks/{schema-VKBUX74S.js → schema-F2RCHWJK.js} +3 -3
  47. package/dist/chunks/{update-G6D7GNBJ.js → update-QRLM425M.js} +5 -5
  48. package/dist/commands/build/index.js +332 -111
  49. package/dist/commands/deploy/index.js +13 -13
  50. package/dist/commands/dev/index.js +31 -16
  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 +21 -21
@@ -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-CSYB45VZ.js";
15
+ } from "../../chunks/chunk-2QPZXMJE.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-WBGELPB3.js";
21
+ } from "../../chunks/chunk-SASCGHJW.js";
21
22
  import {
22
23
  pickOverrides,
23
24
  readProjectSettings
24
- } from "../../chunks/chunk-KXIQF76V.js";
25
- import "../../chunks/chunk-BBJUIDZF.js";
26
- import "../../chunks/chunk-SZB6YXTE.js";
25
+ } from "../../chunks/chunk-HD23APLQ.js";
26
+ import "../../chunks/chunk-YI3JV6GM.js";
27
+ import "../../chunks/chunk-GVYAYUAT.js";
27
28
  import {
28
29
  printProjectNotFoundError
29
- } from "../../chunks/chunk-ZOEYFRYV.js";
30
+ } from "../../chunks/chunk-QUU263YC.js";
30
31
  import {
31
32
  AGENT_REASON,
32
33
  AGENT_STATUS
33
34
  } from "../../chunks/chunk-LJ5WXXG6.js";
34
- import "../../chunks/chunk-5MNBLHCW.js";
35
+ import "../../chunks/chunk-PB37FIFM.js";
35
36
  import {
36
37
  buildCommand
37
- } from "../../chunks/chunk-7BNN27HP.js";
38
- import "../../chunks/chunk-WA3URLW4.js";
38
+ } from "../../chunks/chunk-DMKETFQS.js";
39
+ import "../../chunks/chunk-6ULI5CCZ.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-H3M6DIPE.js";
64
+ } from "../../chunks/chunk-T77OYIET.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";
@@ -889,10 +890,19 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
889
890
  let zeroConfigRoutes = [];
890
891
  let zeroConfigFallbackRoutes = [];
891
892
  let detectedServices;
892
- const hasExperimentalServicesConfiguredInVercelConfig = hasNonEmptyObject(
893
+ let detectedResolvedServices;
894
+ const localConfigWithServicesV2 = localConfig;
895
+ const hasExperimentalServicesV1ConfiguredInVercelConfig = hasNonEmptyObject(
893
896
  localConfig.experimentalServices
894
897
  );
895
- 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;
896
906
  let isZeroConfig = false;
897
907
  if (builds.length > 0) {
898
908
  output_manager_default.warn(
@@ -904,6 +914,9 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
904
914
  const detectedBuilders = await span.child("vc.detectBuilders").trace(
905
915
  () => (0, import_fs_detectors2.detectBuilders)(files, pkg, {
906
916
  ...localConfig,
917
+ ...configuredExperimentalServicesV2 && {
918
+ experimentalServicesV2: configuredExperimentalServicesV2
919
+ },
907
920
  projectSettings,
908
921
  ignoreBuildScript: true,
909
922
  featHandleMiss: true,
@@ -921,6 +934,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
921
934
  } else {
922
935
  builds = [{ src: "**", use: "@vercel/static" }];
923
936
  }
937
+ detectedResolvedServices = detectedBuilders.services;
924
938
  detectedServices = detectedBuilders.services?.filter(isExperimentalService);
925
939
  if (detectedBuilders.useImplicitEnvInjection && detectedServices && detectedServices.length > 0) {
926
940
  const serviceUrlEnvVars = getExperimentalServiceUrlEnvVars({
@@ -941,10 +955,11 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
941
955
  newRoutes: detectedHostRewriteRoutes ?? null,
942
956
  phase: null
943
957
  });
958
+ const detectedServiceRewriteRoutes = nestExperimentalServicesV2Output ? [] : detectedBuilders.rewriteRoutes;
944
959
  zeroConfigRoutes.push(
945
960
  ...(0, import_routing_utils2.appendRoutesToPhase)({
946
961
  routes: [],
947
- newRoutes: detectedBuilders.rewriteRoutes,
962
+ newRoutes: detectedServiceRewriteRoutes,
948
963
  phase: "filesystem"
949
964
  })
950
965
  );
@@ -953,8 +968,10 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
953
968
  newRoutes: detectedBuilders.errorRoutes,
954
969
  phase: "error"
955
970
  });
956
- zeroConfigRoutes.push(...detectedBuilders.defaultRoutes || []);
957
- zeroConfigFallbackRoutes = detectedBuilders.fallbackRoutes || [];
971
+ if (!nestExperimentalServicesV2Output) {
972
+ zeroConfigRoutes.push(...detectedBuilders.defaultRoutes || []);
973
+ zeroConfigFallbackRoutes = detectedBuilders.fallbackRoutes || [];
974
+ }
958
975
  }
959
976
  const builderSpecs = new Set(builds.map((b) => b.use));
960
977
  let buildersWithPkgs = await span.child("vc.importBuilders").trace(() => importBuilders(builderSpecs, cwd, span));
@@ -1013,12 +1030,14 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1013
1030
  }
1014
1031
  const diagnostics = {};
1015
1032
  const packageManifests = [];
1016
- const getHasDetectedServices = () => detectedServices !== void 0 && detectedServices.length > 0;
1017
- const getHasQueueServices = () => getHasDetectedServices() && detectedServices.some(isQueueBackedService);
1033
+ const getHasDetectedServices = () => detectedResolvedServices !== void 0 && detectedResolvedServices.length > 0;
1034
+ const getHasQueueServices = () => detectedServices?.some(isQueueBackedService);
1018
1035
  const synthesizedServiceCrons = [];
1019
1036
  const serviceByBuilder = /* @__PURE__ */ new Map();
1037
+ const workPathByBuilder = /* @__PURE__ */ new Map();
1038
+ const serviceFileOverrides = /* @__PURE__ */ new Map();
1020
1039
  if (getHasDetectedServices()) {
1021
- for (const service of detectedServices) {
1040
+ for (const service of detectedResolvedServices) {
1022
1041
  serviceByBuilder.set(service.builder, service);
1023
1042
  }
1024
1043
  }
@@ -1035,13 +1054,15 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1035
1054
  try {
1036
1055
  const { builder, pkg: builderPkg } = builderWithPkg;
1037
1056
  const service = getHasDetectedServices() ? serviceByBuilder.get(build) : void 0;
1038
- 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 !== "/";
1039
1060
  let buildWorkPath = workPath;
1040
1061
  let buildEntrypoint = build.src;
1041
1062
  let buildFiles = filesMap;
1042
- if (service && service.workspace !== ".") {
1043
- const wsPrefix = service.workspace + "/";
1044
- buildWorkPath = join2(workPath, service.workspace);
1063
+ if (service && serviceWorkspace && serviceWorkspace !== ".") {
1064
+ const wsPrefix = serviceWorkspace + "/";
1065
+ buildWorkPath = join2(workPath, serviceWorkspace);
1045
1066
  buildEntrypoint = build.src.startsWith(wsPrefix) ? build.src.slice(wsPrefix.length) : build.src;
1046
1067
  buildFiles = {};
1047
1068
  for (const [filePath, file] of Object.entries(filesMap)) {
@@ -1053,6 +1074,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1053
1074
  `Service "${service.name}": workspace-rooted build at "${buildWorkPath}", entrypoint "${buildEntrypoint}" (original: "${build.src}")`
1054
1075
  );
1055
1076
  }
1077
+ workPathByBuilder.set(build, buildWorkPath);
1056
1078
  const settingsForEnv = service ? {
1057
1079
  buildCommand: service.buildCommand ?? void 0,
1058
1080
  installCommand: service.installCommand ?? void 0,
@@ -1093,7 +1115,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1093
1115
  },
1094
1116
  installCommand: service.installCommand ?? void 0,
1095
1117
  buildCommand: service.buildCommand ?? void 0,
1096
- preDeployCommand: service.preDeployCommand ?? void 0,
1118
+ preDeployCommand: legacyExperimentalService?.preDeployCommand ?? void 0,
1097
1119
  framework: builderFramework,
1098
1120
  nodeVersion: projectSettings.nodeVersion,
1099
1121
  bunVersion: localConfig.bunVersion ?? void 0
@@ -1125,8 +1147,8 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1125
1147
  )
1126
1148
  });
1127
1149
  const serviceRoutePrefix = build.config?.routePrefix;
1128
- const serviceWorkspace = build.config?.workspace;
1129
- const preDeployCmd = service?.preDeployCommand?.trim();
1150
+ const serviceConfigWorkspace = build.config?.workspace;
1151
+ const preDeployCmd = legacyExperimentalService?.preDeployCommand?.trim();
1130
1152
  const preDeployEntry = preDeployCmd && service ? { service: service.name } : void 0;
1131
1153
  if (preDeployEntry) {
1132
1154
  preDeployEntries.push(preDeployEntry);
@@ -1147,11 +1169,13 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1147
1169
  ...service ? {
1148
1170
  service: {
1149
1171
  name: service.name,
1150
- type: service.type,
1151
- trigger: service.trigger,
1172
+ ...legacyExperimentalService ? {
1173
+ type: legacyExperimentalService.type,
1174
+ trigger: legacyExperimentalService.trigger
1175
+ } : void 0,
1152
1176
  routePrefix: typeof serviceRoutePrefix === "string" ? serviceRoutePrefix : void 0,
1153
- workspace: typeof serviceWorkspace === "string" ? serviceWorkspace : void 0,
1154
- schedule: service.schedule
1177
+ workspace: typeof serviceConfigWorkspace === "string" ? serviceConfigWorkspace : serviceWorkspace,
1178
+ ...legacyExperimentalService ? { schedule: legacyExperimentalService.schedule } : void 0
1155
1179
  }
1156
1180
  } : void 0
1157
1181
  };
@@ -1159,10 +1183,10 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1159
1183
  `Building entrypoint "${build.src}" with "${builderPkg.name}"`
1160
1184
  );
1161
1185
  const restoreEnv = /* @__PURE__ */ new Map();
1162
- if (detectedServices && service?.env) {
1186
+ if (detectedServices && legacyExperimentalService?.env) {
1163
1187
  const perServiceEnv = getServiceUrlEnvVars({
1164
- requestedEnv: service.env,
1165
- consumerService: service,
1188
+ requestedEnv: legacyExperimentalService.env,
1189
+ consumerService: legacyExperimentalService,
1166
1190
  services: detectedServices,
1167
1191
  frameworkList: import_frameworks2.frameworkList,
1168
1192
  currentEnv: process.env,
@@ -1211,7 +1235,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1211
1235
  return await builder.diagnostics?.(buildOptions);
1212
1236
  });
1213
1237
  if (builderDiagnostics) {
1214
- const prefix = service && service.workspace !== "." ? service.workspace + "/" + builderPkg.name + "/" : "";
1238
+ const prefix = service && serviceWorkspace && serviceWorkspace !== "." ? serviceWorkspace + "/" + builderPkg.name + "/" : "";
1215
1239
  for (const [key, value] of Object.entries(builderDiagnostics)) {
1216
1240
  const fullKey = prefix + key;
1217
1241
  if (key.endsWith("package-manifest.json")) {
@@ -1229,7 +1253,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1229
1253
  `Invalid package-manifest.json from ${fullKey}: ${validationError}`
1230
1254
  );
1231
1255
  } else {
1232
- const workspace = service && service.workspace !== "." ? service.workspace : ".";
1256
+ const workspace = service && serviceWorkspace && serviceWorkspace !== "." ? serviceWorkspace : ".";
1233
1257
  packageManifests.push({
1234
1258
  workspace,
1235
1259
  key: fullKey,
@@ -1306,26 +1330,31 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1306
1330
  }
1307
1331
  }
1308
1332
  }
1309
- if (getHasDetectedServices() && service && "routes" in buildResult && Array.isArray(buildResult.routes) && detectedServices) {
1333
+ if (getHasDetectedServices() && service && legacyExperimentalService && "routes" in buildResult && Array.isArray(buildResult.routes) && detectedServices) {
1310
1334
  buildResult.routes = scopeRoutesToServiceOwnership({
1311
1335
  routes: buildResult.routes,
1312
- owner: service,
1336
+ owner: legacyExperimentalService,
1313
1337
  allServices: detectedServices
1314
1338
  });
1315
1339
  }
1316
- if (service && isQueueBackedService(service) && "output" in buildResult) {
1317
- attachQueueServiceTrigger(buildResult.output, service);
1340
+ if (legacyExperimentalService && isQueueBackedService(legacyExperimentalService) && "output" in buildResult) {
1341
+ attachQueueServiceTrigger(
1342
+ buildResult.output,
1343
+ legacyExperimentalService
1344
+ );
1318
1345
  }
1319
- if (service && isScheduleTriggeredService(service) && !("crons" in buildResult && buildResult.crons?.length)) {
1320
- const staticSchedules = getStaticServiceSchedules(service.schedule);
1321
- if (typeof service.runtime === "string" && staticSchedules.length > 0) {
1322
- 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";
1323
1352
  for (const schedule of staticSchedules) {
1324
1353
  synthesizedServiceCrons.push({
1325
1354
  path: getInternalServiceCronPath(
1326
- service.name,
1355
+ legacyExperimentalService.name,
1327
1356
  cronEntrypoint,
1328
- service.handlerFunction || "cron"
1357
+ legacyExperimentalService.handlerFunction || "cron"
1329
1358
  ),
1330
1359
  schedule
1331
1360
  });
@@ -1333,7 +1362,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1333
1362
  } else {
1334
1363
  throw new NowBuildError2({
1335
1364
  code: "CRON_SERVICE_NO_CRONS",
1336
- 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.`
1337
1366
  });
1338
1367
  }
1339
1368
  }
@@ -1350,7 +1379,7 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1350
1379
  throw buildOutputConfig;
1351
1380
  }
1352
1381
  if (buildOutputConfig) {
1353
- if (!hasExperimentalServicesConfiguredInVercelConfig) {
1382
+ if (!hasExperimentalServicesV1ConfiguredInVercelConfig && !hasExperimentalServicesV2ConfiguredInVercelConfig) {
1354
1383
  const outputConfigPath = join2(outputDir, "config.json");
1355
1384
  const outputConfig = await readJSONFile(outputConfigPath);
1356
1385
  if (outputConfig instanceof CantParseJSONFile) {
@@ -1358,18 +1387,20 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1358
1387
  }
1359
1388
  if (hasNonEmptyObject(outputConfig?.experimentalServices) && !hasNonEmptyObject(buildOutputConfig.experimentalServices)) {
1360
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)) {
1361
1395
  await import_fs_extra2.default.writeJSON(buildOutputConfigPath, buildOutputConfig, {
1362
1396
  spaces: 2
1363
1397
  });
1364
1398
  }
1365
1399
  }
1366
- if (buildOutputConfig.overrides) {
1367
- overrides.push(buildOutputConfig.overrides);
1368
- }
1369
- if (getHasDetectedServices() && service && Array.isArray(buildOutputConfig.routes) && detectedServices) {
1400
+ if (getHasDetectedServices() && service && legacyExperimentalService && Array.isArray(buildOutputConfig.routes) && detectedServices) {
1370
1401
  buildOutputConfig.routes = scopeRoutesToServiceOwnership({
1371
1402
  routes: buildOutputConfig.routes,
1372
- owner: service,
1403
+ owner: legacyExperimentalService,
1373
1404
  allServices: detectedServices
1374
1405
  });
1375
1406
  }
@@ -1382,31 +1413,39 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1382
1413
  if ("output" in buildResult) {
1383
1414
  buildOutputLength = Array.isArray(buildResult.output) ? buildResult.output.length : 1;
1384
1415
  }
1385
- ops.push(
1386
- builderSpan.child("vc.builder.writeBuildResult", {
1387
- buildOutputLength: String(buildOutputLength)
1388
- }).trace(
1389
- () => writeBuildResult({
1390
- repoRootPath,
1391
- outputDir,
1392
- buildResult: rawBuildResult,
1393
- build,
1394
- builder,
1395
- builderPkg,
1396
- vercelConfig: localConfig,
1397
- standalone,
1398
- workPath: buildWorkPath,
1399
- service,
1400
- stripServiceRoutePrefix
1401
- })
1402
- ).then(
1403
- (override) => {
1404
- if (override)
1405
- overrides.push(override);
1406
- },
1407
- (err) => err
1408
- )
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
+ })
1409
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
+ }
1410
1449
  } catch (err) {
1411
1450
  const buildJsonBuild = buildsJsonBuilds.get(build);
1412
1451
  if (buildJsonBuild) {
@@ -1444,41 +1483,61 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1444
1483
  (build) => getBuilderIdentity(build) === candidateIdentity
1445
1484
  );
1446
1485
  };
1447
- const appendServiceRoutes = (services) => {
1486
+ const appendExperimentalServicesV1Routes = (services) => {
1448
1487
  const serviceRoutes = (0, import_fs_detectors2.generateServicesRoutes)(services);
1449
1488
  zeroConfigRoutes = (0, import_routing_utils2.appendRoutesToPhase)({
1450
1489
  routes: zeroConfigRoutes,
1451
1490
  newRoutes: serviceRoutes.hostRewrites.length ? serviceRoutes.hostRewrites : null,
1452
1491
  phase: null
1453
1492
  });
1493
+ const serviceRewriteRoutes = nestExperimentalServicesV2Output ? [] : [
1494
+ ...serviceRoutes.rewrites,
1495
+ ...serviceRoutes.workers,
1496
+ ...serviceRoutes.crons
1497
+ ];
1454
1498
  zeroConfigRoutes.push(
1455
1499
  ...(0, import_routing_utils2.appendRoutesToPhase)({
1456
1500
  routes: [],
1457
- newRoutes: [
1458
- ...serviceRoutes.rewrites,
1459
- ...serviceRoutes.workers,
1460
- ...serviceRoutes.crons
1461
- ],
1501
+ newRoutes: serviceRewriteRoutes,
1462
1502
  phase: "filesystem"
1463
1503
  })
1464
1504
  );
1465
- zeroConfigRoutes.push(...serviceRoutes.defaults);
1466
- zeroConfigFallbackRoutes.push(...serviceRoutes.fallbacks);
1505
+ if (!nestExperimentalServicesV2Output) {
1506
+ zeroConfigRoutes.push(...serviceRoutes.defaults);
1507
+ zeroConfigFallbackRoutes.push(...serviceRoutes.fallbacks);
1508
+ }
1467
1509
  };
1468
1510
  await runBuilders(builds);
1469
1511
  await flushOps();
1470
- if (!hasExperimentalServicesConfiguredInVercelConfig) {
1512
+ if (!hasExperimentalServicesV1ConfiguredInVercelConfig && !hasExperimentalServicesV2ConfiguredInVercelConfig) {
1471
1513
  const generatedConfigPath = join2(outputDir, "config.json");
1472
1514
  const generatedConfig = await readJSONFile(generatedConfigPath);
1473
1515
  if (generatedConfig instanceof CantParseJSONFile) {
1474
1516
  throw generatedConfig;
1475
1517
  }
1476
- if (hasNonEmptyObject(generatedConfig?.experimentalServices)) {
1477
- 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;
1478
1533
  const generatedBuilders = await span.child("vc.detectGeneratedServices").trace(
1479
1534
  () => (0, import_fs_detectors2.detectBuilders)(files, pkg, {
1480
1535
  ...localConfig,
1481
- experimentalServices: generatedConfig.experimentalServices,
1536
+ ...generatedExperimentalServicesV2Config ? {
1537
+ experimentalServicesV2: generatedExperimentalServicesV2Config
1538
+ } : {
1539
+ experimentalServices: generatedExperimentalServicesV1Config
1540
+ },
1482
1541
  projectSettings,
1483
1542
  ignoreBuildScript: true,
1484
1543
  featHandleMiss: true,
@@ -1491,15 +1550,19 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1491
1550
  for (const w of generatedBuilders.warnings) {
1492
1551
  output_manager_default.warn(w.message, null, w.link, w.action || "Learn More");
1493
1552
  }
1494
- detectedServices = generatedBuilders.services?.filter(
1495
- isExperimentalService
1496
- );
1497
- if (!detectedServices || detectedServices.length === 0) {
1553
+ detectedResolvedServices = generatedBuilders.services;
1554
+ if (!detectedResolvedServices || detectedResolvedServices.length === 0) {
1555
+ detectedResolvedServices = void 0;
1498
1556
  detectedServices = void 0;
1499
1557
  } else {
1500
- appendServiceRoutes(detectedServices);
1558
+ detectedServices = detectedResolvedServices.filter(
1559
+ isExperimentalService
1560
+ );
1561
+ if (detectedServices.length > 0) {
1562
+ appendExperimentalServicesV1Routes(detectedServices);
1563
+ }
1501
1564
  }
1502
- if (detectedServices && generatedBuilders.useImplicitEnvInjection) {
1565
+ if (detectedServices && detectedServices.length > 0 && generatedBuilders.useImplicitEnvInjection) {
1503
1566
  const serviceUrlEnvVars = getExperimentalServiceUrlEnvVars({
1504
1567
  services: detectedServices,
1505
1568
  frameworkList: import_frameworks2.frameworkList,
@@ -1513,11 +1576,20 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1513
1576
  }
1514
1577
  const buildsToRun = [];
1515
1578
  const seenBuildsToRun = /* @__PURE__ */ new Set();
1516
- for (const service of detectedServices || []) {
1579
+ const relocatedGeneratedServiceBuilds = /* @__PURE__ */ new Set();
1580
+ for (const service of detectedResolvedServices || []) {
1517
1581
  serviceByBuilder.set(service.builder, service);
1518
1582
  const alreadyExecutedBuild = getAlreadyExecutedBuild(service.builder);
1519
1583
  if (alreadyExecutedBuild) {
1520
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
+ }
1521
1593
  continue;
1522
1594
  }
1523
1595
  const serviceBuilderIdentity = getBuilderIdentity(service.builder);
@@ -1554,8 +1626,8 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1554
1626
  builder: builderUse,
1555
1627
  framework: service?.framework,
1556
1628
  serviceName: service?.name,
1557
- serviceType: service?.type,
1558
- routePrefix: service?.routePrefix
1629
+ serviceType: service && isExperimentalService(service) ? service.type : void 0,
1630
+ routePrefix: service && isExperimentalService(service) ? service.routePrefix : void 0
1559
1631
  };
1560
1632
  }
1561
1633
  if (Object.keys(projectManifest).length > 0) {
@@ -1624,19 +1696,24 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1624
1696
  });
1625
1697
  }
1626
1698
  }
1627
- if (existingConfig.overrides) {
1699
+ if (existingConfig.overrides && !nestExperimentalServicesV2Output) {
1628
1700
  overrides.push(existingConfig.overrides);
1629
1701
  }
1630
1702
  }
1703
+ const topLevelBuildResults = nestExperimentalServicesV2Output ? new Map(
1704
+ Array.from(buildResults.entries()).filter(
1705
+ ([build]) => !serviceByBuilder.has(build)
1706
+ )
1707
+ ) : buildResults;
1631
1708
  const builderRoutes = Array.from(
1632
- buildResults.entries()
1709
+ topLevelBuildResults.entries()
1633
1710
  ).filter((b) => "routes" in b[1] && Array.isArray(b[1].routes)).map((b) => {
1634
1711
  const build = b[0];
1635
1712
  const buildResult = b[1];
1636
1713
  let entrypoint = build.src;
1637
1714
  if (getHasDetectedServices() && typeof build.src === "string") {
1638
1715
  const service = serviceByBuilder.get(build);
1639
- if (service && service.type === "web" && typeof service.routePrefix === "string") {
1716
+ if (service && isExperimentalService(service) && service.type === "web" && typeof service.routePrefix === "string") {
1640
1717
  entrypoint = getServicesMergeEntrypoint(service, build.src);
1641
1718
  }
1642
1719
  }
@@ -1664,15 +1741,18 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1664
1741
  phase: "filesystem"
1665
1742
  });
1666
1743
  }
1667
- const mergedImages = mergeImages(localConfig.images, buildResults.values());
1744
+ const mergedImages = mergeImages(
1745
+ localConfig.images,
1746
+ topLevelBuildResults.values()
1747
+ );
1668
1748
  const mergedCrons = mergeCrons(
1669
1749
  [...localConfig.crons || [], ...synthesizedServiceCrons],
1670
- buildResults.values()
1750
+ topLevelBuildResults.values()
1671
1751
  );
1672
- const mergedWildcard = mergeWildcard(buildResults.values());
1752
+ const mergedWildcard = mergeWildcard(topLevelBuildResults.values());
1673
1753
  const mergedDeploymentId = await mergeDeploymentId(
1674
1754
  existingConfig?.deploymentId,
1675
- buildResults.values(),
1755
+ topLevelBuildResults.values(),
1676
1756
  workPath
1677
1757
  );
1678
1758
  if (mergedDeploymentId) {
@@ -1691,23 +1771,41 @@ async function doBuild(client, project, buildsJson, cwd, outputDir, span, standa
1691
1771
  });
1692
1772
  }
1693
1773
  }
1694
- const mergedOverrides = overrides.length > 0 ? Object.assign({}, ...overrides) : void 0;
1695
- 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
+ );
1696
1782
  const config = {
1697
1783
  version: 3,
1698
- routes: mergedRoutes,
1784
+ routes: nestExperimentalServicesV2Output ? explicitRootRoutes : mergedRoutes,
1699
1785
  images: mergedImages,
1700
1786
  wildcard: mergedWildcard,
1701
1787
  overrides: mergedOverrides,
1702
1788
  framework,
1703
1789
  crons: mergedCrons,
1704
- ...detectedExperimentalServicesConfig && Object.keys(detectedExperimentalServicesConfig).length > 0 && {
1705
- experimentalServices: detectedExperimentalServicesConfig
1790
+ ...detectedExperimentalServicesV1Config && Object.keys(detectedExperimentalServicesV1Config).length > 0 && {
1791
+ experimentalServices: detectedExperimentalServicesV1Config
1706
1792
  },
1707
- ...!detectedExperimentalServicesConfig && detectedServices && detectedServices.length > 0 && { services: detectedServices },
1793
+ ...detectedExperimentalServicesV2Config && Object.keys(detectedExperimentalServicesV2Config).length > 0 && {
1794
+ experimentalServicesV2: detectedExperimentalServicesV2Config
1795
+ },
1796
+ ...!detectedExperimentalServicesV1Config && detectedServices && detectedServices.length > 0 && { services: detectedServices },
1708
1797
  ...mergedDeploymentId && { deploymentId: mergedDeploymentId }
1709
1798
  };
1710
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
+ }
1711
1809
  await writeFlagsJSON(buildResults.values(), outputDir);
1712
1810
  collectSpan.stop();
1713
1811
  const relOutputDir = relative2(cwd, outputDir);
@@ -1970,6 +2068,129 @@ function mergeWildcard(buildResults) {
1970
2068
  }
1971
2069
  return wildcard;
1972
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
+ }
1973
2194
  async function mergeDeploymentId(existingDeploymentId, buildResults, workPath) {
1974
2195
  if (existingDeploymentId) {
1975
2196
  return existingDeploymentId;