@vercel/fs-detectors 5.11.1 → 5.11.3

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.
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { autoDetectServices } from './services/auto-detect';
4
4
  export type { AutoDetectOptions, AutoDetectResult, } from './services/auto-detect';
5
5
  export { isStaticBuild, isRouteOwningBuilder, INTERNAL_SERVICE_PREFIX, getInternalServiceFunctionPath, getInternalServiceCronPath, getInternalServiceCronPathPrefix, getInternalServiceWorkerPath, getInternalServiceWorkerPathPrefix, } from './services/utils';
6
6
  export { getServicesBuilders } from './services/get-services-builders';
7
- export type { DetectServicesOptions, DetectServicesResult, DetectServicesSource, ResolvedService, Service, ServicesRoutes, ServiceDetectionError, } from './services/types';
7
+ export type { DetectServicesOptions, DetectServicesResult, DetectServicesSource, ServicesConfig, ResolvedServicesResult, InferredServicesResult, ResolvedService, Service, ServicesRoutes, ServiceDetectionError, } from './services/types';
8
8
  export { detectFileSystemAPI } from './detect-file-system-api';
9
9
  export { detectFramework, detectFrameworks, detectFrameworkRecord, detectFrameworkVersion, } from './detect-framework';
10
10
  export { getProjectPaths } from './get-project-paths';
@@ -100,13 +100,22 @@ async function detectServicesAtRoot(fs, rootFramework) {
100
100
  };
101
101
  const backendResult = await detectBackendServices(fs);
102
102
  if (backendResult.error) {
103
- return { services: null, errors: [backendResult.error] };
103
+ return {
104
+ services: null,
105
+ errors: [backendResult.error]
106
+ };
104
107
  }
105
108
  if (Object.keys(backendResult.services).length === 0) {
106
- return { services: null, errors: [] };
109
+ return {
110
+ services: null,
111
+ errors: []
112
+ };
107
113
  }
108
114
  Object.assign(services, backendResult.services);
109
- return { services, errors: [] };
115
+ return {
116
+ services,
117
+ errors: []
118
+ };
110
119
  }
