@vercel/static-build 2.11.3 → 2.11.5

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 (2) hide show
  1. package/dist/index.js +370 -171
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -7166,12 +7166,9 @@ var require_frameworks = __commonJS({
7166
7166
  // may also be detected. It is listed first so that framework detection
7167
7167
  // (which returns the first match in list order) selects it over everything
7168
7168
  // else — e.g. a Next.js app shipping a `Dockerfile.vercel` deploys as a
7169
- // container, not via `@vercel/next`. Experimental for now, so it is only
7170
- // detected when experimental frameworks are enabled
7171
- // (`VERCEL_USE_EXPERIMENTAL_FRAMEWORKS`).
7169
+ // container, not via `@vercel/next`.
7172
7170
  name: "Container",
7173
7171
  slug: "container",
7174
- experimental: true,
7175
7172
  runtimeFramework: true,
7176
7173
  logo: "https://api-frameworks.vercel.sh/framework-logos/container.svg",
7177
7174
  tagline: "Deploy any project as a container image built from a Dockerfile.",
@@ -9039,6 +9036,52 @@ var require_frameworks = __commonJS({
9039
9036
  },
9040
9037
  getOutputDirName: async () => "dist"
9041
9038
  },
9039
+ {
9040
+ name: "TanStack Start",
9041
+ slug: "tanstack-start-lovable",
9042
+ logo: "https://api-frameworks.vercel.sh/framework-logos/tanstack-start.svg",
9043
+ darkModeLogo: "https://api-frameworks.vercel.sh/framework-logos/tanstack-start-dark.svg",
9044
+ platform: {
9045
+ name: "lovable",
9046
+ logo: "https://api-frameworks.vercel.sh/framework-logos/lovable.svg"
9047
+ },
9048
+ tagline: "Full-stack Framework powered by TanStack Router imported from Lovable",
9049
+ description: "Full-document SSR, Streaming, Server Functions, bundling and more, imported from Lovable",
9050
+ website: "https://lovable.dev/",
9051
+ supersedes: ["tanstack-start", "ionic-react", "vite"],
9052
+ detectors: {
9053
+ every: [
9054
+ {
9055
+ matchPackage: "@lovable.dev/vite-tanstack-config"
9056
+ }
9057
+ ],
9058
+ some: [
9059
+ {
9060
+ matchPackage: "@tanstack/react-start"
9061
+ },
9062
+ {
9063
+ matchPackage: "@tanstack/solid-start"
9064
+ }
9065
+ ]
9066
+ },
9067
+ settings: {
9068
+ installCommand: {
9069
+ placeholder: "`yarn install`, `pnpm install`, `npm install`, or `bun install`"
9070
+ },
9071
+ buildCommand: {
9072
+ placeholder: "`npm run build` or `vite build`",
9073
+ value: "vite build"
9074
+ },
9075
+ devCommand: {
9076
+ placeholder: "vite",
9077
+ value: "vite --port $PORT"
9078
+ },
9079
+ outputDirectory: {
9080
+ value: "dist"
9081
+ }
9082
+ },
9083
+ getOutputDirName: async () => "dist"
9084
+ },
9042
9085
  {
9043
9086
  name: "VitePress",
9044
9087
  slug: "vitepress",
@@ -9541,6 +9584,10 @@ var require_frameworks = __commonJS({
9541
9584
  website: "https://storybook.js.org",
9542
9585
  ignoreRuntimes: ["@vercel/next", "@vercel/node"],
9543
9586
  disableRootMiddleware: true,
9587
+ // Storybook is a devDependency of many apps that deploy something else
9588
+ // entirely, so detecting it is not evidence the user intends to deploy
9589
+ // Storybook itself.
9590
+ detectionConfidence: "weak",
9544
9591
  detectors: {
9545
9592
  every: [
9546
9593
  {
@@ -11452,7 +11499,7 @@ var require_frameworks = __commonJS({
11452
11499
  name: "Services",
11453
11500
  slug: "services",
11454
11501
  experimental: true,
11455
- logo: "https://api-frameworks.vercel.sh/framework-logos/other.svg",
11502
+ logo: "https://api-frameworks.vercel.sh/framework-logos/services.svg",
11456
11503
  tagline: "Multiple services deployed as serverless functions within your project.",
11457
11504
  description: "Multiple services deployed as serverless functions within your project.",
11458
11505
  website: "https://vercel.com",
@@ -19803,7 +19850,7 @@ var require_superstatic = __commonJS({
19803
19850
  convertCleanUrls: () => convertCleanUrls,
19804
19851
  convertHeaders: () => convertHeaders,
19805
19852
  convertRedirects: () => convertRedirects,
19806
- convertRewrites: () => convertRewrites,
19853
+ convertRewrites: () => convertRewrites2,
19807
19854
  convertTrailingSlash: () => convertTrailingSlash,
19808
19855
  getCleanUrls: () => getCleanUrls2,
19809
19856
  pathToRegexp: () => pathToRegexp,
@@ -19919,7 +19966,7 @@ var require_superstatic = __commonJS({
19919
19966
  }
19920
19967
  });
19921
19968
  }
19922
- function convertRewrites(rewrites, internalParamNames) {
19969
+ function convertRewrites2(rewrites, internalParamNames) {
19923
19970
  return rewrites.map((r) => {
19924
19971
  const { src, segments } = sourceToRegex2(r.source);
19925
19972
  const hasSegments = collectHasSegments(r.has);
@@ -19937,7 +19984,7 @@ var require_superstatic = __commonJS({
19937
19984
  if (typeof r.destination === "string") {
19938
19985
  route = { src, dest: interpolate(r.destination), check: true };
19939
19986
  } else {
19940
- const destination = { ...r.destination };
19987
+ const destination = { ...r.destination, type: "service" };
19941
19988
  if (typeof destination.path === "string") {
19942
19989
  destination.path = interpolate(destination.path);
19943
19990
  }
@@ -20600,13 +20647,13 @@ var require_schemas = __commonJS({
20600
20647
  pattern: "^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$"
20601
20648
  };
20602
20649
  var serviceDestinationSchema = {
20603
- description: "A service-targeted destination that delegates routing into a named service from `services`.",
20650
+ description: "A service-targeted destination that delegates routing into a named service from `services`. Identified by the presence of `service`.",
20604
20651
  type: "object",
20605
20652
  additionalProperties: false,
20606
- required: ["type", "service"],
20653
+ required: ["service"],
20607
20654
  properties: {
20608
20655
  type: {
20609
- description: "Discriminator. Must be `service`.",
20656
+ description: "Optional explicit format marker. The destination shape is identified by the `service` property, so `type` is no longer required. When present it must be `service`.",
20610
20657
  type: "string",
20611
20658
  enum: ["service"]
20612
20659
  },
@@ -21376,6 +21423,7 @@ var require_dist7 = __commonJS({
21376
21423
  __export2(src_exports2, {
21377
21424
  appendRoutesToPhase: () => import_append.appendRoutesToPhase,
21378
21425
  compilePathToRegexpTemplate: () => import_superstatic2.compilePathToRegexpTemplate,
21426
+ convertRewrites: () => import_superstatic2.convertRewrites,
21379
21427
  getCleanUrls: () => import_superstatic2.getCleanUrls,
21380
21428
  getOwnershipGuard: () => import_service_route_ownership.getOwnershipGuard,
21381
21429
  getTransformedRoutes: () => getTransformedRoutes,
@@ -21430,6 +21478,8 @@ var require_dist7 = __commonJS({
21430
21478
  if (typeof route.destination === "string") {
21431
21479
  route.dest = route.destination;
21432
21480
  delete route.destination;
21481
+ } else if (typeof route.destination.service === "string") {
21482
+ route.destination = { ...route.destination, type: "service" };
21433
21483
  }
21434
21484
  }
21435
21485
  if (route.statusCode !== void 0) {
@@ -22799,7 +22849,7 @@ var require_utils4 = __commonJS({
22799
22849
  DETECTION_FRAMEWORKS: () => DETECTION_FRAMEWORKS,
22800
22850
  INTERNAL_QUEUES_PREFIX: () => INTERNAL_QUEUES_PREFIX,
22801
22851
  INTERNAL_SERVICE_PREFIX: () => import_build_utils5.INTERNAL_SERVICE_PREFIX,
22802
- assignRoutePrefixes: () => assignRoutePrefixes,
22852
+ assignMountPaths: () => assignMountPaths,
22803
22853
  combineBuildCommand: () => combineBuildCommand,
22804
22854
  filterFrameworksByRuntime: () => filterFrameworksByRuntime,
22805
22855
  getBuilderForRuntime: () => getBuilderForRuntime,
@@ -22811,6 +22861,7 @@ var require_utils4 = __commonJS({
22811
22861
  hasFile: () => hasFile,
22812
22862
  inferRuntimeFromFramework: () => inferRuntimeFromFramework,
22813
22863
  inferServiceRuntime: () => inferServiceRuntime,
22864
+ isBFFFramework: () => isBFFFramework,
22814
22865
  isFrontendFramework: () => isFrontendFramework,
22815
22866
  isRouteOwningBuilder: () => isRouteOwningBuilder2,
22816
22867
  isStaticBuild: () => isStaticBuild2,
@@ -22882,6 +22933,16 @@ var require_utils4 = __commonJS({
22882
22933
  }
22883
22934
  return !inferRuntimeFromFramework(framework);
22884
22935
  }
22936
+ var BFF_FRAMEWORKS = /* @__PURE__ */ new Set([
22937
+ "nextjs",
22938
+ "nuxtjs",
22939
+ "sveltekit",
22940
+ "remix",
22941
+ "solidstart"
22942
+ ]);
22943
+ function isBFFFramework(framework) {
22944
+ return !!framework && BFF_FRAMEWORKS.has(framework);
22945
+ }
22885
22946
  function filterFrameworksByRuntime(frameworks2, runtime) {
22886
22947
  if (!runtime) {
22887
22948
  return [...frameworks2];
@@ -22950,11 +23011,11 @@ var require_utils4 = __commonJS({
22950
23011
  }
22951
23012
  return { config: null, error: null };
22952
23013
  }
22953
- function assignRoutePrefixes(services) {
23014
+ function assignMountPaths(services) {
22954
23015
  const warnings = [];
22955
23016
  const names = Object.keys(services);
22956
23017
  if (names.length === 1) {
22957
- services[names[0]].routePrefix = "/";
23018
+ services[names[0]].mountPath = "/";
22958
23019
  return warnings;
22959
23020
  }
22960
23021
  const frontendNames = names.filter(
@@ -22967,11 +23028,19 @@ var require_utils4 = __commonJS({
22967
23028
  rootName = frontendNames.find((n) => n === "frontend" || n === "web") ?? frontendNames.sort()[0];
22968
23029
  warnings.push({
22969
23030
  code: "MULTIPLE_FRONTENDS",
22970
- message: `Multiple frontend services detected (${frontendNames.join(", ")}). "${rootName}" was assigned routePrefix "/". Adjust manually if a different service should be the root.`
23031
+ message: `Multiple frontend services detected (${frontendNames.join(", ")}). "${rootName}" was assigned mount path "/". Adjust manually if a different service should be the root.`
22971
23032
  });
22972
23033
  }
23034
+ const rootFramework = rootName ? services[rootName].framework : void 0;
23035
+ const isBFF = rootFramework ? isBFFFramework(rootFramework) : false;
23036
+ const nonRootNames = names.filter((n) => n !== rootName);
23037
+ const needsNamespace = isBFF || nonRootNames.length > 1;
22973
23038
  for (const name of names) {
22974
- services[name].routePrefix = name === rootName ? "/" : `/_/${name}`;
23039
+ if (name === rootName) {
23040
+ services[name].mountPath = "/";
23041
+ } else {
23042
+ services[name].mountPath = needsNamespace ? `/api/${name}` : "/api";
23043
+ }
22975
23044
  }
22976
23045
  return warnings;
22977
23046
  }
@@ -24183,10 +24252,35 @@ var require_resolve_v2 = __commonJS({
24183
24252
  var import_resolve = require_resolve();
24184
24253
  var import_utils = require_utils4();
24185
24254
  var frameworksBySlug = new Map(import_frameworks2.frameworkList.map((f) => [f.slug, f]));
24186
- var SERVICE_NAME_REGEX = /^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;
24255
+ var MAX_SERVICE_NAME_LENGTH = 64;
24256
+ var SERVICE_NAME_REGEX = /^[a-z]([a-z_-]*[a-z])?$/;
24257
+ function isValidServiceName(name) {
24258
+ return name.length <= MAX_SERVICE_NAME_LENGTH && SERVICE_NAME_REGEX.test(name);
24259
+ }
24260
+ function getInvalidServiceNameMessage(name) {
24261
+ return `Service name "${name}" is invalid. Names must be 1-${MAX_SERVICE_NAME_LENGTH} characters, start and end with a lowercase letter, and contain only lowercase letters, hyphens, and underscores.`;
24262
+ }
24263
+ var CONTAINER_ENTRYPOINT_CANDIDATES = [
24264
+ "Dockerfile.vercel",
24265
+ "Containerfile.vercel",
24266
+ "Dockerfile",
24267
+ "Containerfile"
24268
+ ];
24269
+ var CONTAINER_ENTRYPOINT_BASENAMES = new Set(
24270
+ CONTAINER_ENTRYPOINT_CANDIDATES.map((name) => name.toLowerCase())
24271
+ );
24187
24272
  function isDockerfileEntrypoint(entrypoint) {
24188
- const base = import_path7.posix.basename(entrypoint).toLowerCase();
24189
- return base === "dockerfile" || base === "containerfile" || base.endsWith(".dockerfile");
24273
+ return CONTAINER_ENTRYPOINT_BASENAMES.has(
24274
+ import_path7.posix.basename(entrypoint).toLowerCase()
24275
+ );
24276
+ }
24277
+ async function detectContainerEntrypoint(serviceFs) {
24278
+ for (const candidate of CONTAINER_ENTRYPOINT_CANDIDATES) {
24279
+ if (await serviceFs.hasPath(candidate)) {
24280
+ return candidate;
24281
+ }
24282
+ }
24283
+ return void 0;
24190
24284
  }
24191
24285
  function normalizeContainerCommand(command) {
24192
24286
  if (command === void 0) {
@@ -24194,29 +24288,40 @@ var require_resolve_v2 = __commonJS({
24194
24288
  }
24195
24289
  return Array.isArray(command) ? command : [command];
24196
24290
  }
24197
- function resolveContainerServiceV2(name, config, normalizedRoot) {
24291
+ async function resolveContainerServiceV2(name, config, normalizedRoot, serviceFs) {
24198
24292
  const isRoot = normalizedRoot === ".";
24199
24293
  const entrypoint = config.entrypoint;
24200
- const dockerfile = typeof entrypoint === "string" && isDockerfileEntrypoint(entrypoint) ? import_path7.posix.normalize(entrypoint) : void 0;
24201
- const image = typeof entrypoint === "string" && !dockerfile ? entrypoint : void 0;
24202
- if (!dockerfile && !image) {
24203
- return {
24204
- error: {
24205
- code: "MISSING_SERVICE_CONFIG",
24206
- message: `Container service "${name}" must specify an "entrypoint": a Dockerfile path to build, or a prebuilt OCI image reference.`,
24207
- serviceName: name
24208
- }
24209
- };
24294
+ let dockerfile;
24295
+ if (typeof entrypoint === "string") {
24296
+ if (!isDockerfileEntrypoint(entrypoint)) {
24297
+ return {
24298
+ error: {
24299
+ code: "INVALID_SERVICE_CONFIG",
24300
+ message: `Container service "${name}" has invalid "entrypoint" "${entrypoint}". It must name a Dockerfile or Containerfile.`,
24301
+ serviceName: name
24302
+ }
24303
+ };
24304
+ }
24305
+ dockerfile = import_path7.posix.normalize(entrypoint);
24306
+ } else {
24307
+ dockerfile = await detectContainerEntrypoint(serviceFs);
24308
+ if (!dockerfile) {
24309
+ return {
24310
+ error: {
24311
+ code: "MISSING_SERVICE_CONFIG",
24312
+ message: `Container service "${name}" has no "entrypoint" and no ${CONTAINER_ENTRYPOINT_CANDIDATES.join(
24313
+ ", "
24314
+ )} was found in "${normalizedRoot}".`,
24315
+ serviceName: name
24316
+ }
24317
+ };
24318
+ }
24210
24319
  }
24211
- const localSrc = dockerfile ?? image ?? "Dockerfile";
24212
- const builderSrc = isRoot ? localSrc : import_path7.posix.join(normalizedRoot, localSrc);
24320
+ const builderSrc = isRoot ? dockerfile : import_path7.posix.join(normalizedRoot, dockerfile);
24213
24321
  const builderConfig = { zeroConfig: true };
24214
24322
  if (!isRoot) {
24215
24323
  builderConfig.workspace = normalizedRoot;
24216
24324
  }
24217
- if (image) {
24218
- builderConfig.handler = image;
24219
- }
24220
24325
  const command = normalizeContainerCommand(config.command);
24221
24326
  if (command) {
24222
24327
  builderConfig.command = command;
@@ -24227,7 +24332,7 @@ var require_resolve_v2 = __commonJS({
24227
24332
  name,
24228
24333
  root: normalizedRoot,
24229
24334
  runtime: "container",
24230
- entrypoint: image ?? dockerfile,
24335
+ entrypoint: dockerfile,
24231
24336
  command,
24232
24337
  builder: {
24233
24338
  src: builderSrc,
@@ -24246,10 +24351,10 @@ var require_resolve_v2 = __commonJS({
24246
24351
  };
24247
24352
  }
24248
24353
  function validateServiceConfigV22(name, config) {
24249
- if (!SERVICE_NAME_REGEX.test(name)) {
24354
+ if (!isValidServiceName(name)) {
24250
24355
  return {
24251
24356
  code: "INVALID_SERVICE_NAME",
24252
- message: `Service name "${name}" is invalid. Names must start with a letter, end with an alphanumeric character, and contain only alphanumeric characters, hyphens, and underscores.`,
24357
+ message: getInvalidServiceNameMessage(name),
24253
24358
  serviceName: name
24254
24359
  };
24255
24360
  }
@@ -24306,27 +24411,19 @@ var require_resolve_v2 = __commonJS({
24306
24411
  };
24307
24412
  }
24308
24413
  }
24309
- const isContainer = config.runtime === "container";
24310
- if (!config.framework && !config.entrypoint && !isContainer) {
24311
- return {
24312
- code: "MISSING_SERVICE_CONFIG",
24313
- message: `Service "${name}" must specify "framework" or "entrypoint".`,
24314
- serviceName: name
24315
- };
24316
- }
24317
24414
  return null;
24318
24415
  }
24319
24416
  async function resolveConfiguredServiceV22(name, config, fs5) {
24320
24417
  const normalizedRoot = (0, import_utils.stripTrailingSlash)(import_path7.posix.normalize(config.root));
24321
- const isContainer = config.runtime === "container" || typeof config.entrypoint === "string" && isDockerfileEntrypoint(config.entrypoint);
24322
- if (isContainer) {
24323
- return resolveContainerServiceV2(name, config, normalizedRoot);
24324
- }
24325
24418
  const serviceFsResult = normalizedRoot === "." ? { fs: fs5 } : await (0, import_resolve.getServiceFs)(fs5, name, normalizedRoot);
24326
24419
  if (serviceFsResult.error) {
24327
24420
  return { error: serviceFsResult.error };
24328
24421
  }
24329
24422
  const serviceFs = serviceFsResult.fs;
24423
+ const isContainer = config.runtime === "container" || typeof config.entrypoint === "string" && isDockerfileEntrypoint(config.entrypoint);
24424
+ if (isContainer) {
24425
+ return resolveContainerServiceV2(name, config, normalizedRoot, serviceFs);
24426
+ }
24330
24427
  const rawEntrypoint = config.entrypoint;
24331
24428
  const moduleAttr = typeof rawEntrypoint === "string" ? (0, import_resolve.parsePyModuleAttrEntrypoint)(rawEntrypoint) : null;
24332
24429
  let normalizedEntrypoint;
@@ -24345,14 +24442,15 @@ var require_resolve_v2 = __commonJS({
24345
24442
  entrypointIsDirectory = Boolean(resolved.entrypoint?.isDirectory);
24346
24443
  }
24347
24444
  const entrypointFile = entrypointIsDirectory || !normalizedEntrypoint ? void 0 : normalizedEntrypoint;
24348
- const inferredRuntime = (0, import_utils.inferServiceRuntime)({
24445
+ let inferredRuntime = (0, import_utils.inferServiceRuntime)({
24349
24446
  runtime: config.runtime,
24350
24447
  framework: config.framework,
24351
24448
  entrypoint: entrypointFile
24352
24449
  });
24353
24450
  let framework = config.framework;
24354
- if (!framework && normalizedEntrypoint) {
24355
- const workspace = entrypointIsDirectory ? normalizedEntrypoint : import_path7.posix.dirname(normalizedEntrypoint) || ".";
24451
+ let detectedFramework = false;
24452
+ if (!framework) {
24453
+ const workspace = entrypointIsDirectory && normalizedEntrypoint ? normalizedEntrypoint : ".";
24356
24454
  const detection = await (0, import_resolve.detectFrameworkFromWorkspace)({
24357
24455
  fs: serviceFs,
24358
24456
  workspace,
@@ -24363,6 +24461,12 @@ var require_resolve_v2 = __commonJS({
24363
24461
  return { error: detection.error };
24364
24462
  }
24365
24463
  framework = detection.framework;
24464
+ detectedFramework = Boolean(framework);
24465
+ inferredRuntime = (0, import_utils.inferServiceRuntime)({
24466
+ runtime: config.runtime,
24467
+ framework,
24468
+ entrypoint: entrypointFile
24469
+ });
24366
24470
  }
24367
24471
  if (entrypointIsDirectory && !framework) {
24368
24472
  return {
@@ -24373,6 +24477,16 @@ var require_resolve_v2 = __commonJS({
24373
24477
  }
24374
24478
  };
24375
24479
  }
24480
+ const frameworkRuntime = (0, import_utils.inferRuntimeFromFramework)(framework);
24481
+ if (detectedFramework && frameworkRuntime && !entrypointFile) {
24482
+ return {
24483
+ error: {
24484
+ code: "MISSING_SERVICE_CONFIG",
24485
+ message: `Service "${name}" detected framework "${framework}" in "${normalizedRoot}" and must specify an "entrypoint" for runtime "${frameworkRuntime}".`,
24486
+ serviceName: name
24487
+ }
24488
+ };
24489
+ }
24376
24490
  const frameworkDefinition = framework ? frameworksBySlug.get(framework) : void 0;
24377
24491
  let builderUse;
24378
24492
  let builderSrc;
@@ -24381,16 +24495,26 @@ var require_resolve_v2 = __commonJS({
24381
24495
  builderSrc = entrypointFile || frameworkDefinition?.useRuntime?.src || "package.json";
24382
24496
  } else {
24383
24497
  if (!inferredRuntime) {
24384
- return {
24385
- error: {
24386
- code: "MISSING_SERVICE_CONFIG",
24387
- message: `Service "${name}" must specify "framework" or a runtime-resolvable "entrypoint".`,
24388
- serviceName: name
24389
- }
24390
- };
24498
+ if (config.buildCommand) {
24499
+ builderUse = "@vercel/static-build";
24500
+ builderSrc = "package.json";
24501
+ } else {
24502
+ builderUse = "@vercel/static";
24503
+ builderSrc = config.outputDirectory ? import_path7.posix.join(config.outputDirectory, "**") : "**";
24504
+ }
24505
+ } else {
24506
+ if (!entrypointFile) {
24507
+ return {
24508
+ error: {
24509
+ code: "MISSING_SERVICE_CONFIG",
24510
+ message: `Service "${name}" must specify an "entrypoint" for runtime "${inferredRuntime}".`,
24511
+ serviceName: name
24512
+ }
24513
+ };
24514
+ }
24515
+ builderUse = inferredRuntime === "node" ? "@vercel/backends" : (0, import_utils.getBuilderForRuntime)(inferredRuntime);
24516
+ builderSrc = entrypointFile;
24391
24517
  }
24392
- builderUse = inferredRuntime === "node" ? "@vercel/backends" : (0, import_utils.getBuilderForRuntime)(inferredRuntime);
24393
- builderSrc = entrypointFile;
24394
24518
  }
24395
24519
  const isRoot = normalizedRoot === ".";
24396
24520
  const projectRelativeSrc = isRoot ? builderSrc : import_path7.posix.join(normalizedRoot, builderSrc);
@@ -24401,6 +24525,9 @@ var require_resolve_v2 = __commonJS({
24401
24525
  if (framework) {
24402
24526
  builderConfig.framework = framework;
24403
24527
  }
24528
+ if (config.outputDirectory) {
24529
+ builderConfig.outputDirectory = config.outputDirectory;
24530
+ }
24404
24531
  if (!isRoot) {
24405
24532
  builderConfig.workspace = normalizedRoot;
24406
24533
  }
@@ -24463,6 +24590,14 @@ var require_resolve_v2 = __commonJS({
24463
24590
  const serviceNames = new Set(Object.keys(services));
24464
24591
  for (const service of resolved) {
24465
24592
  for (const binding of service.bindings ?? []) {
24593
+ if (!isValidServiceName(binding.service)) {
24594
+ errors.push({
24595
+ code: "INVALID_SERVICE_BINDING_NAME",
24596
+ message: `Service "${service.name}" declares an invalid binding service name "${binding.service}". ${getInvalidServiceNameMessage(binding.service)}`,
24597
+ serviceName: service.name
24598
+ });
24599
+ continue;
24600
+ }
24466
24601
  if (!serviceNames.has(binding.service)) {
24467
24602
  errors.push({
24468
24603
  code: "UNKNOWN_SERVICE_BINDING",
@@ -24579,8 +24714,9 @@ var require_auto_detect = __commonJS({
24579
24714
  async function detectServicesAtRoot(fs5, rootFramework, detectEntrypoint) {
24580
24715
  const services = {};
24581
24716
  services.frontend = {
24717
+ root: ".",
24582
24718
  framework: rootFramework.slug ?? void 0,
24583
- routePrefix: "/"
24719
+ mountPath: "/"
24584
24720
  };
24585
24721
  const backendResult = await detectBackendServices(fs5, detectEntrypoint);
24586
24722
  if (backendResult.error) {
@@ -24598,9 +24734,10 @@ var require_auto_detect = __commonJS({
24598
24734
  };
24599
24735
  }
24600
24736
  Object.assign(services, backendResult.services);
24737
+ const mountWarnings = (0, import_utils.assignMountPaths)(services);
24601
24738
  return {
24602
24739
  services,
24603
- warnings: [],
24740
+ warnings: mountWarnings,
24604
24741
  errors: []
24605
24742
  };
24606
24743
  }
@@ -24610,7 +24747,7 @@ var require_auto_detect = __commonJS({
24610
24747
  services[serviceName] = {
24611
24748
  framework: frontendFramework.slug ?? void 0,
24612
24749
  root: frontendLocation,
24613
- routePrefix: "/"
24750
+ mountPath: "/"
24614
24751
  };
24615
24752
  const backendResult = await detectBackendServices(fs5, detectEntrypoint);
24616
24753
  if (backendResult.error) {
@@ -24633,9 +24770,10 @@ var require_auto_detect = __commonJS({
24633
24770
  };
24634
24771
  }
24635
24772
  Object.assign(services, backendResult.services);
24773
+ const mountWarnings = (0, import_utils.assignMountPaths)(services);
24636
24774
  return {
24637
24775
  services,
24638
- warnings: [],
24776
+ warnings: mountWarnings,
24639
24777
  errors: []
24640
24778
  };
24641
24779
  }
@@ -24730,14 +24868,14 @@ var require_auto_detect = __commonJS({
24730
24868
  }
24731
24869
  const framework = frameworks2[0];
24732
24870
  const slug = framework.slug ?? void 0;
24733
- const routePrefix = `/_/${serviceName}`;
24871
+ const mountPath = `/${serviceName}`;
24734
24872
  const detected = detectEntrypoint && !(0, import_utils.isFrontendFramework)(slug) ? await detectEntrypoint({ workPath: dirPath, framework: slug }) : null;
24735
24873
  return {
24736
24874
  service: {
24737
24875
  framework: slug,
24738
24876
  root: dirPath,
24739
24877
  ...detected ? { entrypoint: detected.entrypoint } : {},
24740
- routePrefix
24878
+ mountPath
24741
24879
  }
24742
24880
  };
24743
24881
  }
@@ -24869,18 +25007,17 @@ var require_detect_railway = __commonJS({
24869
25007
  }
24870
25008
  const framework = frameworks2[0];
24871
25009
  const slug = framework.slug ?? void 0;
24872
- let serviceConfig = {};
24873
- serviceConfig.framework = slug;
24874
- if (cf.dirPath !== ".") {
24875
- serviceConfig.root = cf.dirPath;
24876
- if (detectEntrypoint && !(0, import_utils.isFrontendFramework)(slug)) {
24877
- const detected = await detectEntrypoint({
24878
- workPath: cf.dirPath,
24879
- framework: slug
24880
- });
24881
- if (detected) {
24882
- serviceConfig.entrypoint = detected.entrypoint;
24883
- }
25010
+ const serviceConfig = {
25011
+ root: cf.dirPath,
25012
+ framework: slug
25013
+ };
25014
+ if (cf.dirPath !== "." && detectEntrypoint && !(0, import_utils.isFrontendFramework)(slug)) {
25015
+ const detected = await detectEntrypoint({
25016
+ workPath: cf.dirPath,
25017
+ framework: slug
25018
+ });
25019
+ if (detected) {
25020
+ serviceConfig.entrypoint = detected.entrypoint;
24884
25021
  }
24885
25022
  }
24886
25023
  if (cf.config.build?.buildCommand) {
@@ -24899,7 +25036,7 @@ var require_detect_railway = __commonJS({
24899
25036
  if (serviceNames.length === 0) {
24900
25037
  return { services: null, errors: [], warnings };
24901
25038
  }
24902
- warnings.push(...(0, import_utils.assignRoutePrefixes)(services));
25039
+ warnings.push(...(0, import_utils.assignMountPaths)(services));
24903
25040
  return { services, errors: [], warnings };
24904
25041
  }
24905
25042
  async function findRailwayConfigs(fs5, dirPath = ".", depth = 0) {
@@ -27966,7 +28103,7 @@ var require_detect_render = __commonJS({
27966
28103
  const name = rs.name ?? "unnamed";
27967
28104
  const hint = {
27968
28105
  entrypoint: rs.rootDir ?? "<path-to-entrypoint>",
27969
- routePrefix: `/_/${name}`
28106
+ mountPath: `/api/${name}`
27970
28107
  };
27971
28108
  warnings.push({
27972
28109
  code: "RENDER_PSERV_HINT",
@@ -28020,19 +28157,18 @@ var require_detect_render = __commonJS({
28020
28157
  }
28021
28158
  const framework = frameworks2[0];
28022
28159
  const vercelType = SERVICE_TYPE_MAP[serviceType];
28023
- const serviceConfig = {};
28024
- serviceConfig.type = vercelType;
28025
- serviceConfig.framework = framework.slug ?? void 0;
28026
- if (rootDir !== ".") {
28027
- serviceConfig.root = rootDir;
28028
- if (detectEntrypoint && !(0, import_utils.isFrontendFramework)(serviceConfig.framework)) {
28029
- const detected = await detectEntrypoint({
28030
- workPath: rootDir,
28031
- framework: serviceConfig.framework
28032
- });
28033
- if (detected) {
28034
- serviceConfig.entrypoint = detected.entrypoint;
28035
- }
28160
+ const serviceConfig = {
28161
+ root: rootDir,
28162
+ type: vercelType,
28163
+ framework: framework.slug ?? void 0
28164
+ };
28165
+ if (rootDir !== "." && detectEntrypoint && !(0, import_utils.isFrontendFramework)(serviceConfig.framework)) {
28166
+ const detected = await detectEntrypoint({
28167
+ workPath: rootDir,
28168
+ framework: serviceConfig.framework
28169
+ });
28170
+ if (detected) {
28171
+ serviceConfig.entrypoint = detected.entrypoint;
28036
28172
  }
28037
28173
  }
28038
28174
  const buildCommand = (0, import_utils.combineBuildCommand)(
@@ -28050,7 +28186,7 @@ var require_detect_render = __commonJS({
28050
28186
  if (Object.keys(services).length === 0) {
28051
28187
  return { services: null, errors: [], warnings };
28052
28188
  }
28053
- warnings.push(...(0, import_utils.assignRoutePrefixes)(services));
28189
+ warnings.push(...(0, import_utils.assignMountPaths)(services));
28054
28190
  return { services, errors: [], warnings };
28055
28191
  }
28056
28192
  async function readRenderYaml(fs5) {
@@ -28207,6 +28343,7 @@ var require_detect_procfile = __commonJS({
28207
28343
  if (isWorkerLikeProcess) {
28208
28344
  if (hasSupportedWorkerCommand(tokens) && entrypoint?.endsWith(".py")) {
28209
28345
  services[processType] = {
28346
+ root: ".",
28210
28347
  type: "worker",
28211
28348
  entrypoint,
28212
28349
  runtime: "python"
@@ -28223,12 +28360,12 @@ var require_detect_procfile = __commonJS({
28223
28360
  });
28224
28361
  continue;
28225
28362
  }
28226
- const serviceConfig = { type: "web" };
28227
- if (detectedFramework) {
28228
- serviceConfig.framework = detectedFramework.slug ?? void 0;
28229
- }
28230
- serviceConfig.entrypoint = entrypoint ?? ".";
28231
- services[processType] = serviceConfig;
28363
+ services[processType] = {
28364
+ root: ".",
28365
+ type: "web",
28366
+ ...detectedFramework?.slug ? { framework: detectedFramework.slug } : {},
28367
+ entrypoint: entrypoint ?? "."
28368
+ };
28232
28369
  }
28233
28370
  if (errors.length > 0) {
28234
28371
  return { services: null, errors, warnings };
@@ -28244,7 +28381,7 @@ var require_detect_procfile = __commonJS({
28244
28381
  firstService.buildCommand = releaseCommand;
28245
28382
  }
28246
28383
  }
28247
- warnings.push(...(0, import_utils.assignRoutePrefixes)(services));
28384
+ warnings.push(...(0, import_utils.assignMountPaths)(services));
28248
28385
  return { services, errors: [], warnings };
28249
28386
  }
28250
28387
  function parseProcfile(content) {
@@ -28361,6 +28498,7 @@ var require_detect_services = __commonJS({
28361
28498
  var detect_services_exports = {};
28362
28499
  __export2(detect_services_exports, {
28363
28500
  detectServices: () => detectServices2,
28501
+ generateServiceRewrites: () => generateServiceRewrites,
28364
28502
  generateServicesRoutes: () => generateServicesRoutes2
28365
28503
  });
28366
28504
  module2.exports = __toCommonJS2(detect_services_exports);
@@ -28393,6 +28531,7 @@ var require_detect_services = __commonJS({
28393
28531
  source: resolved.source,
28394
28532
  useImplicitEnvInjection: resolved.useImplicitEnvInjection,
28395
28533
  routes: resolved.routes,
28534
+ rewrites: resolved.rewrites,
28396
28535
  errors: resolved.errors,
28397
28536
  warnings: resolved.warnings,
28398
28537
  resolved,
@@ -28402,18 +28541,17 @@ var require_detect_services = __commonJS({
28402
28541
  function toInferredLayoutConfig(services) {
28403
28542
  const inferredConfig = {};
28404
28543
  for (const [name, service] of Object.entries(services)) {
28405
- const serviceConfig = {};
28544
+ const serviceConfig = {
28545
+ root: service.root
28546
+ };
28406
28547
  if (service.type) {
28407
28548
  serviceConfig.type = service.type;
28408
28549
  }
28409
- if (typeof service.root === "string") {
28410
- serviceConfig.root = service.root;
28411
- }
28412
28550
  if (typeof service.entrypoint === "string") {
28413
28551
  serviceConfig.entrypoint = service.entrypoint;
28414
28552
  }
28415
- if (typeof service.routePrefix === "string") {
28416
- serviceConfig.routePrefix = service.routePrefix;
28553
+ if (typeof service.mountPath === "string") {
28554
+ serviceConfig.mountPath = service.mountPath;
28417
28555
  }
28418
28556
  if ((0, import_utils.isFrontendFramework)(service.framework)) {
28419
28557
  serviceConfig.framework = service.framework;
@@ -28444,6 +28582,7 @@ var require_detect_services = __commonJS({
28444
28582
  source: "configured",
28445
28583
  useImplicitEnvInjection: true,
28446
28584
  routes: emptyRoutes(),
28585
+ rewrites: [],
28447
28586
  errors: [configError],
28448
28587
  warnings: []
28449
28588
  });
@@ -28454,6 +28593,7 @@ var require_detect_services = __commonJS({
28454
28593
  source: "configured",
28455
28594
  useImplicitEnvInjection: false,
28456
28595
  routes: emptyRoutes(),
28596
+ rewrites: [],
28457
28597
  errors: [
28458
28598
  {
28459
28599
  code: "SERVICES_AND_EXPERIMENTAL_SERVICES_V2",
@@ -28466,63 +28606,66 @@ var require_detect_services = __commonJS({
28466
28606
  const hasProvidedConfiguredServices = providedConfiguredServices && Object.keys(providedConfiguredServices).length > 0;
28467
28607
  const experimentalServicesV2 = hasProvidedConfiguredServices && (providedConfiguredServicesType === "services" || providedConfiguredServicesType === "experimentalServicesV2") ? providedConfiguredServices : hasProvidedConfiguredServices ? void 0 : vercelConfig?.services ?? vercelConfig?.experimentalServicesV2;
28468
28608
  if (experimentalServicesV2 && Object.keys(experimentalServicesV2).length > 0) {
28469
- const result2 = await (0, import_resolve_v2.resolveAllConfiguredServicesV2)(
28609
+ const result = await (0, import_resolve_v2.resolveAllConfiguredServicesV2)(
28470
28610
  experimentalServicesV2,
28471
28611
  scopedFs
28472
28612
  );
28473
28613
  return withResolvedResult({
28474
- services: result2.services,
28614
+ services: result.services,
28475
28615
  source: "configured",
28476
28616
  // V2 uses explicit `bindings`, so no implicit `{NAME}_URL` injection.
28477
28617
  useImplicitEnvInjection: false,
28478
28618
  // V2 routes are explicitly carried per-service to output them separately.
28479
28619
  routes: emptyRoutes(),
28480
- errors: result2.errors,
28620
+ rewrites: [],
28621
+ errors: result.errors,
28481
28622
  warnings: []
28482
28623
  });
28483
28624
  }
28484
28625
  const experimentalServicesV1 = hasProvidedConfiguredServices ? providedConfiguredServices : vercelConfig?.experimentalServices;
28485
28626
  const hasExperimentalServicesV1 = experimentalServicesV1 && Object.keys(experimentalServicesV1).length > 0;
28486
- if (!hasExperimentalServicesV1) {
28487
- const detectors = [
28488
- { detect: import_detect_railway.detectRailwayServices, source: "railway" },
28489
- { detect: import_detect_render.detectRenderServices, source: "render" },
28490
- { detect: import_detect_procfile.detectProcfileServices, source: "procfile" },
28491
- { detect: import_auto_detect.autoDetectServices, source: "layout" }
28492
- ];
28493
- for (const { detect, source } of detectors) {
28494
- const detectResult = await detect({ fs: scopedFs, detectEntrypoint });
28495
- const match = await tryResolveInferred(detectResult, source, scopedFs);
28496
- if (match)
28497
- return match;
28498
- }
28627
+ if (hasExperimentalServicesV1) {
28628
+ const result = await (0, import_resolve.resolveAllConfiguredServices)(
28629
+ experimentalServicesV1,
28630
+ scopedFs,
28631
+ "configured"
28632
+ );
28633
+ const routes = generateServicesRoutes2(result.services);
28499
28634
  return withResolvedResult({
28500
- services: [],
28501
- source: "auto-detected",
28635
+ services: result.services,
28636
+ source: "configured",
28637
+ // experimentalServices uses the legacy `{NAME}_URL` injection.
28502
28638
  useImplicitEnvInjection: true,
28503
- routes: emptyRoutes(),
28504
- errors: [
28505
- {
28506
- code: "NO_EXPERIMENTAL_SERVICES_CONFIGURED",
28507
- message: "No services configured. Add `experimentalServices` to vercel.json."
28508
- }
28509
- ],
28639
+ routes,
28640
+ rewrites: [],
28641
+ errors: result.errors,
28510
28642
  warnings: []
28511
28643
  });
28512
28644
  }
28513
- const result = await (0, import_resolve.resolveAllConfiguredServices)(
28514
- experimentalServicesV1,
28515
- scopedFs,
28516
- "configured"
28517
- );
28518
- const routes = generateServicesRoutes2(result.services);
28645
+ const detectors = [
28646
+ { detect: import_detect_railway.detectRailwayServices, source: "railway" },
28647
+ { detect: import_detect_render.detectRenderServices, source: "render" },
28648
+ { detect: import_detect_procfile.detectProcfileServices, source: "procfile" },
28649
+ { detect: import_auto_detect.autoDetectServices, source: "layout" }
28650
+ ];
28651
+ for (const { detect, source } of detectors) {
28652
+ const detectResult = await detect({ fs: scopedFs, detectEntrypoint });
28653
+ const match = await tryResolveInferred(detectResult, source, scopedFs);
28654
+ if (match)
28655
+ return match;
28656
+ }
28519
28657
  return withResolvedResult({
28520
- services: result.services,
28521
- source: "configured",
28522
- // experimentalServices uses the legacy `{NAME}_URL` injection.
28658
+ services: [],
28659
+ source: "auto-detected",
28523
28660
  useImplicitEnvInjection: true,
28524
- routes,
28525
- errors: result.errors,
28661
+ routes: emptyRoutes(),
28662
+ rewrites: [],
28663
+ errors: [
28664
+ {
28665
+ code: "NO_EXPERIMENTAL_SERVICES_CONFIGURED",
28666
+ message: "No services configured. Add `experimentalServices` to vercel.json."
28667
+ }
28668
+ ],
28526
28669
  warnings: []
28527
28670
  });
28528
28671
  }
@@ -28531,8 +28674,9 @@ var require_detect_services = __commonJS({
28531
28674
  return withResolvedResult({
28532
28675
  services: [],
28533
28676
  source: "auto-detected",
28534
- useImplicitEnvInjection: true,
28677
+ useImplicitEnvInjection: source !== "layout",
28535
28678
  routes: emptyRoutes(),
28679
+ rewrites: [],
28536
28680
  errors: detectResult.errors,
28537
28681
  warnings: detectResult.warnings
28538
28682
  });
@@ -28540,52 +28684,96 @@ var require_detect_services = __commonJS({
28540
28684
  if (!detectResult.services) {
28541
28685
  return null;
28542
28686
  }
28687
+ if (source === "layout") {
28688
+ const v2Services = {};
28689
+ for (const [name, svc] of Object.entries(detectResult.services)) {
28690
+ v2Services[name] = {
28691
+ root: svc.root,
28692
+ ...svc.framework ? { framework: svc.framework } : {},
28693
+ ...svc.entrypoint ? { entrypoint: svc.entrypoint } : {}
28694
+ };
28695
+ }
28696
+ const result2 = await (0, import_resolve_v2.resolveAllConfiguredServicesV2)(v2Services, scopedFs);
28697
+ const rootServices = Object.values(detectResult.services).filter(
28698
+ (svc) => svc.mountPath === "/" && typeof svc.framework === "string"
28699
+ );
28700
+ const shouldInfer2 = result2.errors.length === 0 && rootServices.length === 1 && result2.services.length > 1;
28701
+ const inferred2 = shouldInfer2 ? {
28702
+ source,
28703
+ config: toInferredLayoutConfig(detectResult.services),
28704
+ services: result2.services,
28705
+ warnings: detectResult.warnings
28706
+ } : null;
28707
+ return withResolvedResult(
28708
+ {
28709
+ services: shouldInfer2 ? result2.services : [],
28710
+ source: "auto-detected",
28711
+ useImplicitEnvInjection: false,
28712
+ routes: emptyRoutes(),
28713
+ rewrites: shouldInfer2 ? generateServiceRewrites(detectResult.services) : [],
28714
+ experimentalServicesV2: shouldInfer2 ? v2Services : void 0,
28715
+ errors: result2.errors,
28716
+ warnings: detectResult.warnings
28717
+ },
28718
+ inferred2
28719
+ );
28720
+ }
28721
+ const v1Services = {};
28722
+ for (const [name, svc] of Object.entries(detectResult.services)) {
28723
+ v1Services[name] = {
28724
+ root: svc.root === "." ? void 0 : svc.root,
28725
+ ...svc.framework ? { framework: svc.framework } : {},
28726
+ ...svc.entrypoint ? { entrypoint: svc.entrypoint } : {},
28727
+ ...svc.type ? { type: svc.type } : {},
28728
+ ...svc.buildCommand ? { buildCommand: svc.buildCommand } : {},
28729
+ ...svc.preDeployCommand ? { preDeployCommand: svc.preDeployCommand } : {},
28730
+ ...svc.mountPath ? { routePrefix: svc.mountPath } : {}
28731
+ };
28732
+ }
28543
28733
  const result = await (0, import_resolve.resolveAllConfiguredServices)(
28544
- detectResult.services,
28734
+ v1Services,
28545
28735
  scopedFs,
28546
28736
  "generated"
28547
28737
  );
28548
- let shouldInfer;
28549
- if (source === "layout") {
28550
- const rootWebFrameworkServices = result.services.filter(
28551
- (service) => service.type === "web" && service.routePrefix === "/" && typeof service.framework === "string"
28552
- );
28553
- shouldInfer = result.errors.length === 0 && rootWebFrameworkServices.length === 1 && result.services.length > 1;
28554
- } else {
28555
- shouldInfer = result.errors.length === 0 && result.services.length > 0;
28556
- }
28738
+ const shouldInfer = result.errors.length === 0 && result.services.length > 0;
28557
28739
  const inferred = shouldInfer ? {
28558
28740
  source,
28559
28741
  config: toInferredLayoutConfig(detectResult.services),
28560
28742
  services: result.services,
28561
28743
  warnings: detectResult.warnings
28562
28744
  } : null;
28563
- if (source === "layout" && shouldInfer) {
28564
- const routes = generateServicesRoutes2(result.services);
28565
- return withResolvedResult(
28566
- {
28567
- services: result.services,
28568
- source: "auto-detected",
28569
- useImplicitEnvInjection: true,
28570
- routes,
28571
- errors: result.errors,
28572
- warnings: detectResult.warnings
28573
- },
28574
- inferred
28575
- );
28576
- }
28577
28745
  return withResolvedResult(
28578
28746
  {
28579
28747
  services: [],
28580
28748
  source: "auto-detected",
28581
28749
  useImplicitEnvInjection: true,
28582
28750
  routes: emptyRoutes(),
28751
+ rewrites: [],
28583
28752
  errors: result.errors,
28584
28753
  warnings: detectResult.warnings
28585
28754
  },
28586
28755
  inferred
28587
28756
  );
28588
28757
  }
28758
+ function generateServiceRewrites(services) {
28759
+ const entries = Object.entries(services).filter(
28760
+ ([, svc]) => typeof svc.mountPath === "string" && (!svc.type || svc.type === "web")
28761
+ ).sort(([, a], [, b]) => b.mountPath.length - a.mountPath.length);
28762
+ return entries.map(([name, svc]) => {
28763
+ const mountPath = svc.mountPath;
28764
+ if (mountPath === "/") {
28765
+ return {
28766
+ source: "/(.*)",
28767
+ destination: { type: "service", service: name }
28768
+ };
28769
+ }
28770
+ const prefix = mountPath.startsWith("/") ? mountPath.slice(1) : mountPath;
28771
+ return {
28772
+ source: `/${prefix}(/.*)?`,
28773
+ destination: { type: "service", service: name }
28774
+ };
28775
+ });
28776
+ }
28589
28777
  function generateServicesRoutes2(allServices) {
28590
28778
  const services = allServices.filter(import_build_utils5.isExperimentalService);
28591
28779
  const hostRewrites = [];
@@ -29042,6 +29230,8 @@ var require_get_services_builders = __commonJS({
29042
29230
  ...result.routes.crons
29043
29231
  ] : null,
29044
29232
  errorRoutes: [],
29233
+ serviceRewrites: result.rewrites.length > 0 ? result.rewrites : void 0,
29234
+ experimentalServicesV2: result.experimentalServicesV2,
29045
29235
  services: result.services,
29046
29236
  useImplicitEnvInjection: result.useImplicitEnvInjection
29047
29237
  };
@@ -29653,7 +29843,7 @@ var require_detect_builders = __commonJS({
29653
29843
  }
29654
29844
  }
29655
29845
  }
29656
- if (frontendBuilder && ((0, import_is_official_runtime.isOfficialRuntime)("express", frontendBuilder.use) || (0, import_is_official_runtime.isOfficialRuntime)("hono", frontendBuilder.use) || (0, import_is_official_runtime.isOfficialRuntime)("backends", frontendBuilder.use))) {
29846
+ if (frontendBuilder && ((0, import_is_official_runtime.isOfficialRuntime)("express", frontendBuilder.use) || (0, import_is_official_runtime.isOfficialRuntime)("hono", frontendBuilder.use) || (0, import_is_official_runtime.isOfficialRuntime)("python", frontendBuilder.use) || (0, import_is_official_runtime.isOfficialRuntime)("backends", frontendBuilder.use))) {
29657
29847
  return null;
29658
29848
  }
29659
29849
  if (unusedFunctions.size) {
@@ -35656,6 +35846,15 @@ var build = async ({
35656
35846
  }) => {
35657
35847
  await (0, import_build_utils4.download)(files, workPath, meta);
35658
35848
  const routePrefix = config.routePrefix;
35849
+ if (routePrefix) {
35850
+ const mountpointCandidate = routePrefix.replace(/^\//, "") || ".";
35851
+ if (mountpointCandidate.split(/[/\\]/).some((segment) => segment === "..")) {
35852
+ throw new import_build_utils4.NowBuildError({
35853
+ code: "STATIC_BUILD_UNSAFE_ROUTE_PREFIX",
35854
+ message: `Invalid routePrefix "${routePrefix}": path traversal segments are not allowed.`
35855
+ });
35856
+ }
35857
+ }
35659
35858
  const mountpoint = routePrefix ? routePrefix.replace(/^\//, "") || "." : import_path6.default.dirname(entrypoint);
35660
35859
  const entrypointDir = import_path6.default.join(workPath, import_path6.default.dirname(entrypoint));
35661
35860
  let distPath = import_path6.default.join(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/static-build",
3
- "version": "2.11.3",
3
+ "version": "2.11.5",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index",
6
6
  "homepage": "https://vercel.com/docs/build-step",
@@ -15,7 +15,7 @@
15
15
  "dependencies": {
16
16
  "ts-morph": "12.0.0",
17
17
  "@vercel/gatsby-plugin-vercel-analytics": "1.0.11",
18
- "@vercel/gatsby-plugin-vercel-builder": "2.2.23",
18
+ "@vercel/gatsby-plugin-vercel-builder": "2.2.25",
19
19
  "@vercel/static-config": "3.4.0"
20
20
  },
21
21
  "devDependencies": {
@@ -37,11 +37,11 @@
37
37
  "semver": "7.5.2",
38
38
  "tree-kill": "1.2.2",
39
39
  "vitest": "2.0.3",
40
- "@vercel/build-utils": "13.32.1",
40
+ "@vercel/build-utils": "13.32.3",
41
+ "@vercel/frameworks": "3.30.6",
41
42
  "@vercel/error-utils": "2.2.0",
42
- "@vercel/frameworks": "3.30.0",
43
- "@vercel/fs-detectors": "6.10.1",
44
- "@vercel/routing-utils": "6.3.1"
43
+ "@vercel/fs-detectors": "6.12.1",
44
+ "@vercel/routing-utils": "6.4.0"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "node ../../utils/build-builder.mjs",