@vercel/fs-detectors 7.2.5 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ import type { ServiceRuntime } from '@vercel/build-utils';
2
+ /**
3
+ * Runtimes that can build container images with Cloud Native Buildpacks,
4
+ * with the files (any one of them, at the build root) that mark a project
5
+ * the buildpack can build. Keep this in sync with `@vercel/container`'s
6
+ * buildpack registry (`BUILDPACKS[].projectMarkers`).
7
+ *
8
+ * Routing is per runtime on purpose: the platform decides which buildpack to
9
+ * run from the language markers, and the buildpack classifies the application
10
+ * (for example Rails versus a plain Rack app) from its resolved bundle. There
11
+ * are no framework-level presets for buildpack runtimes.
12
+ */
13
+ export declare const BUILDPACK_PROJECT_MARKERS: ReadonlyMap<ServiceRuntime, readonly string[]>;
14
+ export declare function isBuildpackRuntimeEnabled(runtime: string): boolean;
15
+ /** The runtime's buildpack, when one exists and its flag is on. */
16
+ export declare function toBuildpackRuntime(runtime: string | null | undefined): ServiceRuntime | undefined;
17
+ /**
18
+ * Whether the build root carries one of the buildpack's project markers.
19
+ * `hasFile` is checked against exact root-relative names, never ancestors or
20
+ * nested directories: the buildpack stages the root as-is, and the legacy
21
+ * runtime keeps building projects that lack the marker.
22
+ */
23
+ export declare function hasBuildpackProjectMarker(runtime: ServiceRuntime, hasFile: (name: string) => Promise<boolean> | boolean): Promise<boolean>;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var buildpack_runtimes_exports = {};
20
+ __export(buildpack_runtimes_exports, {
21
+ BUILDPACK_PROJECT_MARKERS: () => BUILDPACK_PROJECT_MARKERS,
22
+ hasBuildpackProjectMarker: () => hasBuildpackProjectMarker,
23
+ isBuildpackRuntimeEnabled: () => isBuildpackRuntimeEnabled,
24
+ toBuildpackRuntime: () => toBuildpackRuntime
25
+ });
26
+ module.exports = __toCommonJS(buildpack_runtimes_exports);
27
+ const BUILDPACK_PROJECT_MARKERS = /* @__PURE__ */ new Map([["ruby", ["Gemfile"]]]);
28
+ function isBuildpackRuntimeEnabled(runtime) {
29
+ return process.env[`VERCEL_EXPERIMENTAL_BUILDPACK_${runtime.toUpperCase()}`] === "1";
30
+ }
31
+ function toBuildpackRuntime(runtime) {
32
+ if (!runtime || !BUILDPACK_PROJECT_MARKERS.has(runtime) || !isBuildpackRuntimeEnabled(runtime)) {
33
+ return void 0;
34
+ }
35
+ return runtime;
36
+ }
37
+ async function hasBuildpackProjectMarker(runtime, hasFile) {
38
+ for (const marker of BUILDPACK_PROJECT_MARKERS.get(runtime) ?? []) {
39
+ if (await hasFile(marker)) {
40
+ return true;
41
+ }
42
+ }
43
+ return false;
44
+ }
45
+ // Annotate the CommonJS export names for ESM import in node:
46
+ 0 && (module.exports = {
47
+ BUILDPACK_PROJECT_MARKERS,
48
+ hasBuildpackProjectMarker,
49
+ isBuildpackRuntimeEnabled,
50
+ toBuildpackRuntime
51
+ });
@@ -49,6 +49,7 @@ var import_frameworks = require("@vercel/frameworks");
49
49
  var import_is_official_runtime = require("./is-official-runtime");
50
50
  var import_build_utils = require("@vercel/build-utils");
51
51
  var import_python = require("./python");
52
+ var import_buildpack_runtimes = require("./buildpack-runtimes");
52
53
  const REGEX_MIDDLEWARE_FILES = "middleware.[jt]s";
