@vercel/fs-detectors 6.13.2 → 6.14.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.
- package/dist/detect-builders.d.ts +12 -4
- package/dist/detect-builders.js +150 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -0
- package/dist/services/utils.js +1 -1
- package/package.json +4 -4
|
@@ -4,10 +4,6 @@ import type { PackageJson, Builder, BuilderFunctions, ExperimentalServices, Expe
|
|
|
4
4
|
* Pattern for finding all supported middleware files.
|
|
5
5
|
*/
|
|
6
6
|
export declare const REGEX_MIDDLEWARE_FILES = "middleware.[jt]s";
|
|
7
|
-
/**
|
|
8
|
-
* Pattern for files that the Vercel platform cares about separately from frameworks.
|
|
9
|
-
* These files are excluded from static file serving.
|
|
10
|
-
*/
|
|
11
7
|
export declare const REGEX_VERCEL_PLATFORM_FILES: string;
|
|
12
8
|
/**
|
|
13
9
|
* Pattern for non-Vercel platform files.
|
|
@@ -19,6 +15,10 @@ export interface ErrorResponse {
|
|
|
19
15
|
action?: string;
|
|
20
16
|
link?: string;
|
|
21
17
|
}
|
|
18
|
+
export interface ProxyConfig {
|
|
19
|
+
entrypoint: string;
|
|
20
|
+
matcher?: string | string[];
|
|
21
|
+
}
|
|
22
22
|
export interface Options {
|
|
23
23
|
tag?: string;
|
|
24
24
|
functions?: BuilderFunctions;
|
|
@@ -32,6 +32,7 @@ export interface Options {
|
|
|
32
32
|
featHandleMiss?: boolean;
|
|
33
33
|
bunVersion?: string;
|
|
34
34
|
workPath?: string;
|
|
35
|
+
proxy?: ProxyConfig;
|
|
35
36
|
}
|
|
36
37
|
export declare function sortFiles(fileA: string, fileB: string): number;
|
|
37
38
|
export declare function detectApiExtensions(builders: Builder[]): Set<string>;
|
|
@@ -51,3 +52,10 @@ export declare function detectBuilders(files: string[], pkg?: PackageJson | unde
|
|
|
51
52
|
experimentalServicesV2?: Services;
|
|
52
53
|
useImplicitEnvInjection?: boolean;
|
|
53
54
|
}>;
|
|
55
|
+
export declare function getProxyBuilder(proxy: ProxyConfig, tag?: string, functions?: BuilderFunctions): Builder;
|
|
56
|
+
/**
|
|
57
|
+
* Validates a `proxy` config value in isolation, without knowledge of the
|
|
58
|
+
* project's files or framework. Also used by the CLI to validate
|
|
59
|
+
* `vercel.json` before builders are detected.
|
|
60
|
+
*/
|
|
61
|
+
export declare function validateProxyConfig(proxy: ProxyConfig): ErrorResponse | null;
|
package/dist/detect-builders.js
CHANGED
|
@@ -35,7 +35,9 @@ __export(detect_builders_exports, {
|
|
|
35
35
|
detectApiExtensions: () => detectApiExtensions,
|
|
36
36
|
detectBuilders: () => detectBuilders,
|
|
37
37
|
detectOutputDirectory: () => detectOutputDirectory,
|
|
38
|
-
|
|
38
|
+
getProxyBuilder: () => getProxyBuilder,
|
|
39
|
+
sortFiles: () => sortFiles,
|
|
40
|
+
validateProxyConfig: () => validateProxyConfig
|
|
39
41
|
});
|
|
40
42
|
module.exports = __toCommonJS(detect_builders_exports);
|
|
41
43
|
var import_minimatch = __toESM(require("minimatch"));
|
|
@@ -46,7 +48,7 @@ var import_is_official_runtime = require("./is-official-runtime");
|
|
|
46
48
|
var import_build_utils = require("@vercel/build-utils");
|
|
47
49
|
var import_get_services_builders = require("./services/get-services-builders");
|
|
48
50
|
const REGEX_MIDDLEWARE_FILES = "middleware.[jt]s";
|
|
49
|
-
const
|
|
51
|
+
const VERCEL_PLATFORM_FILES = [
|
|
50
52
|
"api/**",
|
|
51
53
|
"node_modules/**",
|
|
52
54
|
REGEX_MIDDLEWARE_FILES,
|
|
@@ -58,8 +60,18 @@ const REGEX_VERCEL_PLATFORM_FILES = [
|
|
|
58
60
|
"bun.lockb",
|
|
59
61
|
".gitignore",
|
|
60
62
|
"README.md"
|
|
61
|
-
]
|
|
62
|
-
const
|
|
63
|
+
];
|
|
64
|
+
const REGEX_VERCEL_PLATFORM_FILES = VERCEL_PLATFORM_FILES.join(",");
|
|
65
|
+
function escapeMinimatchPath(path) {
|
|
66
|
+
return path.replace(/([\\,*?[\]{}()!+@])/g, "\\$1");
|
|
67
|
+
}
|
|
68
|
+
function getStaticFilesPattern(additionalExclusions = []) {
|
|
69
|
+
return `!{${[
|
|
70
|
+
...VERCEL_PLATFORM_FILES,
|
|
71
|
+
...additionalExclusions.map(escapeMinimatchPath)
|
|
72
|
+
].join(",")}}`;
|
|
73
|
+
}
|
|
74
|
+
const REGEX_NON_VERCEL_PLATFORM_FILES = getStaticFilesPattern();
|
|
63
75
|
const slugToFramework = new Map(
|
|
64
76
|
import_frameworks.frameworkList.map((f) => [f.slug, f])
|
|
65
77
|
);
|
|
@@ -115,6 +127,18 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
115
127
|
};
|
|
116
128
|
}
|
|
117
129
|
const { framework } = projectSettings;
|
|
130
|
+
const proxyError = validateProxy(options, files, framework);
|
|
131
|
+
if (proxyError) {
|
|
132
|
+
return {
|
|
133
|
+
builders: null,
|
|
134
|
+
errors: [proxyError],
|
|
135
|
+
warnings: [],
|
|
136
|
+
defaultRoutes: null,
|
|
137
|
+
redirectRoutes: null,
|
|
138
|
+
rewriteRoutes: null,
|
|
139
|
+
errorRoutes: null
|
|
140
|
+
};
|
|
141
|
+
}
|
|
118
142
|
const servicesConfig = services ?? experimentalServicesV2;
|
|
119
143
|
const configuredServices = servicesConfig ?? experimentalServicesV1;
|
|
120
144
|
const configuredServicesType = servicesConfig ? services ? "services" : "experimentalServicesV2" : "experimentalServices";
|
|
@@ -131,6 +155,12 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
131
155
|
...(0, import_get_services_builders.warnIgnoredDirectories)(files, configuredServices)
|
|
132
156
|
);
|
|
133
157
|
}
|
|
158
|
+
if (!result.errors && options.proxy) {
|
|
159
|
+
result.builders = [
|
|
160
|
+
getProxyBuilder(options.proxy, options.tag, options.functions),
|
|
161
|
+
...result.builders ?? []
|
|
162
|
+
];
|
|
163
|
+
}
|
|
134
164
|
return result;
|
|
135
165
|
}
|
|
136
166
|
const errors = [];
|
|
@@ -181,6 +211,9 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
181
211
|
const apiRoutes = [];
|
|
182
212
|
const dynamicRoutes = [];
|
|
183
213
|
for (const fileName of sortedFiles) {
|
|
214
|
+
if (fileName === options.proxy?.entrypoint) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
184
217
|
const apiBuilder = await maybeGetApiBuilder(fileName, apiMatches, options);
|
|
185
218
|
if (apiBuilder) {
|
|
186
219
|
const { routeError, apiRoute, isDynamic } = getApiRoute(
|
|
@@ -223,6 +256,15 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
223
256
|
fallbackEntrypoint = fileName;
|
|
224
257
|
}
|
|
225
258
|
}
|
|
259
|
+
if (options.proxy) {
|
|
260
|
+
const proxyBuilder = getProxyBuilder(
|
|
261
|
+
options.proxy,
|
|
262
|
+
options.tag,
|
|
263
|
+
options.functions
|
|
264
|
+
);
|
|
265
|
+
addToUsedFunctions(proxyBuilder);
|
|
266
|
+
apiBuilders.unshift(proxyBuilder);
|
|
267
|
+
}
|
|
226
268
|
if (!makeFrontendStatic && (hasBuildScript(pkg) || buildCommand || framework)) {
|
|
227
269
|
frontendBuilder = detectFrontBuilder(
|
|
228
270
|
pkg,
|
|
@@ -256,13 +298,31 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
256
298
|
} else if (apiBuilders.length && hasNoneApiFiles) {
|
|
257
299
|
frontendBuilder = {
|
|
258
300
|
use: "@vercel/static",
|
|
259
|
-
src:
|
|
301
|
+
src: getStaticFilesPattern(
|
|
302
|
+
options.proxy ? [options.proxy.entrypoint] : []
|
|
303
|
+
),
|
|
260
304
|
config: {
|
|
261
305
|
zeroConfig: true
|
|
262
306
|
}
|
|
263
307
|
};
|
|
264
308
|
}
|
|
265
309
|
}
|
|
310
|
+
if (options.proxy && frontendBuilder && (0, import_is_official_runtime.isOfficialRuntime)("next", frontendBuilder.use)) {
|
|
311
|
+
return {
|
|
312
|
+
builders: null,
|
|
313
|
+
errors: [
|
|
314
|
+
{
|
|
315
|
+
code: "proxy_framework_conflict",
|
|
316
|
+
message: "The `proxy` property cannot be used with Next.js because the framework builds its own routing middleware."
|
|
317
|
+
}
|
|
318
|
+
],
|
|
319
|
+
warnings,
|
|
320
|
+
defaultRoutes: null,
|
|
321
|
+
redirectRoutes: null,
|
|
322
|
+
rewriteRoutes: null,
|
|
323
|
+
errorRoutes: null
|
|
324
|
+
};
|
|
325
|
+
}
|
|
266
326
|
const unusedFunctionError = checkUnusedFunctions(
|
|
267
327
|
frontendBuilder,
|
|
268
328
|
usedFunctions,
|
|
@@ -329,7 +389,7 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
329
389
|
};
|
|
330
390
|
}
|
|
331
391
|
async function maybeGetApiBuilder(fileName, apiMatches, options) {
|
|
332
|
-
const middleware = fileName === "middleware.js" || fileName === "middleware.ts";
|
|
392
|
+
const middleware = !options.proxy && (fileName === "middleware.js" || fileName === "middleware.ts");
|
|
333
393
|
if (middleware && options.projectSettings?.framework === "nextjs") {
|
|
334
394
|
return null;
|
|
335
395
|
}
|
|
@@ -402,6 +462,30 @@ function getFunction(fileName, { functions = {} }) {
|
|
|
402
462
|
const func = keys.find((key) => key === fileName || (0, import_minimatch.default)(fileName, key));
|
|
403
463
|
return func ? { fnPattern: func, func: functions[func] } : { fnPattern: null, func: null };
|
|
404
464
|
}
|
|
465
|
+
function getProxyBuilder(proxy, tag, functions = {}) {
|
|
466
|
+
const { fnPattern, func } = getFunction(proxy.entrypoint, { functions });
|
|
467
|
+
const runtime = func?.runtime;
|
|
468
|
+
const config = {
|
|
469
|
+
zeroConfig: true,
|
|
470
|
+
middleware: true,
|
|
471
|
+
...!runtime ? { middlewareRuntime: "nodejs" } : {},
|
|
472
|
+
...proxy.matcher ? { middlewareMatcher: proxy.matcher } : {}
|
|
473
|
+
};
|
|
474
|
+
if (fnPattern && func) {
|
|
475
|
+
config.functions = { [fnPattern]: func };
|
|
476
|
+
if (func.includeFiles) {
|
|
477
|
+
config.includeFiles = func.includeFiles;
|
|
478
|
+
}
|
|
479
|
+
if (func.excludeFiles) {
|
|
480
|
+
config.excludeFiles = func.excludeFiles;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return {
|
|
484
|
+
src: proxy.entrypoint,
|
|
485
|
+
use: runtime || `@vercel/node${tag ? `@${tag}` : ""}`,
|
|
486
|
+
config
|
|
487
|
+
};
|
|
488
|
+
}
|
|
405
489
|
function getApiMatches() {
|
|
406
490
|
const config = { zeroConfig: true };
|
|
407
491
|
return [
|
|
@@ -417,6 +501,63 @@ function getApiMatches() {
|
|
|
417
501
|
{ src: "api/**/*.rs", use: `@vercel/rust`, config }
|
|
418
502
|
];
|
|
419
503
|
}
|
|
504
|
+
function validateProxyConfig(proxy) {
|
|
505
|
+
if (typeof proxy !== "object" || typeof proxy.entrypoint !== "string" || !proxy.entrypoint) {
|
|
506
|
+
return {
|
|
507
|
+
code: "invalid_proxy",
|
|
508
|
+
message: "The `proxy` property must contain an `entrypoint` string that references a `.js` or `.ts` file."
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
const entrypoint = proxy.entrypoint;
|
|
512
|
+
const segments = entrypoint.split("/");
|
|
513
|
+
if (entrypoint.startsWith("/") || entrypoint.includes("\\") || segments.includes(".") || segments.includes("..") || /[?#\u0000-\u001f]/.test(entrypoint)) {
|
|
514
|
+
return {
|
|
515
|
+
code: "invalid_proxy_entrypoint",
|
|
516
|
+
message: "The `proxy.entrypoint` path must be relative to the project root and cannot contain traversal, query, fragment, or control characters."
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
if (!/\.(?:js|ts)$/.test(entrypoint) || entrypoint.endsWith(".d.ts")) {
|
|
520
|
+
return {
|
|
521
|
+
code: "invalid_proxy_entrypoint",
|
|
522
|
+
message: "The `proxy.entrypoint` path must end in `.js` or `.ts` and reference an executable file."
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
if (proxy.matcher !== void 0) {
|
|
526
|
+
const matchers = Array.isArray(proxy.matcher) ? proxy.matcher : [proxy.matcher];
|
|
527
|
+
if (matchers.length === 0 || matchers.some(
|
|
528
|
+
(matcher) => typeof matcher !== "string" || !matcher.startsWith("/")
|
|
529
|
+
)) {
|
|
530
|
+
return {
|
|
531
|
+
code: "invalid_proxy_matcher",
|
|
532
|
+
message: "The `proxy.matcher` value must be a path matcher starting with `/`, or an array of path matchers starting with `/`."
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
538
|
+
function validateProxy(options, files, framework) {
|
|
539
|
+
const { proxy } = options;
|
|
540
|
+
if (!proxy) {
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
const configError = validateProxyConfig(proxy);
|
|
544
|
+
if (configError) {
|
|
545
|
+
return configError;
|
|
546
|
+
}
|
|
547
|
+
if (!files.includes(proxy.entrypoint)) {
|
|
548
|
+
return {
|
|
549
|
+
code: "proxy_entrypoint_not_found",
|
|
550
|
+
message: `The proxy entrypoint \`${proxy.entrypoint}\` does not exist. Set \`proxy.entrypoint\` to an existing \`.js\` or \`.ts\` file.`
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
if (framework === "nextjs" || framework === "astro") {
|
|
554
|
+
return {
|
|
555
|
+
code: "proxy_framework_conflict",
|
|
556
|
+
message: `The \`proxy\` property cannot be used with ${framework === "nextjs" ? "Next.js" : "Astro"} because the framework builds its own routing middleware.`
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
420
561
|
function hasBuildScript(pkg) {
|
|
421
562
|
const { scripts = {} } = pkg || {};
|
|
422
563
|
return Boolean(scripts && scripts["build"]);
|
|
@@ -870,5 +1011,7 @@ function sortFilesBySegmentCount(fileA, fileB) {
|
|
|
870
1011
|
detectApiExtensions,
|
|
871
1012
|
detectBuilders,
|
|
872
1013
|
detectOutputDirectory,
|
|
873
|
-
|
|
1014
|
+
getProxyBuilder,
|
|
1015
|
+
sortFiles,
|
|
1016
|
+
validateProxyConfig
|
|
874
1017
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { detectBuilders, detectOutputDirectory, detectApiDirectory, detectApiExtensions, type Options as DetectBuildersOptions, } from './detect-builders';
|
|
1
|
+
export { detectBuilders, detectOutputDirectory, detectApiDirectory, detectApiExtensions, getProxyBuilder, validateProxyConfig, type Options as DetectBuildersOptions, type ProxyConfig, } from './detect-builders';
|
|
2
2
|
export { detectServices, generateServicesRoutes, } from './services/detect-services';
|
|
3
3
|
export { resolveAllConfiguredServicesV2, resolveConfiguredServiceV2, validateServiceConfigV2, } from './services/resolve-v2';
|
|
4
4
|
export { isExperimentalService, isExperimentalServiceV2, } from '@vercel/build-utils';
|
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ __export(src_exports, {
|
|
|
46
46
|
getInternalServiceWorkerPath: () => import_utils.getInternalServiceWorkerPath,
|
|
47
47
|
getInternalServiceWorkerPathPrefix: () => import_utils.getInternalServiceWorkerPathPrefix,
|
|
48
48
|
getProjectPaths: () => import_get_project_paths.getProjectPaths,
|
|
49
|
+
getProxyBuilder: () => import_detect_builders.getProxyBuilder,
|
|
49
50
|
getServicesBuilders: () => import_get_services_builders.getServicesBuilders,
|
|
50
51
|
getWorkspacePackagePaths: () => import_get_workspace_package_paths.getWorkspacePackagePaths,
|
|
51
52
|
getWorkspaces: () => import_get_workspaces.getWorkspaces,
|
|
@@ -59,6 +60,7 @@ __export(src_exports, {
|
|
|
59
60
|
packageManagers: () => import_package_managers.packageManagers,
|
|
60
61
|
resolveAllConfiguredServicesV2: () => import_resolve_v2.resolveAllConfiguredServicesV2,
|
|
61
62
|
resolveConfiguredServiceV2: () => import_resolve_v2.resolveConfiguredServiceV2,
|
|
63
|
+
validateProxyConfig: () => import_detect_builders.validateProxyConfig,
|
|
62
64
|
validateServiceConfigV2: () => import_resolve_v2.validateServiceConfigV2,
|
|
63
65
|
workspaceManagers: () => import_workspace_managers.workspaceManagers
|
|
64
66
|
});
|
|
@@ -113,6 +115,7 @@ var import_detect_instrumentation = require("./detect-instrumentation");
|
|
|
113
115
|
getInternalServiceWorkerPath,
|
|
114
116
|
getInternalServiceWorkerPathPrefix,
|
|
115
117
|
getProjectPaths,
|
|
118
|
+
getProxyBuilder,
|
|
116
119
|
getServicesBuilders,
|
|
117
120
|
getWorkspacePackagePaths,
|
|
118
121
|
getWorkspaces,
|
|
@@ -126,6 +129,7 @@ var import_detect_instrumentation = require("./detect-instrumentation");
|
|
|
126
129
|
packageManagers,
|
|
127
130
|
resolveAllConfiguredServicesV2,
|
|
128
131
|
resolveConfiguredServiceV2,
|
|
132
|
+
validateProxyConfig,
|
|
129
133
|
validateServiceConfigV2,
|
|
130
134
|
workspaceManagers,
|
|
131
135
|
...require("./monorepos/get-monorepo-default-settings")
|
package/dist/services/utils.js
CHANGED
|
@@ -177,7 +177,7 @@ async function readVercelConfig(fs) {
|
|
|
177
177
|
};
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
const hasVercelToml =
|
|
180
|
+
const hasVercelToml = await fs.hasPath("vercel.toml");
|
|
181
181
|
if (hasVercelToml) {
|
|
182
182
|
try {
|
|
183
183
|
const { parse: tomlParse } = await import("smol-toml");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/fs-detectors",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.14.0",
|
|
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/
|
|
23
|
+
"@vercel/build-utils": "13.36.0",
|
|
24
|
+
"@vercel/frameworks": "3.30.7",
|
|
24
25
|
"@vercel/error-utils": "2.2.0",
|
|
25
|
-
"@vercel/
|
|
26
|
-
"@vercel/frameworks": "3.30.7"
|
|
26
|
+
"@vercel/routing-utils": "6.4.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/glob": "7.2.0",
|