@vercel/static-build 2.8.38 → 2.8.40

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 +670 -469
  2. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -10383,6 +10383,60 @@ var require_frameworks = __commonJS({
10383
10383
  }
10384
10384
  ]
10385
10385
  },
10386
+ {
10387
+ name: "Django",
10388
+ slug: "django",
10389
+ experimental: true,
10390
+ logo: "https://api-frameworks.vercel.sh/framework-logos/django.svg",
10391
+ tagline: "Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. ",
10392
+ description: "A Django project served via the Python Runtime.",
10393
+ website: "https://www.djangoproject.com",
10394
+ supersedes: ["python"],
10395
+ useRuntime: { src: "index.py", use: "@vercel/python" },
10396
+ ignoreRuntimes: ["@vercel/python"],
10397
+ detectors: {
10398
+ some: [
10399
+ {
10400
+ path: "requirements.txt",
10401
+ matchContent: "[Dd]jango"
10402
+ },
10403
+ {
10404
+ path: "pyproject.toml",
10405
+ matchContent: "[Dd]jango"
10406
+ },
10407
+ {
10408
+ path: "Pipfile",
10409
+ matchContent: "[Dd]jango"
10410
+ }
10411
+ ]
10412
+ },
10413
+ settings: {
10414
+ installCommand: {
10415
+ placeholder: "`pip install -r requirements.txt`"
10416
+ },
10417
+ buildCommand: {
10418
+ placeholder: "None",
10419
+ value: null
10420
+ },
10421
+ devCommand: {
10422
+ placeholder: "None",
10423
+ value: null
10424
+ },
10425
+ outputDirectory: {
10426
+ value: "N/A"
10427
+ }
10428
+ },
10429
+ getOutputDirName: async () => "public",
10430
+ defaultRoutes: [
10431
+ {
10432
+ handle: "filesystem"
10433
+ },
10434
+ {
10435
+ src: "/(.*)",
10436
+ dest: "/"
10437
+ }
10438
+ ]
10439
+ },
10386
10440
  {
10387
10441
  name: "Sanity (v3)",
10388
10442
  slug: "sanity-v3",
@@ -22427,15 +22481,13 @@ var require_utils4 = __commonJS({
22427
22481
  }
22428
22482
  });
22429
22483
 