111
120
  async function detectServicesFrontendSubdir(fs, frontendFramework, frontendLocation) {
112
121
  const services = {};
@@ -118,7 +127,10 @@ async function detectServicesFrontendSubdir(fs, frontendFramework, frontendLocat
118
127
  };
119
128
  const backendResult = await detectBackendServices(fs);
120
129
  if (backendResult.error) {
121
- return { services: null, errors: [backendResult.error] };
130
+ return {
131
+ services: null,
132
+ errors: [backendResult.error]
133
+ };
122
134
  }
123
135
  if (Object.keys(backendResult.services).length === 0) {
124
136
  return {
@@ -132,7 +144,10 @@ async function detectServicesFrontendSubdir(fs, frontendFramework, frontendLocat
132
144
  };
133
145
  }
134
146
  Object.assign(services, backendResult.services);
135
- return { services, errors: [] };
147
+ return {
148
+ services,
149
+ errors: []
150
+ };
136
151
  }
137
152
  async function detectBackendServices(fs) {
138
153
  const services = {};
@@ -30,43 +30,68 @@ const PREVIEW_DOMAIN_MISSING = [
30
30
  { type: "host", value: { suf: ".vercel.app" } },
31
31
  { type: "host", value: { suf: ".vercel.dev" } }
32
32
  ];
33
+ function emptyRoutes() {
34
+ return {
35
+ hostRewrites: [],
36
+ rewrites: [],
37
+ defaults: [],
38
+ crons: [],
39
+ workers: []
40
+ };
41
+ }
42
+ function withResolvedResult(resolved, inferred = null) {
43
+ return {
44
+ services: resolved.services,
45
+ source: resolved.source,
46
+ routes: resolved.routes,
47
+ errors: resolved.errors,
48
+ warnings: resolved.warnings,
49
+ resolved,
50
+ inferred
51
+ };
52
+ }
53
+ function toInferredLayoutConfig(services) {
54
+ const inferredConfig = {};
55
+ for (const [name, service] of Object.entries(services)) {
56
+ const serviceConfig = {};
57
+ if (typeof service.entrypoint === "string") {
58
+ serviceConfig.entrypoint = service.entrypoint;
59
+ }
60
+ if (typeof service.routePrefix === "string") {
61
+ serviceConfig.routePrefix = service.routePrefix;
62
+ }
63
+ if ((0, import_utils.isFrontendFramework)(service.framework)) {
64
+ serviceConfig.framework = service.framework;
65
+ }
66
+ inferredConfig[name] = serviceConfig;
67
+ }
68
+ return inferredConfig;
69
+ }
33
70
  async function detectServices(options) {
34
71
  const { fs, workPath } = options;
35
72
  const scopedFs = workPath ? fs.chdir(workPath) : fs;
36
73
  const { config: vercelConfig, error: configError } = await (0, import_utils.readVercelConfig)(scopedFs);
37
74
  if (configError) {
38
- return {
75
+ return withResolvedResult({
39
76
  services: [],
40
77
  source: "configured",
41
- routes: {
42
- hostRewrites: [],
43
- rewrites: [],
44
- defaults: [],
45
- crons: [],
46
- workers: []
47
- },
78
+ routes: emptyRoutes(),
48
79
  errors: [configError],
49
80
  warnings: []
50
- };
81
+ });
51
82
  }
52
83
  const configuredServices = vercelConfig?.experimentalServices;
53
84
  const hasConfiguredServices = configuredServices && Object.keys(configuredServices).length > 0;
54
85
  if (!hasConfiguredServices) {
55
86
  const autoResult = await (0, import_auto_detect.autoDetectServices)({ fs: scopedFs });
56
87
  if (autoResult.errors.length > 0) {
57
- return {
88
+ return withResolvedResult({
58
89
  services: [],
59
90
  source: "auto-detected",
60
- routes: {
61
- hostRewrites: [],
62
- rewrites: [],
63
- defaults: [],
64
- crons: [],
65
- workers: []
66
- },
91
+ routes: emptyRoutes(),
67
92
  errors: autoResult.errors,
68
93
  warnings: []
69
- };
94
+ });
70
95
  }
71
96
  if (autoResult.services) {
72
97
  const result2 = await (0, import_resolve.resolveAllConfiguredServices)(
@@ -75,24 +100,28 @@ async function detectServices(options) {
75
100
  "generated"
76
101
  );
77
102
  const routes2 = generateServicesRoutes(result2.services);
78
- return {
103
+ const resolved = {
79
104
  services: result2.services,
80
105
  source: "auto-detected",
81
106
  routes: routes2,
82
107
  errors: result2.errors,
83
108
  warnings: []
84
109
  };
110
+ const rootWebFrameworkServices = result2.services.filter(
111
+ (service) => service.type === "web" && service.routePrefix === "/" && typeof service.framework === "string"
112
+ );
113
+ const inferred = result2.errors.length === 0 && rootWebFrameworkServices.length === 1 && result2.services.length > 1 ? {
114
+ source: "layout",
115
+ config: toInferredLayoutConfig(autoResult.services),
116
+ services: result2.services,
117
+ warnings: []
118
+ } : null;
119
+ return withResolvedResult(resolved, inferred);
85
120
  }
86
- return {
121
+ return withResolvedResult({
87
122
  services: [],
88
123
  source: "auto-detected",
89
- routes: {
90
- hostRewrites: [],
91
- rewrites: [],
92
- defaults: [],
93
- crons: [],
94
- workers: []
95
- },
124
+ routes: emptyRoutes(),
96
125
  errors: [
97
126
  {
98
127
  code: "NO_SERVICES_CONFIGURED",
@@ -100,7 +129,7 @@ async function detectServices(options) {
100
129
  }
101
130
  ],
102
131
  warnings: []
103
- };
132
+ });
104
133
  }
105
134
  const result = await (0, import_resolve.resolveAllConfiguredServices)(
106
135
  configuredServices,
@@ -108,13 +137,13 @@ async function detectServices(options) {
108
137
  "configured"
109
138
  );
110
139
  const routes = generateServicesRoutes(result.services);
111
- return {
140
+ return withResolvedResult({
112
141
  services: result.services,
113
142
  source: "configured",
114
143
  routes,
115
144
  errors: result.errors,
116
145
  warnings: []
117
- };
146
+ });
118
147
  }
119
148
  function generateServicesRoutes(services) {
120
149
  const hostRewrites = [];
@@ -188,7 +217,6 @@ function generateServicesRoutes(services) {
188
217
  check: true
189
218
  });
190
219
  }
191
- } else {
192
220
  }
193
221
  }
194
222
  const workerServices = services.filter((s) => s.type === "worker");
@@ -32,18 +32,28 @@ export interface ServicesRoutes {
32
32
  */
33
33
  workers: Route[];
34
34
  }
35
- export interface DetectServicesResult {
35
+ export type ServicesConfig = ExperimentalServices;
36
+ export interface ResolvedServicesResult {
36
37
  services: Service[];
38
+ source: DetectServicesSource;
39
+ routes: ServicesRoutes;
40
+ errors: ServiceDetectionError[];
41
+ warnings: ServiceDetectionWarning[];
42
+ }
43
+ export interface InferredServicesResult {
44
+ source: 'layout' | 'procfile';
45
+ config: ServicesConfig;
46
+ services: Service[];
47
+ warnings: ServiceDetectionWarning[];
48
+ }
49
+ export interface DetectServicesResult extends ResolvedServicesResult {
37
50
  /**
38
51
  * Source of service definitions:
39
52
  * - `configured`: loaded from explicit project configuration (currently `vercel.json#experimentalServices`)
40
53
  * - `auto-detected`: inferred from project structure
41
54
  */
42
- source: DetectServicesSource;
43
- /** Routing rules derived from services */
44
- routes: ServicesRoutes;
45
- errors: ServiceDetectionError[];
46
- warnings: ServiceDetectionWarning[];
55
+ resolved: ResolvedServicesResult;
56
+ inferred: InferredServicesResult | null;
47
57
  }
48
58
  export type DetectServicesSource = 'configured' | 'auto-detected';
49
59
  export interface ServiceDetectionWarning {
@@ -34,6 +34,7 @@ export declare function isRouteOwningBuilder(service: ResolvedService): boolean;
34
34
  * - `express` -> `node`
35
35
  */
36
36
  export declare function inferRuntimeFromFramework(framework: string | null | undefined): ServiceRuntime | undefined;
37
+ export declare function isFrontendFramework(framework: string | null | undefined): boolean;
37
38
  export declare function filterFrameworksByRuntime<T extends {
38
39
  slug?: string | null;
39
40
  }>(frameworks: readonly T[], runtime?: ServiceRuntime): T[];
@@ -30,6 +30,7 @@ __export(utils_exports, {
30
30
  hasFile: () => hasFile,
31
31
  inferRuntimeFromFramework: () => inferRuntimeFromFramework,
32
32
  inferServiceRuntime: () => inferServiceRuntime,
33
+ isFrontendFramework: () => isFrontendFramework,
33
34
  isRouteOwningBuilder: () => isRouteOwningBuilder,
34
35
  isStaticBuild: () => isStaticBuild,
35
36
  readVercelConfig: () => readVercelConfig
@@ -95,6 +96,12 @@ function inferRuntimeFromFramework(framework) {
95
96
  }
96
97
  return void 0;
97
98
  }
99
+ function isFrontendFramework(framework) {
100
+ if (!framework) {
101
+ return false;
102
+ }
103
+ return !inferRuntimeFromFramework(framework);
104
+ }
98
105
  function filterFrameworksByRuntime(frameworks, runtime) {
99
106
  if (!runtime) {
100
107
  return [...frameworks];
@@ -160,6 +167,7 @@ async function readVercelConfig(fs) {
160
167
  hasFile,
161
168
  inferRuntimeFromFramework,
162
169
  inferServiceRuntime,
170
+ isFrontendFramework,
163
171
  isRouteOwningBuilder,
164
172
  isStaticBuild,
165
173
  readVercelConfig
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/fs-detectors",
3
- "version": "5.11.1",
3
+ "version": "5.11.3",
4
4
  "description": "Vercel filesystem detectors",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -20,8 +20,9 @@
20
20
  "minimatch": "3.1.2",
21
21
  "semver": "6.3.1",
22
22
  "@vercel/error-utils": "2.0.3",
23
- "@vercel/frameworks": "3.21.1",
24
- "@vercel/routing-utils": "6.0.2"
23
+ "@vercel/routing-utils": "6.0.2",
24
+ "@vercel/build-utils": "13.8.2",
25
+ "@vercel/frameworks": "3.21.1"
25
26
  },
26
27
  "devDependencies": {
27
28
  "@types/glob": "7.2.0",
@@ -31,8 +32,7 @@
31
32
  "@types/node": "20.11.0",
32
33
  "@types/semver": "7.3.10",
33
34
  "jest-junit": "16.0.0",
34
- "typescript": "4.9.5",
35
- "@vercel/build-utils": "13.8.1"
35
+ "typescript": "4.9.5"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "node ../../utils/build.mjs",