53
54
  const VERCEL_PLATFORM_FILES = [
54
55
  "api/**",
@@ -588,6 +589,17 @@ function detectFrontBuilder(pkg, files, usedFunctions, fallbackEntrypoint, optio
588
589
  }
589
590
  const f = slugToFramework.get(framework || "");
590
591
  if (f && f.useRuntime && !isRustStaticOutput(framework, projectSettings)) {
592
+ const buildpackRuntime = (0, import_buildpack_runtimes.toBuildpackRuntime)(framework);
593
+ if (buildpackRuntime && (import_buildpack_runtimes.BUILDPACK_PROJECT_MARKERS.get(buildpackRuntime) ?? []).some(
594
+ (marker) => files.includes(marker)
595
+ )) {
596
+ config.buildpack = buildpackRuntime;
597
+ return {
598
+ src: "<detect>",
599
+ use: `@vercel/container${withTag}`,
600
+ config
601
+ };
602
+ }
591
603
  const { src, use } = f.useRuntime;
592
604
  const shouldUseUnifiedBackend = (0, import_build_utils.isExperimentalBackendsEnabled)() && import_build_utils.BACKEND_BUILDERS.includes(use);
593
605
  const finalUse = shouldUseUnifiedBackend ? import_build_utils.UNIFIED_BACKEND_BUILDER : use;
@@ -27,6 +27,7 @@ __export(detect_framework_exports, {
27
27
  module.exports = __toCommonJS(detect_framework_exports);
28
28
  var import_build_utils = require("@vercel/build-utils");
29
29
  var import_child_process = require("child_process");
30
+ var import_buildpack_runtimes = require("./buildpack-runtimes");
30
31
  function shouldIncludeExperimentalFrameworks(useExperimentalFrameworks) {
31
32
  if (typeof useExperimentalFrameworks === "boolean") {
32
33
  return useExperimentalFrameworks;
@@ -41,7 +42,10 @@ function filterFrameworkList(frameworkList, useExperimentalFrameworks) {
41
42
  }
42
43
  return frameworkList.filter((f) => {
43
44
  const experimental = f.experimental;
44
- return !experimental;
45
+ if (!experimental) {
46
+ return true;
47
+ }
48
+ return (0, import_buildpack_runtimes.toBuildpackRuntime)(f.slug) !== void 0;
45
49
  });
46
50
  }
47
51
  async function matches(fs, framework) {
@@ -25,6 +25,7 @@ __export(detect_services_exports, {
25
25
  module.exports = __toCommonJS(detect_services_exports);
26
26
  var import_build_utils = require("@vercel/build-utils");
27
27
  var import_routing_utils = require("@vercel/routing-utils");
28
+ var import_buildpack_runtimes = require("../buildpack-runtimes");
28
29
  var import_framework = require("./runtimes/framework");
29
30
  var import_utils = require("./utils");
30
31
  var import_resolve = require("./resolve");
@@ -60,6 +61,11 @@ function withResolvedResult(resolved, inferred = null) {
60
61
  inferred
61
62
  };
62
63
  }
64
+ function isBuildpackInferredService(svc) {
65
+ return (0, import_buildpack_runtimes.toBuildpackRuntime)(
66
+ svc.runtime ?? (0, import_framework.inferRuntimeFromFramework)(svc.framework)
67
+ ) !== void 0;
68
+ }
63
69
  function toInferredLayoutConfig(services) {
64
70
  const inferredConfig = {};
65
71
  for (const [name, service] of Object.entries(services)) {
@@ -69,7 +75,7 @@ function toInferredLayoutConfig(services) {
69
75
  if (service.type) {
70
76
  serviceConfig.type = service.type;
71
77
  }
72
- if (typeof service.entrypoint === "string") {
78
+ if (typeof service.entrypoint === "string" && !isBuildpackInferredService(service)) {
73
79
  serviceConfig.entrypoint = service.entrypoint;
74
80
  }
75
81
  if (typeof service.mountPath === "string") {
@@ -212,7 +218,7 @@ async function tryResolveInferred(detectResult, source, scopedFs) {
212
218
  v2Services[name] = {
213
219
  root: svc.root,
214
220
  ...svc.framework ? { framework: svc.framework } : {},
215
- ...svc.entrypoint ? { entrypoint: svc.entrypoint } : {}
221
+ ...svc.entrypoint && !isBuildpackInferredService(svc) ? { entrypoint: svc.entrypoint } : {}
216
222
  };
217
223
  }
218
224
  const result2 = await (0, import_resolve_v2.resolveAllConfiguredServicesV2)(v2Services, scopedFs);
@@ -245,7 +251,7 @@ async function tryResolveInferred(detectResult, source, scopedFs) {
245
251
  v1Services[name] = {
246
252
  root: svc.root === "." ? void 0 : svc.root,
247
253
  ...svc.framework ? { framework: svc.framework } : {},
248
- ...svc.entrypoint ? { entrypoint: svc.entrypoint } : {},
254
+ ...svc.entrypoint && !isBuildpackInferredService(svc) ? { entrypoint: svc.entrypoint } : {},
249
255
  ...svc.type ? { type: svc.type } : {},
250
256
  ...svc.buildCommand ? { buildCommand: svc.buildCommand } : {},
251
257
  ...svc.preDeployCommand ? { preDeployCommand: svc.preDeployCommand } : {},
@@ -30,7 +30,9 @@ var import_constants = require("./runtimes/constants");
30
30
  var import_framework = require("./runtimes/framework");
31
31
  var import_runtime = require("./runtimes/runtime");
32
32
  var import_entrypoint = require("./runtimes/entrypoint");
33
+ var import_buildpack_runtimes = require("../buildpack-runtimes");
33
34
  var import_resolve = require("./resolve");
35
+ var import_utils = require("./utils");
34
36
  const frameworksBySlug = new Map(import_frameworks.frameworkList.map((f) => [f.slug, f]));
35
37
  const MAX_SERVICE_NAME_LENGTH = 64;
36
38
  const SERVICE_NAME_REGEX = /^[a-z]([a-z_-]*[a-z])?$/;
@@ -234,7 +236,23 @@ async function resolveConfiguredServiceV2(name, config, fs) {
234
236
  entrypoint: entrypointFile
235
237
  });
236
238
  }
237
- if (entrypointIsDirectory && !framework) {
239
+ const flaggedBuildpackRuntime = (0, import_buildpack_runtimes.toBuildpackRuntime)(
240
+ inferredRuntime
241
+ );
242
+ if (flaggedBuildpackRuntime && config.command !== void 0) {
243
+ return {
244
+ error: {
245
+ code: "INVALID_COMMAND",
246
+ message: `Service "${name}" can only specify "command" when using runtime "container".`,
247
+ serviceName: name
248
+ }
249
+ };
250
+ }
251
+ const buildpackRuntime = flaggedBuildpackRuntime && !entrypointFile && !(0, import_framework.isFrontendFramework)(framework) && await (0, import_buildpack_runtimes.hasBuildpackProjectMarker)(
252
+ flaggedBuildpackRuntime,
253
+ (marker) => (0, import_utils.hasFile)(serviceFs, marker)
254
+ ) ? flaggedBuildpackRuntime : void 0;
255
+ if (entrypointIsDirectory && !framework && !buildpackRuntime) {
238
256
  return {
239
257
  error: {
240
258
  code: "MISSING_SERVICE_FRAMEWORK",
@@ -244,7 +262,7 @@ async function resolveConfiguredServiceV2(name, config, fs) {
244
262
  };
245
263
  }
246
264
  const frameworkRuntime = (0, import_framework.inferRuntimeFromFramework)(framework);
247
- if (detectedFramework && frameworkRuntime && !entrypointFile) {
265
+ if (detectedFramework && frameworkRuntime && !entrypointFile && !buildpackRuntime) {
248
266
  return {
249
267
  error: {
250
268
  code: "MISSING_SERVICE_CONFIG",
@@ -256,7 +274,10 @@ async function resolveConfiguredServiceV2(name, config, fs) {
256
274
  const frameworkDefinition = framework ? frameworksBySlug.get(framework) : void 0;
257
275
  let builderUse;
258
276
  let builderSrc;
259
- if (framework) {
277
+ if (buildpackRuntime) {
278
+ builderUse = "@vercel/container";
279
+ builderSrc = "<detect>";
280
+ } else if (framework) {
260
281
  builderUse = (0, import_build_utils.isNodeBackendFramework)(framework) ? "@vercel/backends" : frameworkDefinition?.useRuntime?.use || "@vercel/static-build";
261
282
  builderSrc = entrypointFile || frameworkDefinition?.useRuntime?.src || "package.json";
262
283
  } else {
@@ -291,6 +312,9 @@ async function resolveConfiguredServiceV2(name, config, fs) {
291
312
  if (framework) {
292
313
  builderConfig.framework = framework;
293
314
  }
315
+ if (buildpackRuntime) {
316
+ builderConfig.buildpack = buildpackRuntime;
317
+ }
294
318
  if (config.outputDirectory) {
295
319
  builderConfig.outputDirectory = config.outputDirectory;
296
320
  }
@@ -31,6 +31,7 @@ module.exports = __toCommonJS(resolve_exports);
31
31
  var import_path = require("path");
32
32
  var import_build_utils = require("@vercel/build-utils");
33
33
  var import_constants = require("./runtimes/constants");
34
+ var import_buildpack_runtimes = require("../buildpack-runtimes");
34
35
  var import_framework = require("./runtimes/framework");
35
36
  var import_runtime = require("./runtimes/runtime");
36
37
  var import_entrypoint = require("./runtimes/entrypoint");
@@ -511,6 +512,15 @@ function validateServiceConfig(name, config, options = {}) {
511
512
  };
512
513
  }
513
514
  if (hasBuilderOrRuntime && !hasFramework && !hasEntrypoint) {
515
+ const buildpackRuntime = config.builder ? void 0 : (0, import_buildpack_runtimes.toBuildpackRuntime)(config.runtime);
516
+ if (buildpackRuntime) {
517
+ const markers = import_buildpack_runtimes.BUILDPACK_PROJECT_MARKERS.get(buildpackRuntime) ?? [];
518
+ return {
519
+ code: "BUILDPACK_REQUIRES_SERVICES",
520
+ message: `Service "${name}" must specify "entrypoint" when using "runtime" with "experimentalServices". Move it to "services" to build without an "entrypoint" from a ${markers.join(" or ")} at the service root.`,
521
+ serviceName: name
522
+ };
523
+ }
514
524
  return {
515
525
  code: "MISSING_ENTRYPOINT",
516
526
  message: `Service "${name}" must specify "entrypoint" when using "${config.builder ? "builder" : "runtime"}".`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/fs-detectors",
3
- "version": "7.2.5",
3
+ "version": "7.3.0",
4
4
  "description": "Vercel filesystem detectors",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -20,11 +20,11 @@
20
20
  "minimatch": "3.1.2",
21
21
  "semver": "6.3.1",
22
22
  "smol-toml": "1.5.2",
23
- "@vercel/build-utils": "14.10.1",
24
- "@vercel/error-utils": "2.2.1",
25
23
  "@vercel/frameworks": "3.34.0",
24
+ "@vercel/error-utils": "2.2.1",
26
25
  "@vercel/python-analysis": "0.14.0",
27
- "@vercel/routing-utils": "6.6.0"
26
+ "@vercel/routing-utils": "6.6.0",
27
+ "@vercel/build-utils": "14.10.1"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/glob": "7.2.0",