22430
- // ../fs-detectors/dist/services/resolve.js
22431
- var require_resolve = __commonJS({
22432
- "../fs-detectors/dist/services/resolve.js"(exports2, module2) {
22484
+ // ../fs-detectors/dist/detect-framework.js
22485
+ var require_detect_framework = __commonJS({
22486
+ "../fs-detectors/dist/detect-framework.js"(exports2, module2) {
22433
22487
  "use strict";
22434
- var __create2 = Object.create;
22435
22488
  var __defProp2 = Object.defineProperty;
22436
22489
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
22437
22490
  var __getOwnPropNames2 = Object.getOwnPropertyNames;
22438
- var __getProtoOf2 = Object.getPrototypeOf;
22439
22491
  var __hasOwnProp2 = Object.prototype.hasOwnProperty;
22440
22492
  var __export2 = (target, all) => {
22441
22493
  for (var name in all)
@@ -22449,300 +22501,247 @@ var require_resolve = __commonJS({
22449
22501
  }
22450
22502
  return to;
22451
22503
  };
22452
- var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps2(
22453
- // If the importer is in node compatibility mode or this is not an ESM
22454
- // file that has been converted to a CommonJS file using a Babel-
22455
- // compatible transform (i.e. "__esModule" has not been set), then set
22456
- // "default" to the CommonJS "module.exports" for node compatibility.
22457
- isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
22458
- mod
22459
- ));
22460
22504
  var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
22461
- var resolve_exports = {};
22462
- __export2(resolve_exports, {
22463
- resolveAllConfiguredServices: () => resolveAllConfiguredServices,
22464
- resolveConfiguredService: () => resolveConfiguredService,
22465
- validateServiceConfig: () => validateServiceConfig
22505
+ var detect_framework_exports = {};
22506
+ __export2(detect_framework_exports, {
22507
+ detectFramework: () => detectFramework2,
22508
+ detectFrameworkRecord: () => detectFrameworkRecord3,
22509
+ detectFrameworkVersion: () => detectFrameworkVersion2,
22510
+ detectFrameworks: () => detectFrameworks2,
22511
+ removeSupersededFrameworks: () => removeSupersededFrameworks
22466
22512
  });
22467
- module2.exports = __toCommonJS2(resolve_exports);
22468
- var import_path7 = require("path");
22469
- var import_types = require_types3();
22470
- var import_utils = require_utils4();
22471
- var import_frameworks2 = __toESM2(require_frameworks());
22472
- var import_routing_utils = require_dist6();
22473
- var frameworksBySlug = new Map(import_frameworks2.default.map((f) => [f.slug, f]));
22474
- var SERVICE_NAME_REGEX = /^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;
22475
- function toWorkspaceRelativeEntrypoint(entrypoint, workspace) {
22476
- const normalizedEntrypoint = import_path7.posix.normalize(entrypoint);
22477
- if (workspace === ".") {
22478
- return normalizedEntrypoint;
22479
- }
22480
- const workspacePrefix = `${workspace}/`;
22481
- if (normalizedEntrypoint.startsWith(workspacePrefix)) {
22482
- return normalizedEntrypoint.slice(workspacePrefix.length);
22513
+ module2.exports = __toCommonJS2(detect_framework_exports);
22514
+ var import_child_process2 = require("child_process");
22515
+ function shouldIncludeExperimentalFrameworks(useExperimentalFrameworks) {
22516
+ if (typeof useExperimentalFrameworks === "boolean") {
22517
+ return useExperimentalFrameworks;
22483
22518
  }
22484
- const relativeEntrypoint = import_path7.posix.relative(
22485
- workspace,
22486
- normalizedEntrypoint
22487
- );
22488
- if (relativeEntrypoint === "" || relativeEntrypoint.startsWith("..")) {
22489
- return normalizedEntrypoint;
22519
+ const experimentalEnv = process.env.VERCEL_USE_EXPERIMENTAL_FRAMEWORKS;
22520
+ const isEnabled = (val) => val === "1" || typeof val === "string" && val.toLowerCase() === "true";
22521
+ return isEnabled(experimentalEnv);
22522
+ }
22523
+ function filterFrameworkList(frameworkList, useExperimentalFrameworks) {
22524
+ if (shouldIncludeExperimentalFrameworks(useExperimentalFrameworks)) {
22525
+ return frameworkList;
22490
22526
  }
22491
- return relativeEntrypoint;
22527
+ return frameworkList.filter((f) => {
22528
+ const experimental = f.experimental;
22529
+ return !experimental;
22530
+ });
22492
22531
  }
22493
- async function inferWorkspaceFromNearestManifest({
22494
- fs: fs5,
22495
- entrypoint,
22496
- runtime
22497
- }) {
22498
- if (!entrypoint || !runtime) {
22499
- return void 0;
22532
+ async function matches(fs5, framework) {
22533
+ const { detectors } = framework;
22534
+ if (!detectors) {
22535
+ return;
22500
22536
  }
22501
- const manifests = import_types.RUNTIME_MANIFESTS[runtime];
22502
- if (!manifests || manifests.length === 0) {
22503
- return void 0;
22537
+ const { every, some } = detectors;
22538
+ if (every !== void 0 && !Array.isArray(every)) {
22539
+ return;
22504
22540
  }
22505
- let dir = import_path7.posix.dirname(import_path7.posix.normalize(entrypoint)) || ".";
22506
- if (dir === "") {
22507
- dir = ".";
22541
+ if (some !== void 0 && !Array.isArray(some)) {
22542
+ return;
22508
22543
  }
22509
- let reachedRoot = false;
22510
- while (!reachedRoot) {
22511
- for (const manifest of manifests) {
22512
- const manifestPath = dir === "." ? manifest : import_path7.posix.join(dir, manifest);
22513
- if (await (0, import_utils.hasFile)(fs5, manifestPath)) {
22514
- return dir;
22515
- }
22544
+ const check = async ({
22545
+ path: path6,
22546
+ matchContent,
22547
+ matchPackage
22548
+ }) => {
22549
+ if (matchPackage && matchContent) {
22550
+ throw new Error(
22551
+ `Cannot specify "matchPackage" and "matchContent" in the same detector for "${framework.slug}"`
22552
+ );
22516
22553
  }
22517
- if (dir === "." || dir === "/") {
22518
- reachedRoot = true;
22519
- } else {
22520
- const parent = import_path7.posix.dirname(dir);
22521
- if (!parent || parent === dir) {
22522
- reachedRoot = true;
22523
- } else {
22524
- dir = parent;
22554
+ if (matchPackage && path6) {
22555
+ throw new Error(
22556
+ `Cannot specify "matchPackage" and "path" in the same detector for "${framework.slug}" because "path" is assumed to be "package.json".`
22557
+ );
22558
+ }
22559
+ if (!path6 && !matchPackage) {
22560
+ throw new Error(
22561
+ `Must specify either "path" or "matchPackage" in detector for "${framework.slug}".`
22562
+ );
22563
+ }
22564
+ if (!path6) {
22565
+ path6 = "package.json";
22566
+ }
22567
+ if (matchPackage) {
22568
+ matchContent = `"(dev)?(d|D)ependencies":\\s*{[^}]*"${matchPackage}":\\s*"(.+?)"[^}]*}`;
22569
+ }
22570
+ if (await fs5.hasPath(path6) === false) {
22571
+ return;
22572
+ }
22573
+ if (matchContent) {
22574
+ if (await fs5.isFile(path6) === false) {
22575
+ return;
22576
+ }
22577
+ const regex = new RegExp(matchContent, "m");
22578
+ const content = await fs5.readFile(path6);
22579
+ const match = content.toString().match(regex);
22580
+ if (!match) {
22581
+ return;
22582
+ }
22583
+ if (matchPackage && match[3]) {
22584
+ return {
22585
+ framework,
22586
+ detectedVersion: match[3]
22587
+ };
22525
22588
  }
22526
22589
  }
22527
- }
22528
- return void 0;
22529
- }
22530
- function isReservedServiceRoutePrefix(routePrefix) {
22531
- const normalized = (0, import_routing_utils.normalizeRoutePrefix)(routePrefix);
22532
- return normalized === import_utils.INTERNAL_SERVICE_PREFIX || normalized.startsWith(`${import_utils.INTERNAL_SERVICE_PREFIX}/`);
22533
- }
22534
- function validateServiceConfig(name, config) {
22535
- if (!SERVICE_NAME_REGEX.test(name)) {
22536
- return {
22537
- code: "INVALID_SERVICE_NAME",
22538
- 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.`,
22539
- serviceName: name
22540
- };
22541
- }
22542
- if (!config || typeof config !== "object") {
22543
- return {
22544
- code: "INVALID_SERVICE_CONFIG",
22545
- message: `Service "${name}" has an invalid configuration. Expected an object.`,
22546
- serviceName: name
22547
- };
22548
- }
22549
- const serviceType = config.type || "web";
22550
- if (serviceType === "web" && !config.routePrefix) {
22551
- return {
22552
- code: "MISSING_ROUTE_PREFIX",
22553
- message: `Web service "${name}" must specify "routePrefix".`,
22554
- serviceName: name
22555
- };
22556
- }
22557
- if (serviceType === "web" && config.routePrefix && isReservedServiceRoutePrefix(config.routePrefix)) {
22558
22590
  return {
22559
- code: "RESERVED_ROUTE_PREFIX",
22560
- message: `Web service "${name}" cannot use routePrefix "${config.routePrefix}". The "${import_utils.INTERNAL_SERVICE_PREFIX}" prefix is reserved for internal services routing.`,
22561
- serviceName: name
22591
+ framework
22562
22592
  };
22593
+ };
22594
+ const result = [];
22595
+ if (every) {
22596
+ const everyResult = await Promise.all(every.map((item) => check(item)));
22597
+ result.push(...everyResult);
22563
22598
  }
22564
- if ((serviceType === "worker" || serviceType === "cron") && config.routePrefix) {
22565
- return {
22566
- code: "INVALID_ROUTE_PREFIX",
22567
- message: `${serviceType === "worker" ? "Worker" : "Cron"} service "${name}" cannot have "routePrefix". Only web services should specify "routePrefix".`,
22568
- serviceName: name
22569
- };
22599
+ if (some) {
22600
+ let someResult;
22601
+ for (const item of some) {
22602
+ const itemResult = await check(item);
22603
+ if (itemResult) {
22604
+ someResult = itemResult;
22605
+ break;
22606
+ }
22607
+ }
22608
+ result.push(someResult);
22570
22609
  }
22571
- if (serviceType === "cron" && !config.schedule) {
22572
- return {
22573
- code: "MISSING_CRON_SCHEDULE",
22574
- message: `Cron service "${name}" is missing required "schedule" field.`,
22575
- serviceName: name
22576
- };
22610
+ if (!result.every((res) => !!res)) {
22611
+ return;
22577
22612
  }
22578
- if (config.runtime && !(config.runtime in import_types.RUNTIME_BUILDERS)) {
22579
- return {
22580
- code: "INVALID_RUNTIME",
22581
- message: `Service "${name}" has invalid runtime "${config.runtime}".`,
22582
- serviceName: name
22583
- };
22584
- }
22585
- if (config.framework && !frameworksBySlug.has(config.framework)) {
22586
- return {
22587
- code: "INVALID_FRAMEWORK",
22588
- message: `Service "${name}" has invalid framework "${config.framework}".`,
22589
- serviceName: name
22590
- };
22591
- }
22592
- const hasFramework = Boolean(config.framework);
22593
- const hasBuilderOrRuntime = Boolean(config.builder || config.runtime);
22594
- const hasEntrypoint = Boolean(config.entrypoint);
22595
- if (!hasFramework && !hasBuilderOrRuntime && !hasEntrypoint) {
22596
- return {
22597
- code: "MISSING_SERVICE_CONFIG",
22598
- message: `Service "${name}" must specify "framework", "entrypoint", or both "builder"/"runtime" with "entrypoint".`,
22599
- serviceName: name
22600
- };
22601
- }
22602
- if (hasBuilderOrRuntime && !hasFramework && !hasEntrypoint) {
22603
- return {
22604
- code: "MISSING_ENTRYPOINT",
22605
- message: `Service "${name}" must specify "entrypoint" when using "${config.builder ? "builder" : "runtime"}".`,
22606
- serviceName: name
22607
- };
22608
- }
22609
- if (hasEntrypoint && !hasBuilderOrRuntime && !hasFramework) {
22610
- const runtime = (0, import_utils.inferServiceRuntime)({ entrypoint: config.entrypoint });
22611
- if (!runtime) {
22612
- const supported = Object.keys(import_types.ENTRYPOINT_EXTENSIONS).join(", ");
22613
- return {
22614
- code: "UNSUPPORTED_ENTRYPOINT",
22615
- message: `Service "${name}" has unsupported entrypoint "${config.entrypoint}". Use a supported extension (${supported}) or specify "builder", "framework", or "runtime".`,
22616
- serviceName: name
22617
- };
22613
+ const detectedVersion = result.find(
22614
+ (r) => typeof r === "object" && r.detectedVersion
22615
+ )?.detectedVersion;
22616
+ return {
22617
+ framework,
22618
+ detectedVersion
22619
+ };
22620
+ }
22621
+ function removeSupersededFramework(matches2, slug) {
22622
+ const index = matches2.findIndex((f) => f?.slug === slug);
22623
+ const framework = matches2[index];
22624
+ if (framework) {
22625
+ if (framework.supersedes) {
22626
+ for (const slug2 of framework.supersedes) {
22627
+ removeSupersededFramework(matches2, slug2);
22628
+ }
22618
22629
  }
22630
+ matches2.splice(index, 1);
22619
22631
  }
22620
- return null;
22621
22632
  }
22622
- async function resolveConfiguredService(name, config, fs5, group) {
22623
- const type = config.type || "web";
22624
- const inferredRuntime = (0, import_utils.inferServiceRuntime)(config);
22625
- let workspace = config.workspace || ".";
22626
- let resolvedEntrypoint = config.entrypoint;
22627
- if (!config.workspace) {
22628
- const inferredWorkspace = await inferWorkspaceFromNearestManifest({
22629
- fs: fs5,
22630
- entrypoint: resolvedEntrypoint,
22631
- runtime: inferredRuntime
22632
- });
22633
- if (inferredWorkspace) {
22634
- workspace = inferredWorkspace;
22635
- if (resolvedEntrypoint) {
22636
- resolvedEntrypoint = toWorkspaceRelativeEntrypoint(
22637
- resolvedEntrypoint,
22638
- inferredWorkspace
22639
- );
22633
+ function removeSupersededFrameworks(matches2) {
22634
+ for (const match of matches2.slice()) {
22635
+ if (match?.supersedes) {
22636
+ for (const slug of match.supersedes) {
22637
+ removeSupersededFramework(matches2, slug);
22640
22638
  }
22641
22639
  }
22642
22640
  }
22643
- const topic = type === "worker" ? config.topic || "default" : config.topic;
22644
- const consumer = type === "worker" ? config.consumer || "default" : config.consumer;
22645
- let builderUse;
22646
- let builderSrc;
22647
- if (config.framework) {
22648
- const framework = frameworksBySlug.get(config.framework);
22649
- builderUse = framework?.useRuntime?.use || "@vercel/static-build";
22650
- builderSrc = resolvedEntrypoint || framework?.useRuntime?.src || "package.json";
22651
- } else if (config.builder) {
22652
- builderUse = config.builder;
22653
- builderSrc = resolvedEntrypoint;
22654
- } else {
22655
- builderUse = (0, import_utils.getBuilderForRuntime)(inferredRuntime);
22656
- builderSrc = resolvedEntrypoint;
22657
- }
22658
- const routePrefix = type === "web" && config.routePrefix ? config.routePrefix.startsWith("/") ? config.routePrefix : `/${config.routePrefix}` : void 0;
22659
- const isRoot = workspace === ".";
22660
- if (!isRoot) {
22661
- builderSrc = import_path7.posix.join(workspace, builderSrc);
22662
- }
22663
- const builderConfig = { zeroConfig: true };
22664
- if (config.memory)
22665
- builderConfig.memory = config.memory;
22666
- if (config.maxDuration)
22667
- builderConfig.maxDuration = config.maxDuration;
22668
- if (config.includeFiles)
22669
- builderConfig.includeFiles = config.includeFiles;
22670
- if (config.excludeFiles)
22671
- builderConfig.excludeFiles = config.excludeFiles;
22672
- const isStaticBuild2 = import_types.STATIC_BUILDERS.has(builderUse);
22673
- const runtime = isStaticBuild2 ? void 0 : inferredRuntime;
22674
- if (routePrefix) {
22675
- const stripped = routePrefix.startsWith("/") ? routePrefix.slice(1) : routePrefix;
22676
- builderConfig.routePrefix = stripped || ".";
22677
- }
22678
- if (workspace && workspace !== ".") {
22679
- builderConfig.workspace = workspace;
22680
- }
22681
- if (config.framework) {
22682
- builderConfig.framework = config.framework;
22683
- }
22684
- return {
22685
- name,
22686
- type,
22687
- group,
22688
- workspace,
22689
- entrypoint: resolvedEntrypoint,
22690
- routePrefix,
22691
- framework: config.framework,
22692
- builder: {
22693
- src: builderSrc,
22694
- use: builderUse,
22695
- config: Object.keys(builderConfig).length > 0 ? builderConfig : void 0
22696
- },
22697
- runtime,
22698
- buildCommand: config.buildCommand,
22699
- installCommand: config.installCommand,
22700
- schedule: config.schedule,
22701
- topic,
22702
- consumer
22703
- };
22704
22641
  }
22705
- async function resolveAllConfiguredServices(services, fs5) {
22706
- const resolved = [];
22707
- const errors = [];
22708
- const webServicesByRoutePrefix = /* @__PURE__ */ new Map();
22709
- for (const name of Object.keys(services)) {
22710
- const serviceConfig = services[name];
22711
- const validationError = validateServiceConfig(name, serviceConfig);
22712
- if (validationError) {
22713
- errors.push(validationError);
22714
- continue;
22715
- }
22716
- const service = await resolveConfiguredService(name, serviceConfig, fs5);
22717
- if (service.type === "web" && typeof service.routePrefix === "string") {
22718
- const normalizedRoutePrefix = (0, import_routing_utils.normalizeRoutePrefix)(service.routePrefix);
22719
- const existingServiceName = webServicesByRoutePrefix.get(
22720
- normalizedRoutePrefix
22721
- );
22722
- if (existingServiceName) {
22723
- errors.push({
22724
- code: "DUPLICATE_ROUTE_PREFIX",
22725
- message: `Web services "${existingServiceName}" and "${name}" cannot share routePrefix "${normalizedRoutePrefix}".`,
22726
- serviceName: name
22727
- });
22728
- continue;
22642
+ async function detectFramework2({
22643
+ fs: fs5,
22644
+ frameworkList,
22645
+ useExperimentalFrameworks
22646
+ }) {
22647
+ const filteredList = filterFrameworkList(
22648
+ frameworkList,
22649
+ useExperimentalFrameworks
22650
+ );
22651
+ const result = await Promise.all(
22652
+ filteredList.map(async (frameworkMatch) => {
22653
+ if (await matches(fs5, frameworkMatch)) {
22654
+ return frameworkMatch;
22729
22655
  }
22730
- webServicesByRoutePrefix.set(normalizedRoutePrefix, name);
22731
- }
22732
- resolved.push(service);
22656
+ return null;
22657
+ })
22658
+ );
22659
+ removeSupersededFrameworks(result);
22660
+ return result.find((res) => res !== null)?.slug ?? null;
22661
+ }
22662
+ async function detectFrameworks2({
22663
+ fs: fs5,
22664
+ frameworkList,
22665
+ useExperimentalFrameworks
22666
+ }) {
22667
+ const filteredList = filterFrameworkList(
22668
+ frameworkList,
22669
+ useExperimentalFrameworks
22670
+ );
22671
+ const result = await Promise.all(
22672
+ filteredList.map(async (frameworkMatch) => {
22673
+ if (await matches(fs5, frameworkMatch)) {
22674
+ return frameworkMatch;
22675
+ }
22676
+ return null;
22677
+ })
22678
+ );
22679
+ removeSupersededFrameworks(result);
22680
+ return result.filter((res) => res !== null);
22681
+ }
22682
+ async function detectFrameworkRecord3({
22683
+ fs: fs5,
22684
+ frameworkList,
22685
+ useExperimentalFrameworks
22686
+ }) {
22687
+ const filteredList = filterFrameworkList(
22688
+ frameworkList,
22689
+ useExperimentalFrameworks
22690
+ );
22691
+ const result = await Promise.all(
22692
+ filteredList.map(async (frameworkMatch) => {
22693
+ const matchResult = await matches(fs5, frameworkMatch);
22694
+ if (matchResult) {
22695
+ return {
22696
+ ...frameworkMatch,
22697
+ detectedVersion: matchResult?.detectedVersion
22698
+ };
22699
+ }
22700
+ return null;
22701
+ })
22702
+ );
22703
+ removeSupersededFrameworks(result);
22704
+ return result.find((res) => res !== null) ?? null;
22705
+ }
22706
+ function detectFrameworkVersion2(frameworkRecord) {
22707
+ const allDetectors = [
22708
+ ...frameworkRecord.detectors?.every || [],
22709
+ ...frameworkRecord.detectors?.some || []
22710
+ ];
22711
+ const firstMatchPackage = allDetectors.find((d) => d.matchPackage);
22712
+ if (!firstMatchPackage?.matchPackage) {
22713
+ return;
22733
22714
  }
22734
- return { services: resolved, errors };
22715
+ return lookupInstalledVersion(
22716
+ process.execPath,
22717
+ firstMatchPackage.matchPackage
22718
+ );
22719
+ }
22720
+ function lookupInstalledVersion(cwd, packageName) {
22721
+ try {
22722
+ const script = `require('${packageName}/package.json').version`;
22723
+ return (0, import_child_process2.spawnSync)(cwd, ["-p", script], {
22724
+ encoding: "utf-8"
22725
+ }).stdout.trim();
22726
+ } catch (error) {
22727
+ console.debug(
22728
+ `Error looking up version of installed package "${packageName}": ${error}`
22729
+ );
22730
+ }
22731
+ return;
22735
22732
  }
22736
22733
  }
22737
22734
  });
22738
22735
 
22739
- // ../fs-detectors/dist/detect-framework.js
22740
- var require_detect_framework = __commonJS({
22741
- "../fs-detectors/dist/detect-framework.js"(exports2, module2) {
22736
+ // ../fs-detectors/dist/services/resolve.js
22737
+ var require_resolve = __commonJS({
22738
+ "../fs-detectors/dist/services/resolve.js"(exports2, module2) {
22742
22739
  "use strict";
22740
+ var __create2 = Object.create;
22743
22741
  var __defProp2 = Object.defineProperty;
22744
22742
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
22745
22743
  var __getOwnPropNames2 = Object.getOwnPropertyNames;
22744
+ var __getProtoOf2 = Object.getPrototypeOf;
22746
22745
  var __hasOwnProp2 = Object.prototype.hasOwnProperty;
22747
22746
  var __export2 = (target, all) => {
22748
22747
  for (var name in all)
@@ -22756,234 +22755,434 @@ var require_detect_framework = __commonJS({
22756
22755
  }
22757
22756
  return to;
22758
22757
  };
22759
- var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
22760
- var detect_framework_exports = {};
22761
- __export2(detect_framework_exports, {
22762
- detectFramework: () => detectFramework2,
22763
- detectFrameworkRecord: () => detectFrameworkRecord3,
22764
- detectFrameworkVersion: () => detectFrameworkVersion2,
22765
- detectFrameworks: () => detectFrameworks2,
22766
- removeSupersededFrameworks: () => removeSupersededFrameworks
22758
+ var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps2(
22759
+ // If the importer is in node compatibility mode or this is not an ESM
22760
+ // file that has been converted to a CommonJS file using a Babel-
22761
+ // compatible transform (i.e. "__esModule" has not been set), then set
22762
+ // "default" to the CommonJS "module.exports" for node compatibility.
22763
+ isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
22764
+ mod
22765
+ ));
22766
+ var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
22767
+ var resolve_exports = {};
22768
+ __export2(resolve_exports, {
22769
+ resolveAllConfiguredServices: () => resolveAllConfiguredServices,
22770
+ resolveConfiguredService: () => resolveConfiguredService,
22771
+ validateServiceConfig: () => validateServiceConfig,
22772
+ validateServiceEntrypoint: () => validateServiceEntrypoint
22767
22773
  });
22768
- module2.exports = __toCommonJS2(detect_framework_exports);
22769
- var import_child_process2 = require("child_process");
22770
- function shouldIncludeExperimentalFrameworks(useExperimentalFrameworks) {
22771
- if (typeof useExperimentalFrameworks === "boolean") {
22772
- return useExperimentalFrameworks;
22774
+ module2.exports = __toCommonJS2(resolve_exports);
22775
+ var import_path7 = require("path");
22776
+ var import_types = require_types3();
22777
+ var import_utils = require_utils4();
22778
+ var import_frameworks2 = __toESM2(require_frameworks());
22779
+ var import_detect_framework = require_detect_framework();
22780
+ var import_routing_utils = require_dist6();
22781
+ var frameworksBySlug = new Map(import_frameworks2.default.map((f) => [f.slug, f]));
22782
+ var SERVICE_NAME_REGEX = /^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;
22783
+ function normalizeServiceEntrypoint(entrypoint) {
22784
+ const normalized = import_path7.posix.normalize(entrypoint);
22785
+ return normalized === "" ? "." : normalized;
22786
+ }
22787
+ async function resolveEntrypointPath({
22788
+ fs: fs5,
22789
+ serviceName,
22790
+ entrypoint
22791
+ }) {
22792
+ const normalized = normalizeServiceEntrypoint(entrypoint);
22793
+ if (!await fs5.hasPath(normalized)) {
22794
+ return {
22795
+ error: {
22796
+ code: "ENTRYPOINT_NOT_FOUND",
22797
+ message: `Service "${serviceName}" has entrypoint "${entrypoint}" but that path does not exist.`,
22798
+ serviceName
22799
+ }
22800
+ };
22773
22801
  }
22774
- const experimentalEnv = process.env.VERCEL_USE_EXPERIMENTAL_FRAMEWORKS;
22775
- const isEnabled = (val) => val === "1" || typeof val === "string" && val.toLowerCase() === "true";
22776
- return isEnabled(experimentalEnv);
22802
+ return {
22803
+ entrypoint: {
22804
+ normalized,
22805
+ isDirectory: !await fs5.isFile(normalized)
22806
+ }
22807
+ };
22777
22808
  }
22778
- function filterFrameworkList(frameworkList, useExperimentalFrameworks) {
22779
- if (shouldIncludeExperimentalFrameworks(useExperimentalFrameworks)) {
22780
- return frameworkList;
22809
+ function toWorkspaceRelativeEntrypoint(entrypoint, workspace) {
22810
+ const normalizedEntrypoint = import_path7.posix.normalize(entrypoint);
22811
+ if (workspace === ".") {
22812
+ return normalizedEntrypoint;
22781
22813
  }
22782
- return frameworkList.filter((f) => {
22783
- const experimental = f.experimental;
22784
- return !experimental;
22785
- });
22814
+ const workspacePrefix = `${workspace}/`;
22815
+ if (normalizedEntrypoint.startsWith(workspacePrefix)) {
22816
+ return normalizedEntrypoint.slice(workspacePrefix.length);
22817
+ }
22818
+ const relativeEntrypoint = import_path7.posix.relative(
22819
+ workspace,
22820
+ normalizedEntrypoint
22821
+ );
22822
+ if (relativeEntrypoint === "" || relativeEntrypoint.startsWith("..")) {
22823
+ return normalizedEntrypoint;
22824
+ }
22825
+ return relativeEntrypoint;
22786
22826
  }
22787
- async function matches(fs5, framework) {
22788
- const { detectors } = framework;
22789
- if (!detectors) {
22790
- return;
22827
+ async function inferWorkspaceFromNearestManifest({
22828
+ fs: fs5,
22829
+ entrypoint,
22830
+ runtime
22831
+ }) {
22832
+ if (!entrypoint || !runtime) {
22833
+ return void 0;
22791
22834
  }
22792
- const { every, some } = detectors;
22793
- if (every !== void 0 && !Array.isArray(every)) {
22794
- return;
22835
+ const manifests = import_types.RUNTIME_MANIFESTS[runtime];
22836
+ if (!manifests || manifests.length === 0) {
22837
+ return void 0;
22795
22838
  }
22796
- if (some !== void 0 && !Array.isArray(some)) {
22797
- return;
22839
+ let dir = import_path7.posix.dirname(import_path7.posix.normalize(entrypoint)) || ".";
22840
+ if (dir === "") {
22841
+ dir = ".";
22798
22842
  }
22799
- const check = async ({
22800
- path: path6,
22801
- matchContent,
22802
- matchPackage
22803
- }) => {
22804
- if (matchPackage && matchContent) {
22805
- throw new Error(
22806
- `Cannot specify "matchPackage" and "matchContent" in the same detector for "${framework.slug}"`
22807
- );
22808
- }
22809
- if (matchPackage && path6) {
22810
- throw new Error(
22811
- `Cannot specify "matchPackage" and "path" in the same detector for "${framework.slug}" because "path" is assumed to be "package.json".`
22812
- );
22813
- }
22814
- if (!path6 && !matchPackage) {
22815
- throw new Error(
22816
- `Must specify either "path" or "matchPackage" in detector for "${framework.slug}".`
22817
- );
22818
- }
22819
- if (!path6) {
22820
- path6 = "package.json";
22821
- }
22822
- if (matchPackage) {
22823
- matchContent = `"(dev)?(d|D)ependencies":\\s*{[^}]*"${matchPackage}":\\s*"(.+?)"[^}]*}`;
22824
- }
22825
- if (await fs5.hasPath(path6) === false) {
22826
- return;
22827
- }
22828
- if (matchContent) {
22829
- if (await fs5.isFile(path6) === false) {
22830
- return;
22831
- }
22832
- const regex = new RegExp(matchContent, "m");
22833
- const content = await fs5.readFile(path6);
22834
- const match = content.toString().match(regex);
22835
- if (!match) {
22836
- return;
22843
+ let reachedRoot = false;
22844
+ while (!reachedRoot) {
22845
+ for (const manifest of manifests) {
22846
+ const manifestPath = dir === "." ? manifest : import_path7.posix.join(dir, manifest);
22847
+ if (await (0, import_utils.hasFile)(fs5, manifestPath)) {
22848
+ return dir;
22837
22849
  }
22838
- if (matchPackage && match[3]) {
22839
- return {
22840
- framework,
22841
- detectedVersion: match[3]
22842
- };
22850
+ }
22851
+ if (dir === "." || dir === "/") {
22852
+ reachedRoot = true;
22853
+ } else {
22854
+ const parent = import_path7.posix.dirname(dir);
22855
+ if (!parent || parent === dir) {
22856
+ reachedRoot = true;
22857
+ } else {
22858
+ dir = parent;
22843
22859
  }
22844
22860
  }
22861
+ }
22862
+ return void 0;
22863
+ }
22864
+ async function detectFrameworkFromWorkspace({
22865
+ fs: fs5,
22866
+ workspace,
22867
+ serviceName
22868
+ }) {
22869
+ const serviceFs = workspace === "." ? fs5 : fs5.chdir(workspace);
22870
+ const frameworks2 = await (0, import_detect_framework.detectFrameworks)({
22871
+ fs: serviceFs,
22872
+ frameworkList: import_frameworks2.default
22873
+ });
22874
+ if (frameworks2.length > 1) {
22875
+ const frameworkNames = frameworks2.map((f) => f.name).join(", ");
22845
22876
  return {
22846
- framework
22877
+ error: {
22878
+ code: "MULTIPLE_FRAMEWORKS_SERVICE",
22879
+ message: `Multiple frameworks detected in ${workspace === "." ? "project root" : `${workspace}/`}: ${frameworkNames}. Specify "framework" explicitly in experimentalServices.`,
22880
+ serviceName
22881
+ }
22847
22882
  };
22848
- };
22849
- const result = [];
22850
- if (every) {
22851
- const everyResult = await Promise.all(every.map((item) => check(item)));
22852
- result.push(...everyResult);
22853
22883
  }
22854
- if (some) {
22855
- let someResult;
22856
- for (const item of some) {
22857
- const itemResult = await check(item);
22858
- if (itemResult) {
22859
- someResult = itemResult;
22860
- break;
22884
+ if (frameworks2.length === 1) {
22885
+ return {
22886
+ framework: frameworks2[0].slug ?? void 0
22887
+ };
22888
+ }
22889
+ return {};
22890
+ }
22891
+ function isReservedServiceRoutePrefix(routePrefix) {
22892
+ const normalized = (0, import_routing_utils.normalizeRoutePrefix)(routePrefix);
22893
+ return normalized === import_utils.INTERNAL_SERVICE_PREFIX || normalized.startsWith(`${import_utils.INTERNAL_SERVICE_PREFIX}/`);
22894
+ }
22895
+ function validateServiceConfig(name, config) {
22896
+ if (!SERVICE_NAME_REGEX.test(name)) {
22897
+ return {
22898
+ code: "INVALID_SERVICE_NAME",
22899
+ 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.`,
22900
+ serviceName: name
22901
+ };
22902
+ }
22903
+ if (!config || typeof config !== "object") {
22904
+ return {
22905
+ code: "INVALID_SERVICE_CONFIG",
22906
+ message: `Service "${name}" has an invalid configuration. Expected an object.`,
22907
+ serviceName: name
22908
+ };
22909
+ }
22910
+ const serviceType = config.type || "web";
22911
+ if (serviceType === "web" && !config.routePrefix) {
22912
+ return {
22913
+ code: "MISSING_ROUTE_PREFIX",
22914
+ message: `Web service "${name}" must specify "routePrefix".`,
22915
+ serviceName: name
22916
+ };
22917
+ }
22918
+ if (serviceType === "web" && config.routePrefix && isReservedServiceRoutePrefix(config.routePrefix)) {
22919
+ return {
22920
+ code: "RESERVED_ROUTE_PREFIX",
22921
+ message: `Web service "${name}" cannot use routePrefix "${config.routePrefix}". The "${import_utils.INTERNAL_SERVICE_PREFIX}" prefix is reserved for internal services routing.`,
22922
+ serviceName: name
22923
+ };
22924
+ }
22925
+ if ((serviceType === "worker" || serviceType === "cron") && config.routePrefix) {
22926
+ return {
22927
+ code: "INVALID_ROUTE_PREFIX",
22928
+ message: `${serviceType === "worker" ? "Worker" : "Cron"} service "${name}" cannot have "routePrefix". Only web services should specify "routePrefix".`,
22929
+ serviceName: name
22930
+ };
22931
+ }
22932
+ if (serviceType === "cron" && !config.schedule) {
22933
+ return {
22934
+ code: "MISSING_CRON_SCHEDULE",
22935
+ message: `Cron service "${name}" is missing required "schedule" field.`,
22936
+ serviceName: name
22937
+ };
22938
+ }
22939
+ if (config.runtime && !(config.runtime in import_types.RUNTIME_BUILDERS)) {
22940
+ return {
22941
+ code: "INVALID_RUNTIME",
22942
+ message: `Service "${name}" has invalid runtime "${config.runtime}".`,
22943
+ serviceName: name
22944
+ };
22945
+ }
22946
+ if (config.framework && !frameworksBySlug.has(config.framework)) {
22947
+ return {
22948
+ code: "INVALID_FRAMEWORK",
22949
+ message: `Service "${name}" has invalid framework "${config.framework}".`,
22950
+ serviceName: name
22951
+ };
22952
+ }
22953
+ const hasFramework = Boolean(config.framework);
22954
+ const hasBuilderOrRuntime = Boolean(config.builder || config.runtime);
22955
+ const hasEntrypoint = Boolean(config.entrypoint);
22956
+ if (!hasFramework && !hasBuilderOrRuntime && !hasEntrypoint) {
22957
+ return {
22958
+ code: "MISSING_SERVICE_CONFIG",
22959
+ message: `Service "${name}" must specify "framework", "entrypoint", or both "builder"/"runtime" with "entrypoint".`,
22960
+ serviceName: name
22961
+ };
22962
+ }
22963
+ if (hasBuilderOrRuntime && !hasFramework && !hasEntrypoint) {
22964
+ return {
22965
+ code: "MISSING_ENTRYPOINT",
22966
+ message: `Service "${name}" must specify "entrypoint" when using "${config.builder ? "builder" : "runtime"}".`,
22967
+ serviceName: name
22968
+ };
22969
+ }
22970
+ return null;
22971
+ }
22972
+ function validateServiceEntrypoint(name, config, resolvedEntrypoint) {
22973
+ if (!resolvedEntrypoint.isDirectory && !config.builder && !config.runtime && !config.framework) {
22974
+ const runtime = (0, import_utils.inferServiceRuntime)({ entrypoint: config.entrypoint });
22975
+ if (!runtime) {
22976
+ const supported = Object.keys(import_types.ENTRYPOINT_EXTENSIONS).join(", ");
22977
+ return {
22978
+ code: "UNSUPPORTED_ENTRYPOINT",
22979
+ message: `Service "${name}" has unsupported entrypoint "${config.entrypoint}". Use a supported extension (${supported}) or specify "builder", "framework", or "runtime".`,
22980
+ serviceName: name
22981
+ };
22982
+ }
22983
+ }
22984
+ return null;
22985
+ }
22986
+ async function resolveConfiguredService(options) {
22987
+ const {
22988
+ name,
22989
+ config,
22990
+ fs: fs5,
22991
+ group,
22992
+ resolvedEntrypoint,
22993
+ routePrefixSource = "configured"
22994
+ } = options;
22995
+ const type = config.type || "web";
22996
+ const rawEntrypoint = config.entrypoint;
22997
+ let resolvedEntrypointPath = resolvedEntrypoint;
22998
+ if (!resolvedEntrypointPath && typeof rawEntrypoint === "string") {
22999
+ const resolved = await resolveEntrypointPath({
23000
+ fs: fs5,
23001
+ serviceName: name,
23002
+ entrypoint: rawEntrypoint
23003
+ });
23004
+ resolvedEntrypointPath = resolved.entrypoint;
23005
+ }
23006
+ if (typeof rawEntrypoint === "string" && !resolvedEntrypointPath) {
23007
+ throw new Error(
23008
+ `Failed to resolve entrypoint "${rawEntrypoint}" for service "${name}".`
23009
+ );
23010
+ }
23011
+ const normalizedEntrypoint = resolvedEntrypointPath?.normalized;
23012
+ const entrypointIsDirectory = Boolean(resolvedEntrypointPath?.isDirectory);
23013
+ const inferredRuntime = (0, import_utils.inferServiceRuntime)({
23014
+ ...config,
23015
+ entrypoint: entrypointIsDirectory ? void 0 : normalizedEntrypoint
23016
+ });
23017
+ let workspace = ".";
23018
+ let resolvedEntrypointFile = entrypointIsDirectory || !normalizedEntrypoint ? void 0 : normalizedEntrypoint;
23019
+ if (entrypointIsDirectory && normalizedEntrypoint) {
23020
+ workspace = normalizedEntrypoint;
23021
+ } else {
23022
+ const inferredWorkspace = await inferWorkspaceFromNearestManifest({
23023
+ fs: fs5,
23024
+ entrypoint: resolvedEntrypointFile,
23025
+ runtime: inferredRuntime
23026
+ });
23027
+ if (inferredWorkspace) {
23028
+ workspace = inferredWorkspace;
23029
+ if (resolvedEntrypointFile) {
23030
+ resolvedEntrypointFile = toWorkspaceRelativeEntrypoint(
23031
+ resolvedEntrypointFile,
23032
+ inferredWorkspace
23033
+ );
22861
23034
  }
22862
23035
  }
22863
- result.push(someResult);
22864
23036
  }
22865
- if (!result.every((res) => !!res)) {
22866
- return;
23037
+ const topic = type === "worker" ? config.topic || "default" : config.topic;
23038
+ const consumer = type === "worker" ? config.consumer || "default" : config.consumer;
23039
+ let builderUse;
23040
+ let builderSrc;
23041
+ if (config.framework) {
23042
+ const framework = frameworksBySlug.get(config.framework);
23043
+ builderUse = framework?.useRuntime?.use || "@vercel/static-build";
23044
+ builderSrc = resolvedEntrypointFile || framework?.useRuntime?.src || "package.json";
23045
+ } else if (config.builder) {
23046
+ builderUse = config.builder;
23047
+ builderSrc = resolvedEntrypointFile;
23048
+ } else {
23049
+ builderUse = (0, import_utils.getBuilderForRuntime)(inferredRuntime);
23050
+ builderSrc = resolvedEntrypointFile;
23051
+ }
23052
+ const routePrefix = type === "web" && config.routePrefix ? config.routePrefix.startsWith("/") ? config.routePrefix : `/${config.routePrefix}` : void 0;
23053
+ const isRoot = workspace === ".";
23054
+ if (!isRoot) {
23055
+ builderSrc = import_path7.posix.join(workspace, builderSrc);
23056
+ }
23057
+ const builderConfig = { zeroConfig: true };
23058
+ if (config.memory)
23059
+ builderConfig.memory = config.memory;
23060
+ if (config.maxDuration)
23061
+ builderConfig.maxDuration = config.maxDuration;
23062
+ if (config.includeFiles)
23063
+ builderConfig.includeFiles = config.includeFiles;
23064
+ if (config.excludeFiles)
23065
+ builderConfig.excludeFiles = config.excludeFiles;
23066
+ const isStaticBuild2 = import_types.STATIC_BUILDERS.has(builderUse);
23067
+ const runtime = isStaticBuild2 ? void 0 : inferredRuntime;
23068
+ if (routePrefix) {
23069
+ const stripped = routePrefix.startsWith("/") ? routePrefix.slice(1) : routePrefix;
23070
+ builderConfig.routePrefix = stripped || ".";
23071
+ }
23072
+ if (workspace && workspace !== ".") {
23073
+ builderConfig.workspace = workspace;
23074
+ }
23075
+ if (config.framework) {
23076
+ builderConfig.framework = config.framework;
22867
23077
  }
22868
- const detectedVersion = result.find(
22869
- (r) => typeof r === "object" && r.detectedVersion
22870
- )?.detectedVersion;
22871
23078
  return {
22872
- framework,
22873
- detectedVersion
23079
+ name,
23080
+ type,
23081
+ group,
23082
+ workspace,
23083
+ entrypoint: resolvedEntrypointFile,
23084
+ routePrefix,
23085
+ routePrefixSource: type === "web" && typeof routePrefix === "string" ? routePrefixSource : void 0,
23086
+ framework: config.framework,
23087
+ builder: {
23088
+ src: builderSrc,
23089
+ use: builderUse,
23090
+ config: Object.keys(builderConfig).length > 0 ? builderConfig : void 0
23091
+ },
23092
+ runtime,
23093
+ buildCommand: config.buildCommand,
23094
+ installCommand: config.installCommand,
23095
+ schedule: config.schedule,
23096
+ topic,
23097
+ consumer
22874
23098
  };
22875
23099
  }
22876
- function removeSupersededFramework(matches2, slug) {
22877
- const index = matches2.findIndex((f) => f?.slug === slug);
22878
- const framework = matches2[index];
22879
- if (framework) {
22880
- if (framework.supersedes) {
22881
- for (const slug2 of framework.supersedes) {
22882
- removeSupersededFramework(matches2, slug2);
23100
+ async function resolveAllConfiguredServices(services, fs5, routePrefixSource = "configured") {
23101
+ const resolved = [];
23102
+ const errors = [];
23103
+ const webServicesByRoutePrefix = /* @__PURE__ */ new Map();
23104
+ for (const name of Object.keys(services)) {
23105
+ const serviceConfig = services[name];
23106
+ const validationError = validateServiceConfig(name, serviceConfig);
23107
+ if (validationError) {
23108
+ errors.push(validationError);
23109
+ continue;
23110
+ }
23111
+ let resolvedEntrypoint;
23112
+ if (typeof serviceConfig.entrypoint === "string") {
23113
+ const resolvedPath = await resolveEntrypointPath({
23114
+ fs: fs5,
23115
+ serviceName: name,
23116
+ entrypoint: serviceConfig.entrypoint
23117
+ });
23118
+ if (resolvedPath.error) {
23119
+ errors.push(resolvedPath.error);
23120
+ continue;
22883
23121
  }
23122
+ resolvedEntrypoint = resolvedPath.entrypoint;
22884
23123
  }
22885
- matches2.splice(index, 1);
22886
- }
22887
- }
22888
- function removeSupersededFrameworks(matches2) {
22889
- for (const match of matches2.slice()) {
22890
- if (match?.supersedes) {
22891
- for (const slug of match.supersedes) {
22892
- removeSupersededFramework(matches2, slug);
23124
+ if (resolvedEntrypoint) {
23125
+ const entrypointError = validateServiceEntrypoint(
23126
+ name,
23127
+ serviceConfig,
23128
+ resolvedEntrypoint
23129
+ );
23130
+ if (entrypointError) {
23131
+ errors.push(entrypointError);
23132
+ continue;
22893
23133
  }
22894
23134
  }
22895
- }
22896
- }
22897
- async function detectFramework2({
22898
- fs: fs5,
22899
- frameworkList,
22900
- useExperimentalFrameworks
22901
- }) {
22902
- const filteredList = filterFrameworkList(
22903
- frameworkList,
22904
- useExperimentalFrameworks
22905
- );
22906
- const result = await Promise.all(
22907
- filteredList.map(async (frameworkMatch) => {
22908
- if (await matches(fs5, frameworkMatch)) {
22909
- return frameworkMatch;
23135
+ let resolvedConfig = serviceConfig;
23136
+ const shouldDetectFramework = !serviceConfig.framework && Boolean(resolvedEntrypoint?.isDirectory);
23137
+ if (shouldDetectFramework) {
23138
+ const workspace = resolvedEntrypoint.normalized;
23139
+ const { framework, error } = await detectFrameworkFromWorkspace({
23140
+ fs: fs5,
23141
+ workspace,
23142
+ serviceName: name
23143
+ });
23144
+ if (error) {
23145
+ errors.push(error);
23146
+ continue;
22910
23147
  }
22911
- return null;
22912
- })
22913
- );
22914
- removeSupersededFrameworks(result);
22915
- return result.find((res) => res !== null)?.slug ?? null;
22916
- }
22917
- async function detectFrameworks2({
22918
- fs: fs5,
22919
- frameworkList,
22920
- useExperimentalFrameworks
22921
- }) {
22922
- const filteredList = filterFrameworkList(
22923
- frameworkList,
22924
- useExperimentalFrameworks
22925
- );
22926
- const result = await Promise.all(
22927
- filteredList.map(async (frameworkMatch) => {
22928
- if (await matches(fs5, frameworkMatch)) {
22929
- return frameworkMatch;
23148
+ if (!framework) {
23149
+ errors.push({
23150
+ code: "MISSING_SERVICE_FRAMEWORK",
23151
+ message: `Service "${name}" uses directory entrypoint "${serviceConfig.entrypoint}" but no framework could be detected in "${workspace}". Specify "framework" explicitly or use a file entrypoint.`,
23152
+ serviceName: name
23153
+ });
23154
+ continue;
22930
23155
  }
22931
- return null;
22932
- })
22933
- );
22934
- removeSupersededFrameworks(result);
22935
- return result.filter((res) => res !== null);
22936
- }
22937
- async function detectFrameworkRecord3({
22938
- fs: fs5,
22939
- frameworkList,
22940
- useExperimentalFrameworks
22941
- }) {
22942
- const filteredList = filterFrameworkList(
22943
- frameworkList,
22944
- useExperimentalFrameworks
22945
- );
22946
- const result = await Promise.all(
22947
- filteredList.map(async (frameworkMatch) => {
22948
- const matchResult = await matches(fs5, frameworkMatch);
22949
- if (matchResult) {
22950
- return {
22951
- ...frameworkMatch,
22952
- detectedVersion: matchResult?.detectedVersion
22953
- };
23156
+ resolvedConfig = {
23157
+ ...serviceConfig,
23158
+ framework
23159
+ };
23160
+ }
23161
+ const service = await resolveConfiguredService({
23162
+ name,
23163
+ config: resolvedConfig,
23164
+ fs: fs5,
23165
+ resolvedEntrypoint,
23166
+ routePrefixSource
23167
+ });
23168
+ if (service.type === "web" && typeof service.routePrefix === "string") {
23169
+ const normalizedRoutePrefix = (0, import_routing_utils.normalizeRoutePrefix)(service.routePrefix);
23170
+ const existingServiceName = webServicesByRoutePrefix.get(
23171
+ normalizedRoutePrefix
23172
+ );
23173
+ if (existingServiceName) {
23174
+ errors.push({
23175
+ code: "DUPLICATE_ROUTE_PREFIX",
23176
+ message: `Web services "${existingServiceName}" and "${name}" cannot share routePrefix "${normalizedRoutePrefix}".`,
23177
+ serviceName: name
23178
+ });
23179
+ continue;
22954
23180
  }
22955
- return null;
22956
- })
22957
- );
22958
- removeSupersededFrameworks(result);
22959
- return result.find((res) => res !== null) ?? null;
22960
- }
22961
- function detectFrameworkVersion2(frameworkRecord) {
22962
- const allDetectors = [
22963
- ...frameworkRecord.detectors?.every || [],
22964
- ...frameworkRecord.detectors?.some || []
22965
- ];
22966
- const firstMatchPackage = allDetectors.find((d) => d.matchPackage);
22967
- if (!firstMatchPackage?.matchPackage) {
22968
- return;
22969
- }
22970
- return lookupInstalledVersion(
22971
- process.execPath,
22972
- firstMatchPackage.matchPackage
22973
- );
22974
- }
22975
- function lookupInstalledVersion(cwd, packageName) {
22976
- try {
22977
- const script = `require('${packageName}/package.json').version`;
22978
- return (0, import_child_process2.spawnSync)(cwd, ["-p", script], {
22979
- encoding: "utf-8"
22980
- }).stdout.trim();
22981
- } catch (error) {
22982
- console.debug(
22983
- `Error looking up version of installed package "${packageName}": ${error}`
22984
- );
23181
+ webServicesByRoutePrefix.set(normalizedRoutePrefix, name);
23182
+ }
23183
+ resolved.push(service);
22985
23184
  }
22986
- return;
23185
+ return { services: resolved, errors };
22987
23186
  }
22988
23187
  }
22989
23188
  });
@@ -23110,7 +23309,7 @@ var require_auto_detect = __commonJS({
23110
23309
  const serviceName = frontendLocation.split("/").pop() || "frontend";
23111
23310
  services[serviceName] = {
23112
23311
  framework: frontendFramework.slug ?? void 0,
23113
- workspace: frontendLocation,
23312
+ entrypoint: frontendLocation,
23114
23313
  routePrefix: "/"
23115
23314
  };
23116
23315
  const backendResult = await detectBackendServices(fs5);
@@ -23208,7 +23407,7 @@ var require_auto_detect = __commonJS({
23208
23407
  return {
23209
23408
  service: {
23210
23409
  framework: framework.slug ?? void 0,
23211
- workspace: dirPath,
23410
+ entrypoint: dirPath,
23212
23411
  routePrefix: `/_/${serviceName}`
23213
23412
  }
23214
23413
  };
@@ -23276,7 +23475,8 @@ var require_detect_services = __commonJS({
23276
23475
  if (autoResult.services) {
23277
23476
  const result2 = await (0, import_resolve.resolveAllConfiguredServices)(
23278
23477
  autoResult.services,
23279
- scopedFs
23478
+ scopedFs,
23479
+ "generated"
23280
23480
  );
23281
23481
  const routes2 = generateServicesRoutes2(result2.services);
23282
23482
  return {
@@ -23300,7 +23500,8 @@ var require_detect_services = __commonJS({
23300
23500
  }
23301
23501
  const result = await (0, import_resolve.resolveAllConfiguredServices)(
23302
23502
  configuredServices,
23303
- scopedFs
23503
+ scopedFs,
23504
+ "configured"
23304
23505
  );
23305
23506
  const routes = generateServicesRoutes2(result.services);
23306
23507
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/static-build",
3
- "version": "2.8.38",
3
+ "version": "2.8.40",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index",
6
6
  "homepage": "https://vercel.com/docs/build-step",
@@ -14,9 +14,9 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "ts-morph": "12.0.0",
17
- "@vercel/gatsby-plugin-vercel-analytics": "1.0.11",
17
+ "@vercel/gatsby-plugin-vercel-builder": "2.0.138",
18
18
  "@vercel/static-config": "3.1.2",
19
- "@vercel/gatsby-plugin-vercel-builder": "2.0.136"
19
+ "@vercel/gatsby-plugin-vercel-analytics": "1.0.11"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/aws-lambda": "8.10.64",
@@ -38,11 +38,11 @@
38
38
  "rc9": "1.2.0",
39
39
  "semver": "7.5.2",
40
40
  "tree-kill": "1.2.2",
41
- "@vercel/build-utils": "13.4.1",
42
- "@vercel/error-utils": "2.0.3",
41
+ "@vercel/frameworks": "3.18.0",
43
42
  "@vercel/routing-utils": "5.3.3",
44
- "@vercel/fs-detectors": "5.8.8",
45
- "@vercel/frameworks": "3.18.0"
43
+ "@vercel/build-utils": "13.4.3",
44
+ "@vercel/fs-detectors": "5.8.9",
45
+ "@vercel/error-utils": "2.0.3"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "node ../../utils/build-builder.mjs",