@vercel/fs-detectors 6.7.7 → 6.7.8

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.
@@ -1,5 +1,5 @@
1
1
  import type { Route } from '@vercel/routing-utils';
2
- import type { PackageJson, Builder, BuilderFunctions, ExperimentalServices, ProjectSettings, Service } from '@vercel/build-utils';
2
+ import type { PackageJson, Builder, BuilderFunctions, ExperimentalServices, ProjectSettings, Service, ExperimentalServicesV2 } from '@vercel/build-utils';
3
3
  /**
4
4
  * Pattern for finding all supported middleware files.
5
5
  */
@@ -23,6 +23,7 @@ export interface Options {
23
23
  tag?: string;
24
24
  functions?: BuilderFunctions;
25
25
  experimentalServices?: ExperimentalServices;
26
+ experimentalServicesV2?: ExperimentalServicesV2;
26
27
  ignoreBuildScript?: boolean;
27
28
  projectSettings?: ProjectSettings;
28
29
  cleanUrls?: boolean;
@@ -92,10 +92,14 @@ function detectOutputDirectory(builders) {
92
92
  return publicBuilder ? publicBuilder.src.replace("/**/*", "") : null;
93
93
  }
94
94
  async function detectBuilders(files, pkg, options = {}) {
95
- const { experimentalServices, projectSettings = {} } = options;
95
+ const {
96
+ experimentalServices,
97
+ experimentalServicesV2,
98
+ projectSettings = {}
99
+ } = options;
96
100
  const { framework } = projectSettings;
97
- const configuredServices = experimentalServices;
98
- const configuredServicesType = "experimentalServices";
101
+ const configuredServices = experimentalServices ?? experimentalServicesV2;
102
+ const configuredServicesType = experimentalServices ? "experimentalServices" : "experimentalServicesV2";
99
103
  const hasServicesConfig = configuredServices != null && typeof configuredServices === "object";
100
104
  if (hasServicesConfig || framework === "services") {
101
105
  return (0, import_get_services_builders.getServicesBuilders)({
package/dist/index.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  export { detectBuilders, detectOutputDirectory, detectApiDirectory, detectApiExtensions, type Options as DetectBuildersOptions, } from './detect-builders';
2
2
  export { detectServices, generateServicesRoutes, } from './services/detect-services';
3
+ export { resolveAllConfiguredServicesV2, resolveConfiguredServiceV2, validateServiceConfigV2, } from './services/resolve-v2';
4
+ export { isExperimentalService, isExperimentalServiceV2, } from '@vercel/build-utils';
3
5
  export { autoDetectServices } from './services/auto-detect';
4
6
  export type { AutoDetectOptions, AutoDetectResult, } from './services/auto-detect';
5
7
  export { isStaticBuild, isRouteOwningBuilder, INTERNAL_SERVICE_PREFIX, getInternalServiceFunctionPath, getInternalServiceCronPath, getInternalServiceCronPathPrefix, getInternalServiceWorkerPath, getInternalServiceWorkerPathPrefix, } from './services/utils';
6
8
  export { getServicesBuilders } from './services/get-services-builders';
7
- export type { DetectServicesOptions, DetectServicesResult, DetectServicesSource, InferredServicesConfig, ResolvedServicesResult, InferredServicesResult, ResolvedService, Service, ServicesRoutes, ServiceDetectionError, } from './services/types';
9
+ export type { DetectServicesOptions, DetectServicesResult, DetectServicesSource, InferredServicesConfig, ResolvedServicesResult, InferredServicesResult, ResolvedService, Service, ExperimentalService, ExperimentalServiceV2, ExperimentalServiceV2Config, ExperimentalServicesV2, ExperimentalServiceV2Binding, ServicesRoutes, ServiceDetectionError, } from './services/types';
8
10
  export { detectFileSystemAPI } from './detect-file-system-api';
9
11
  export { detectFramework, detectFrameworks, detectFrameworkRecord, detectFrameworkVersion, } from './detect-framework';
10
12
  export { getProjectPaths } from './get-project-paths';
package/dist/index.js CHANGED
@@ -49,17 +49,24 @@ __export(src_exports, {
49
49
  getServicesBuilders: () => import_get_services_builders.getServicesBuilders,
50
50
  getWorkspacePackagePaths: () => import_get_workspace_package_paths.getWorkspacePackagePaths,
51
51
  getWorkspaces: () => import_get_workspaces.getWorkspaces,
52
+ isExperimentalService: () => import_build_utils.isExperimentalService,
53
+ isExperimentalServiceV2: () => import_build_utils.isExperimentalServiceV2,
52
54
  isOfficialRuntime: () => import_is_official_runtime.isOfficialRuntime,
53
55
  isRouteOwningBuilder: () => import_utils.isRouteOwningBuilder,
54
56
  isStaticBuild: () => import_utils.isStaticBuild,
55
57
  isStaticRuntime: () => import_is_official_runtime.isStaticRuntime,
56
58
  monorepoManagers: () => import_monorepo_managers.monorepoManagers,
57
59
  packageManagers: () => import_package_managers.packageManagers,
60
+ resolveAllConfiguredServicesV2: () => import_resolve_v2.resolveAllConfiguredServicesV2,
61
+ resolveConfiguredServiceV2: () => import_resolve_v2.resolveConfiguredServiceV2,
62
+ validateServiceConfigV2: () => import_resolve_v2.validateServiceConfigV2,
58
63
  workspaceManagers: () => import_workspace_managers.workspaceManagers
59
64
  });
60
65
  module.exports = __toCommonJS(src_exports);
61
66
  var import_detect_builders = require("./detect-builders");
62
67
  var import_detect_services = require("./services/detect-services");
68
+ var import_resolve_v2 = require("./services/resolve-v2");
69
+ var import_build_utils = require("@vercel/build-utils");
63
70
  var import_auto_detect = require("./services/auto-detect");
64
71
  var import_utils = require("./services/utils");
65
72
  var import_get_services_builders = require("./services/get-services-builders");
@@ -109,12 +116,17 @@ var import_detect_instrumentation = require("./detect-instrumentation");
109
116
  getServicesBuilders,
110
117
  getWorkspacePackagePaths,
111
118
  getWorkspaces,
119
+ isExperimentalService,
120
+ isExperimentalServiceV2,
112
121
  isOfficialRuntime,
113
122
  isRouteOwningBuilder,
114
123
  isStaticBuild,
115
124
  isStaticRuntime,
116
125
  monorepoManagers,
117
126
  packageManagers,
127
+ resolveAllConfiguredServicesV2,
128
+ resolveConfiguredServiceV2,
129
+ validateServiceConfigV2,
118
130
  workspaceManagers,
119
131
  ...require("./monorepos/get-monorepo-default-settings")
120
132
  });
@@ -33,4 +33,4 @@ export declare function detectServices(options: DetectServicesOptions): Promise<
33
33
  * Internal cron callback routes under `/_svc/{serviceName}/crons/{entry}/{handler}`
34
34
  * that rewrite to `/_svc/{serviceName}/index`.
35
35
  */
36
- export declare function generateServicesRoutes(services: Service[]): ServicesRoutes;
36
+ export declare function generateServicesRoutes(allServices: Service[]): ServicesRoutes;
@@ -26,6 +26,7 @@ var import_build_utils = require("@vercel/build-utils");
26
26
  var import_routing_utils = require("@vercel/routing-utils");
27
27
  var import_utils = require("./utils");
28
28
  var import_resolve = require("./resolve");
29
+ var import_resolve_v2 = require("./resolve-v2");
29
30
  var import_auto_detect = require("./auto-detect");
30
31
  var import_detect_railway = require("./detect-railway");
31
32
  var import_detect_render = require("./detect-render");
@@ -90,7 +91,8 @@ async function detectServices(options) {
90
91
  fs,
91
92
  workPath,
92
93
  detectEntrypoint,
93
- configuredServices: providedConfiguredServices
94
+ configuredServices: providedConfiguredServices,
95
+ configuredServicesType
94
96
  } = options;
95
97
  const scopedFs = workPath ? fs.chdir(workPath) : fs;
96
98
  const { config: vercelConfig, error: configError } = await (0, import_utils.readVercelConfig)(scopedFs);
@@ -105,6 +107,23 @@ async function detectServices(options) {
105
107
  });
106
108
  }
107
109
  const hasProvidedConfiguredServices = providedConfiguredServices && Object.keys(providedConfiguredServices).length > 0;
110
+ const experimentalServicesV2 = hasProvidedConfiguredServices && configuredServicesType === "experimentalServicesV2" ? providedConfiguredServices : hasProvidedConfiguredServices ? void 0 : vercelConfig?.experimentalServicesV2;
111
+ if (experimentalServicesV2 && Object.keys(experimentalServicesV2).length > 0) {
112
+ const result2 = await (0, import_resolve_v2.resolveAllConfiguredServicesV2)(
113
+ experimentalServicesV2,
114
+ scopedFs
115
+ );
116
+ return withResolvedResult({
117
+ services: result2.services,
118
+ source: "configured",
119
+ // V2 uses explicit `bindings`, so no implicit `{NAME}_URL` injection.
120
+ useImplicitEnvInjection: false,
121
+ // V2 routes are explicitly carried per-service to output them separately.
122
+ routes: emptyRoutes(),
123
+ errors: result2.errors,
124
+ warnings: []
125
+ });
126
+ }
108
127
  const configuredServices = hasProvidedConfiguredServices ? providedConfiguredServices : vercelConfig?.experimentalServices;
109
128
  const hasConfiguredServices = configuredServices && Object.keys(configuredServices).length > 0;
110
129
  if (!hasConfiguredServices) {
@@ -210,7 +229,8 @@ async function tryResolveInferred(detectResult, source, scopedFs) {
210
229
  inferred
211
230
  );
212
231
  }
213
- function generateServicesRoutes(services) {
232
+ function generateServicesRoutes(allServices) {
233
+ const services = allServices.filter(import_build_utils.isExperimentalService);
214
234
  const hostRewrites = [];
215
235
  const rewrites = [];
216
236
  const defaults = [];
@@ -1,6 +1,6 @@
1
1
  import type { Route } from '@vercel/routing-utils';
2
2
  import type { Builder } from '@vercel/build-utils';
3
- import type { ConfiguredServices, ResolvedService } from './types';
3
+ import type { ConfiguredServices, ConfiguredServicesType, Service } from './types';
4
4
  export interface ErrorResponse {
5
5
  code: string;
6
6
  message: string;
@@ -10,7 +10,7 @@ export interface ErrorResponse {
10
10
  export interface GetServicesBuildersOptions {
11
11
  workPath?: string;
12
12
  configuredServices?: ConfiguredServices;
13
- configuredServicesType?: 'experimentalServices';
13
+ configuredServicesType?: ConfiguredServicesType;
14
14
  projectFramework?: string | null;
15
15
  }
16
16
  export interface ServicesBuildersResult {
@@ -23,7 +23,7 @@ export interface ServicesBuildersResult {
23
23
  redirectRoutes: Route[] | null;
24
24
  rewriteRoutes: Route[] | null;
25
25
  errorRoutes: Route[] | null;
26
- services?: ResolvedService[];
26
+ services?: Service[];
27
27
  useImplicitEnvInjection?: boolean;
28
28
  }
29
29
  /**
@@ -0,0 +1,11 @@
1
+ import type { ExperimentalServiceV2, ExperimentalServiceV2Config, ExperimentalServicesV2, ServiceDetectionError } from './types';
2
+ import type { DetectorFilesystem } from '../detectors/filesystem';
3
+ export declare function validateServiceConfigV2(name: string, config: ExperimentalServiceV2Config): ServiceDetectionError | null;
4
+ export declare function resolveConfiguredServiceV2(name: string, config: ExperimentalServiceV2Config, fs: DetectorFilesystem): Promise<{
5
+ service?: ExperimentalServiceV2;
6
+ error?: ServiceDetectionError;
7
+ }>;
8
+ export declare function resolveAllConfiguredServicesV2(services: ExperimentalServicesV2, fs: DetectorFilesystem): Promise<{
9
+ services: ExperimentalServiceV2[];
10
+ errors: ServiceDetectionError[];
11
+ }>;
@@ -0,0 +1,264 @@
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 resolve_v2_exports = {};
20
+ __export(resolve_v2_exports, {
21
+ resolveAllConfiguredServicesV2: () => resolveAllConfiguredServicesV2,
22
+ resolveConfiguredServiceV2: () => resolveConfiguredServiceV2,
23
+ validateServiceConfigV2: () => validateServiceConfigV2
24
+ });
25
+ module.exports = __toCommonJS(resolve_v2_exports);
26
+ var import_path = require("path");
27
+ var import_build_utils = require("@vercel/build-utils");
28
+ var import_frameworks = require("@vercel/frameworks");
29
+ var import_types = require("./types");
30
+ var import_resolve = require("./resolve");
31
+ var import_utils = require("./utils");
32
+ const frameworksBySlug = new Map(import_frameworks.frameworkList.map((f) => [f.slug, f]));
33
+ const SERVICE_NAME_REGEX = /^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;
34
+ function validateServiceConfigV2(name, config) {
35
+ if (!SERVICE_NAME_REGEX.test(name)) {
36
+ return {
37
+ code: "INVALID_SERVICE_NAME",
38
+ 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.`,
39
+ serviceName: name
40
+ };
41
+ }
42
+ if (!config || typeof config !== "object") {
43
+ return {
44
+ code: "INVALID_SERVICE_CONFIG",
45
+ message: `Service "${name}" has an invalid configuration. Expected an object.`,
46
+ serviceName: name
47
+ };
48
+ }
49
+ if (typeof config.root !== "string" || config.root.length === 0) {
50
+ return {
51
+ code: "MISSING_ROOT",
52
+ message: `Service "${name}" must specify a "root".`,
53
+ serviceName: name
54
+ };
55
+ }
56
+ const normalizedRoot = import_path.posix.normalize(config.root);
57
+ if (normalizedRoot.startsWith("/")) {
58
+ return {
59
+ code: "INVALID_ROOT",
60
+ message: `Service "${name}" has invalid "root" "${config.root}". Must be a relative path.`,
61
+ serviceName: name
62
+ };
63
+ }
64
+ if (normalizedRoot === ".." || normalizedRoot.startsWith("../")) {
65
+ return {
66
+ code: "INVALID_ROOT",
67
+ message: `Service "${name}" has invalid "root" "${config.root}". Must not escape the project root.`,
68
+ serviceName: name
69
+ };
70
+ }
71
+ if (config.runtime && !(config.runtime in import_types.RUNTIME_BUILDERS)) {
72
+ return {
73
+ code: "INVALID_RUNTIME",
74
+ message: `Service "${name}" has invalid runtime "${config.runtime}".`,
75
+ serviceName: name
76
+ };
77
+ }
78
+ if (config.framework && !frameworksBySlug.has(config.framework)) {
79
+ return {
80
+ code: "INVALID_FRAMEWORK",
81
+ message: `Service "${name}" has invalid framework "${config.framework}".`,
82
+ serviceName: name
83
+ };
84
+ }
85
+ if (config.runtime && config.framework) {
86
+ const frameworkRuntime = (0, import_utils.inferRuntimeFromFramework)(config.framework);
87
+ if (frameworkRuntime && frameworkRuntime !== config.runtime) {
88
+ return {
89
+ code: "RUNTIME_FRAMEWORK_MISMATCH",
90
+ message: `Service "${name}" has conflicting runtime/framework: runtime "${config.runtime}" is incompatible with framework "${config.framework}" (runtime "${frameworkRuntime}").`,
91
+ serviceName: name
92
+ };
93
+ }
94
+ }
95
+ if (!config.framework && !config.entrypoint) {
96
+ return {
97
+ code: "MISSING_SERVICE_CONFIG",
98
+ message: `Service "${name}" must specify "framework" or "entrypoint".`,
99
+ serviceName: name
100
+ };
101
+ }
102
+ return null;
103
+ }
104
+ async function resolveConfiguredServiceV2(name, config, fs) {
105
+ const root = config.root;
106
+ const normalizedRoot = import_path.posix.normalize(root);
107
+ const serviceFsResult = normalizedRoot === "." ? { fs } : await (0, import_resolve.getServiceFs)(fs, name, root);
108
+ if (serviceFsResult.error) {
109
+ return { error: serviceFsResult.error };
110
+ }
111
+ const serviceFs = serviceFsResult.fs;
112
+ const rawEntrypoint = config.entrypoint;
113
+ const moduleAttr = typeof rawEntrypoint === "string" ? (0, import_resolve.parsePyModuleAttrEntrypoint)(rawEntrypoint) : null;
114
+ let normalizedEntrypoint;
115
+ let entrypointIsDirectory = false;
116
+ if (typeof rawEntrypoint === "string") {
117
+ const entrypointToResolve = moduleAttr ? moduleAttr.filePath : rawEntrypoint;
118
+ const resolved = await (0, import_resolve.resolveEntrypointPath)({
119
+ fs: serviceFs,
120
+ serviceName: name,
121
+ entrypoint: entrypointToResolve
122
+ });
123
+ if (resolved.error) {
124
+ return { error: resolved.error };
125
+ }
126
+ normalizedEntrypoint = resolved.entrypoint?.normalized;
127
+ entrypointIsDirectory = Boolean(resolved.entrypoint?.isDirectory);
128
+ }
129
+ const entrypointFile = entrypointIsDirectory || !normalizedEntrypoint ? void 0 : normalizedEntrypoint;
130
+ const inferredRuntime = (0, import_utils.inferServiceRuntime)({
131
+ runtime: config.runtime,
132
+ framework: config.framework,
133
+ entrypoint: entrypointFile
134
+ });
135
+ let framework = config.framework;
136
+ if (!framework && normalizedEntrypoint) {
137
+ const workspace = entrypointIsDirectory ? normalizedEntrypoint : import_path.posix.dirname(normalizedEntrypoint) || ".";
138
+ const detection = await (0, import_resolve.detectFrameworkFromWorkspace)({
139
+ fs: serviceFs,
140
+ workspace,
141
+ serviceName: name,
142
+ runtime: inferredRuntime
143
+ });
144
+ if (detection.error) {
145
+ return { error: detection.error };
146
+ }
147
+ framework = detection.framework;
148
+ }
149
+ if (entrypointIsDirectory && !framework) {
150
+ return {
151
+ error: {
152
+ code: "MISSING_SERVICE_FRAMEWORK",
153
+ message: `Service "${name}" uses directory entrypoint "${config.entrypoint}" but no framework could be detected. Specify "framework" explicitly or use a file entrypoint.`,
154
+ serviceName: name
155
+ }
156
+ };
157
+ }
158
+ const frameworkDefinition = framework ? frameworksBySlug.get(framework) : void 0;
159
+ let builderUse;
160
+ let builderSrc;
161
+ if (framework) {
162
+ builderUse = (0, import_build_utils.isNodeBackendFramework)(framework) ? "@vercel/backends" : frameworkDefinition?.useRuntime?.use || "@vercel/static-build";
163
+ builderSrc = entrypointFile || frameworkDefinition?.useRuntime?.src || "package.json";
164
+ } else {
165
+ if (!inferredRuntime) {
166
+ return {
167
+ error: {
168
+ code: "MISSING_SERVICE_CONFIG",
169
+ message: `Service "${name}" must specify "framework" or a runtime-resolvable "entrypoint".`,
170
+ serviceName: name
171
+ }
172
+ };
173
+ }
174
+ builderUse = inferredRuntime === "node" ? "@vercel/backends" : (0, import_utils.getBuilderForRuntime)(inferredRuntime);
175
+ builderSrc = entrypointFile;
176
+ }
177
+ const isRoot = normalizedRoot === ".";
178
+ const projectRelativeSrc = isRoot ? builderSrc : import_path.posix.join(normalizedRoot, builderSrc);
179
+ const builderConfig = { zeroConfig: true };
180
+ if (builderUse === "@vercel/backends") {
181
+ builderConfig.serviceName = name;
182
+ }
183
+ if (framework) {
184
+ builderConfig.framework = framework;
185
+ }
186
+ if (!isRoot) {
187
+ builderConfig.workspace = normalizedRoot;
188
+ }
189
+ if (moduleAttr) {
190
+ builderConfig.handlerFunction = moduleAttr.attrName;
191
+ }
192
+ const runtime = import_types.STATIC_BUILDERS.has(builderUse) ? void 0 : inferredRuntime;
193
+ return {
194
+ service: {
195
+ schema: "experimentalServicesV2",
196
+ name,
197
+ root,
198
+ framework,
199
+ runtime,
200
+ entrypoint: entrypointFile,
201
+ builder: {
202
+ src: projectRelativeSrc,
203
+ use: builderUse,
204
+ config: builderConfig
205
+ },
206
+ installCommand: config.installCommand,
207
+ buildCommand: config.buildCommand,
208
+ devCommand: config.devCommand,
209
+ ignoreCommand: config.ignoreCommand,
210
+ outputDirectory: config.outputDirectory,
211
+ bindings: config.bindings,
212
+ functions: config.functions,
213
+ headers: config.headers,
214
+ redirects: config.redirects,
215
+ rewrites: config.rewrites,
216
+ routes: config.routes,
217
+ cleanUrls: config.cleanUrls,
218
+ trailingSlash: config.trailingSlash
219
+ }
220
+ };
221
+ }
222
+ async function resolveAllConfiguredServicesV2(services, fs) {
223
+ const resolved = [];
224
+ const errors = [];
225
+ for (const name of Object.keys(services)) {
226
+ const config = services[name];
227
+ const validationError = validateServiceConfigV2(name, config);
228
+ if (validationError) {
229
+ errors.push(validationError);
230
+ continue;
231
+ }
232
+ const { service, error } = await resolveConfiguredServiceV2(
233
+ name,
234
+ config,
235
+ fs
236
+ );
237
+ if (error) {
238
+ errors.push(error);
239
+ continue;
240
+ }
241
+ if (service) {
242
+ resolved.push(service);
243
+ }
244
+ }
245
+ const serviceNames = new Set(Object.keys(services));
246
+ for (const service of resolved) {
247
+ for (const binding of service.bindings ?? []) {
248
+ if (!serviceNames.has(binding.service)) {
249
+ errors.push({
250
+ code: "UNKNOWN_SERVICE_BINDING",
251
+ message: `Service "${service.name}" declares a binding to unknown service "${binding.service}".`,
252
+ serviceName: service.name
253
+ });
254
+ }
255
+ }
256
+ }
257
+ return { services: resolved, errors };
258
+ }
259
+ // Annotate the CommonJS export names for ESM import in node:
260
+ 0 && (module.exports = {
261
+ resolveAllConfiguredServicesV2,
262
+ resolveConfiguredServiceV2,
263
+ validateServiceConfigV2
264
+ });
@@ -1,10 +1,26 @@
1
- import type { Service, ConfiguredServices, ExperimentalServiceConfig, ServiceDetectionError } from './types';
1
+ import type { ExperimentalService, ConfiguredServices, ExperimentalServiceConfig, ServiceDetectionError, ServiceRuntime } from './types';
2
2
  import type { DetectorFilesystem } from '../detectors/filesystem';
3
+ export declare function parsePyModuleAttrEntrypoint(entrypoint: string): {
4
+ attrName: string;
5
+ filePath: string;
6
+ } | null;
3
7
  type ConfiguredServiceConfig = ExperimentalServiceConfig;
4
8
  interface ResolvedEntrypointPath {
5
9
  normalized: string;
6
10
  isDirectory: boolean;
7
11
  }
12
+ export declare function getServiceFs(fs: DetectorFilesystem, serviceName: string, root?: string): Promise<{
13
+ fs: DetectorFilesystem;
14
+ error?: ServiceDetectionError;
15
+ }>;
16
+ export declare function resolveEntrypointPath({ fs, serviceName, entrypoint, }: {
17
+ fs: DetectorFilesystem;
18
+ serviceName: string;
19
+ entrypoint: string;
20
+ }): Promise<{
21
+ entrypoint?: ResolvedEntrypointPath;
22
+ error?: ServiceDetectionError;
23
+ }>;
8
24
  type RoutePrefixSource = 'configured' | 'generated';
9
25
  interface ResolveConfiguredServiceOptions {
10
26
  name: string;
@@ -19,6 +35,20 @@ interface ResolveConfiguredServiceOptions {
19
35
  interface ResolveAllConfiguredServicesOptions {
20
36
  requireFileEntrypointForBackendRuntimes?: boolean;
21
37
  }
38
+ export declare function inferWorkspaceFromNearestManifest({ fs, entrypoint, runtime, }: {
39
+ fs: DetectorFilesystem;
40
+ entrypoint?: string;
41
+ runtime?: ServiceRuntime;
42
+ }): Promise<string | undefined>;
43
+ export declare function detectFrameworkFromWorkspace({ fs, workspace, serviceName, runtime, }: {
44
+ fs: DetectorFilesystem;
45
+ workspace: string;
46
+ serviceName: string;
47
+ runtime?: ServiceRuntime;
48
+ }): Promise<{
49
+ framework?: string;
50
+ error?: ServiceDetectionError;
51
+ }>;
22
52
  /**
23
53
  * Validate a service configuration from vercel.json services.
24
54
  */
@@ -27,13 +57,13 @@ export declare function validateServiceEntrypoint(name: string, config: Configur
27
57
  /**
28
58
  * Resolve a single service from user configuration.
29
59
  */
30
- export declare function resolveConfiguredService(options: ResolveConfiguredServiceOptions): Promise<Service>;
60
+ export declare function resolveConfiguredService(options: ResolveConfiguredServiceOptions): Promise<ExperimentalService>;
31
61
  /**
32
62
  * Resolve all services from vercel.json services.
33
63
  * Validates each service configuration.
34
64
  */
35
65
  export declare function resolveAllConfiguredServices(services: ConfiguredServices, fs: DetectorFilesystem, routePrefixSource?: RoutePrefixSource, options?: ResolveAllConfiguredServicesOptions): Promise<{
36
- services: Service[];
66
+ services: ExperimentalService[];
37
67
  errors: ServiceDetectionError[];
38
68
  }>;
39
69
  export {};
@@ -18,8 +18,13 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var resolve_exports = {};
20
20
  __export(resolve_exports, {
21
+ detectFrameworkFromWorkspace: () => detectFrameworkFromWorkspace,
22
+ getServiceFs: () => getServiceFs,
23
+ inferWorkspaceFromNearestManifest: () => inferWorkspaceFromNearestManifest,
24
+ parsePyModuleAttrEntrypoint: () => parsePyModuleAttrEntrypoint,
21
25
  resolveAllConfiguredServices: () => resolveAllConfiguredServices,
22
26
  resolveConfiguredService: () => resolveConfiguredService,
27
+ resolveEntrypointPath: () => resolveEntrypointPath,
23
28
  validateServiceConfig: () => validateServiceConfig,
24
29
  validateServiceEntrypoint: () => validateServiceEntrypoint
25
30
  });
@@ -666,6 +671,7 @@ async function resolveConfiguredService(options) {
666
671
  builderConfig.handlerFunction = moduleAttrParsed.attrName;
667
672
  }
668
673
  return {
674
+ schema: "experimentalServices",
669
675
  name,
670
676
  type,
671
677
  trigger,
@@ -870,8 +876,13 @@ function validateEnvRefs(env, serviceName, servicesByName, errors) {
870
876
  }
871
877
  // Annotate the CommonJS export names for ESM import in node:
872
878
  0 && (module.exports = {
879
+ detectFrameworkFromWorkspace,
880
+ getServiceFs,
881
+ inferWorkspaceFromNearestManifest,
882
+ parsePyModuleAttrEntrypoint,
873
883
  resolveAllConfiguredServices,
874
884
  resolveConfiguredService,
885
+ resolveEntrypointPath,
875
886
  validateServiceConfig,
876
887
  validateServiceEntrypoint
877
888
  });
@@ -1,7 +1,7 @@
1
1
  import type { Route } from '@vercel/routing-utils';
2
- import type { DetectEntrypointFn, EnvVar, EnvVars, ExperimentalServiceConfig, ExperimentalServiceGroups, ExperimentalServices, ServiceRuntime, ServiceType, ServiceRefEnvVar, Service, Builder } from '@vercel/build-utils';
2
+ import type { DetectEntrypointFn, EnvVar, EnvVars, ExperimentalServiceConfig, ExperimentalServiceGroups, ExperimentalServices, ExperimentalServiceV2Config, ExperimentalServicesV2, ExperimentalServiceV2Binding, ExperimentalService, ExperimentalServiceV2, ServiceRuntime, ServiceType, ServiceRefEnvVar, Service, Builder } from '@vercel/build-utils';
3
3
  import type { DetectorFilesystem } from '../detectors/filesystem';
4
- export type { DetectEntrypointFn, EnvVar, EnvVars, ExperimentalServiceConfig, ExperimentalServiceGroups, ExperimentalServices, ServiceRuntime, ServiceType, ServiceRefEnvVar, Service, Builder, };
4
+ export type { DetectEntrypointFn, EnvVar, EnvVars, ExperimentalServiceConfig, ExperimentalServiceGroups, ExperimentalServices, ExperimentalServiceV2Config, ExperimentalServicesV2, ExperimentalServiceV2Binding, ExperimentalService, ExperimentalServiceV2, ServiceRuntime, ServiceType, ServiceRefEnvVar, Service, Builder, };
5
5
  /**
6
6
  * @deprecated Use `Service` instead
7
7
  */
@@ -9,7 +9,7 @@ export type ResolvedService = Service;
9
9
  export interface DetectServicesOptions {
10
10
  fs: DetectorFilesystem;
11
11
  configuredServices?: ConfiguredServices;
12
- configuredServicesType?: 'experimentalServices';
12
+ configuredServicesType?: ConfiguredServicesType;
13
13
  /**
14
14
  * Working directory path (relative to fs root).
15
15
  * If provided, vercel.json is read from this path.
@@ -42,7 +42,8 @@ export interface ServicesRoutes {
42
42
  */
43
43
  workers: Route[];
44
44
  }
45
- export type ConfiguredServices = ExperimentalServices;
45
+ export type ConfiguredServicesType = 'experimentalServices' | 'experimentalServicesV2';
46
+ export type ConfiguredServices = ExperimentalServices | ExperimentalServicesV2;
46
47
  export type InferredServicesConfig = ExperimentalServices;
47
48
  export interface ResolvedServicesResult {
48
49
  services: Service[];
@@ -55,7 +56,7 @@ export interface ResolvedServicesResult {
55
56
  export interface InferredServicesResult {
56
57
  source: 'layout' | 'procfile' | 'railway' | 'render';
57
58
  config: InferredServicesConfig;
58
- services: Service[];
59
+ services: ExperimentalService[];
59
60
  warnings: ServiceDetectionWarning[];
60
61
  }
61
62
  export interface DetectServicesResult extends ResolvedServicesResult {
@@ -1,7 +1,7 @@
1
1
  import { INTERNAL_SERVICE_PREFIX, getInternalServiceFunctionPath, getInternalServiceCronPathPrefix, getInternalServiceCronPath } from '@vercel/build-utils';
2
2
  import type { Framework } from '@vercel/frameworks';
3
3
  import type { DetectorFilesystem } from '../detectors/filesystem';
4
- import type { ServiceRuntime, ExperimentalServices, ServiceDetectionError, ServiceDetectionWarning, ResolvedService } from './types';
4
+ import type { ServiceRuntime, ExperimentalServices, ExperimentalServicesV2, ServiceDetectionError, ServiceDetectionWarning, ResolvedService } from './types';
5
5
  export declare const DETECTION_FRAMEWORKS: Framework[];
6
6
  export { INTERNAL_SERVICE_PREFIX, getInternalServiceFunctionPath, getInternalServiceCronPathPrefix, getInternalServiceCronPath, };
7
7
  export declare function hasFile(fs: DetectorFilesystem, filePath: string): Promise<boolean>;
@@ -56,6 +56,7 @@ export declare function inferServiceRuntime(config: {
56
56
  export interface ReadVercelConfigResult {
57
57
  config: {
58
58
  experimentalServices?: ExperimentalServices;
59
+ experimentalServicesV2?: ExperimentalServicesV2;
59
60
  } | null;
60
61
  error: ServiceDetectionError | null;
61
62
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/fs-detectors",
3
- "version": "6.7.7",
3
+ "version": "6.7.8",
4
4
  "description": "Vercel filesystem detectors",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -20,10 +20,10 @@
20
20
  "minimatch": "3.1.2",
21
21
  "semver": "6.3.1",
22
22
  "smol-toml": "1.5.2",
23
- "@vercel/build-utils": "13.27.0",
24
- "@vercel/routing-utils": "6.2.0",
25
23
  "@vercel/frameworks": "3.27.0",
26
- "@vercel/error-utils": "2.2.0"
24
+ "@vercel/build-utils": "13.27.1",
25
+ "@vercel/error-utils": "2.2.0",
26
+ "@vercel/routing-utils": "6.2.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/glob": "7.2.0",