@vercel/fs-detectors 7.6.1 → 7.7.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 +7 -0
- package/dist/detect-builders.js +387 -46
- package/dist/services/resolve-v2.js +1 -1
- package/package.json +6 -6
|
@@ -27,6 +27,13 @@ export interface ProxyConfig {
|
|
|
27
27
|
export interface Options {
|
|
28
28
|
tag?: string;
|
|
29
29
|
functions?: BuilderFunctions;
|
|
30
|
+
/**
|
|
31
|
+
* Source files built by a builder that detection does not create itself
|
|
32
|
+
* (e.g. schedule entrypoints resolved by the CLI). Detection neither builds
|
|
33
|
+
* them as `api/` functions nor serves them as static files, and `functions`
|
|
34
|
+
* patterns that match them count as used.
|
|
35
|
+
*/
|
|
36
|
+
reservedFunctionFiles?: string[];
|
|
30
37
|
ignoreBuildScript?: boolean;
|
|
31
38
|
projectSettings?: ProjectSettings;
|
|
32
39
|
cleanUrls?: boolean;
|
package/dist/detect-builders.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -26,6 +29,272 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
29
|
mod
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// ../../internals/runtimes/dist/constants.js
|
|
34
|
+
var require_constants = __commonJS({
|
|
35
|
+
"../../internals/runtimes/dist/constants.js"(exports, module2) {
|
|
36
|
+
"use strict";
|
|
37
|
+
var __defProp2 = Object.defineProperty;
|
|
38
|
+
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
39
|
+
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
40
|
+
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
41
|
+
var __export2 = (target, all) => {
|
|
42
|
+
for (var name in all)
|
|
43
|
+
__defProp2(target, name, { get: all[name], enumerable: true });
|
|
44
|
+
};
|
|
45
|
+
var __copyProps2 = (to, from, except, desc) => {
|
|
46
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
47
|
+
for (let key of __getOwnPropNames2(from))
|
|
48
|
+
if (!__hasOwnProp2.call(to, key) && key !== except)
|
|
49
|
+
__defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
|
|
50
|
+
}
|
|
51
|
+
return to;
|
|
52
|
+
};
|
|
53
|
+
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
54
|
+
var constants_exports = {};
|
|
55
|
+
__export2(constants_exports, {
|
|
56
|
+
BUILDER_RUNTIMES: () => BUILDER_RUNTIMES,
|
|
57
|
+
CONTAINER_ENTRYPOINT_CANDIDATES: () => CONTAINER_ENTRYPOINT_CANDIDATES,
|
|
58
|
+
ENTRYPOINT_EXTENSIONS: () => ENTRYPOINT_EXTENSIONS2,
|
|
59
|
+
ROUTE_OWNING_BUILDERS: () => ROUTE_OWNING_BUILDERS,
|
|
60
|
+
RUNTIME_BUILDERS: () => RUNTIME_BUILDERS,
|
|
61
|
+
RUNTIME_MANIFESTS: () => RUNTIME_MANIFESTS,
|
|
62
|
+
STATIC_BUILDERS: () => STATIC_BUILDERS
|
|
63
|
+
});
|
|
64
|
+
module2.exports = __toCommonJS2(constants_exports);
|
|
65
|
+
var RUNTIME_BUILDERS = {
|
|
66
|
+
node: "@vercel/backends",
|
|
67
|
+
python: "@vercel/python",
|
|
68
|
+
go: "@vercel/go",
|
|
69
|
+
rust: "@vercel/rust",
|
|
70
|
+
ruby: "@vercel/ruby",
|
|
71
|
+
container: "@vercel/container"
|
|
72
|
+
};
|
|
73
|
+
var RUNTIME_MANIFESTS = {
|
|
74
|
+
node: ["package.json"],
|
|
75
|
+
python: [
|
|
76
|
+
"pyproject.toml",
|
|
77
|
+
"requirements.txt",
|
|
78
|
+
"Pipfile",
|
|
79
|
+
"pylock.yml",
|
|
80
|
+
"uv.lock",
|
|
81
|
+
"setup.py"
|
|
82
|
+
],
|
|
83
|
+
go: ["go.mod"],
|
|
84
|
+
ruby: ["Gemfile"],
|
|
85
|
+
rust: ["Cargo.toml"]
|
|
86
|
+
};
|
|
87
|
+
var ENTRYPOINT_EXTENSIONS2 = {
|
|
88
|
+
".ts": "node",
|
|
89
|
+
".mts": "node",
|
|
90
|
+
".js": "node",
|
|
91
|
+
".mjs": "node",
|
|
92
|
+
".cjs": "node",
|
|
93
|
+
".py": "python",
|
|
94
|
+
".go": "go",
|
|
95
|
+
".rs": "rust",
|
|
96
|
+
".rb": "ruby",
|
|
97
|
+
".ru": "ruby"
|
|
98
|
+
};
|
|
99
|
+
var BUILDER_RUNTIMES = Object.fromEntries(
|
|
100
|
+
Object.entries(RUNTIME_BUILDERS).map(([runtime, builder]) => [
|
|
101
|
+
builder,
|
|
102
|
+
runtime
|
|
103
|
+
])
|
|
104
|
+
);
|
|
105
|
+
var STATIC_BUILDERS = /* @__PURE__ */ new Set([
|
|
106
|
+
"@vercel/static-build",
|
|
107
|
+
"@vercel/static"
|
|
108
|
+
]);
|
|
109
|
+
var ROUTE_OWNING_BUILDERS = /* @__PURE__ */ new Set([
|
|
110
|
+
"@vercel/next",
|
|
111
|
+
"@vercel/backends"
|
|
112
|
+
]);
|
|
113
|
+
var CONTAINER_ENTRYPOINT_CANDIDATES = [
|
|
114
|
+
"Dockerfile.vercel",
|
|
115
|
+
"Containerfile.vercel",
|
|
116
|
+
"Dockerfile",
|
|
117
|
+
"Containerfile"
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// ../../internals/runtimes/dist/entrypoint.js
|
|
123
|
+
var require_entrypoint = __commonJS({
|
|
124
|
+
"../../internals/runtimes/dist/entrypoint.js"(exports, module2) {
|
|
125
|
+
"use strict";
|
|
126
|
+
var __defProp2 = Object.defineProperty;
|
|
127
|
+
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
128
|
+
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
129
|
+
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
130
|
+
var __export2 = (target, all) => {
|
|
131
|
+
for (var name in all)
|
|
132
|
+
__defProp2(target, name, { get: all[name], enumerable: true });
|
|
133
|
+
};
|
|
134
|
+
var __copyProps2 = (to, from, except, desc) => {
|
|
135
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
136
|
+
for (let key of __getOwnPropNames2(from))
|
|
137
|
+
if (!__hasOwnProp2.call(to, key) && key !== except)
|
|
138
|
+
__defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
|
|
139
|
+
}
|
|
140
|
+
return to;
|
|
141
|
+
};
|
|
142
|
+
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
143
|
+
var entrypoint_exports = {};
|
|
144
|
+
__export2(entrypoint_exports, {
|
|
145
|
+
SCHEDULE_ENTRYPOINT_FORMS_HINT: () => SCHEDULE_ENTRYPOINT_FORMS_HINT,
|
|
146
|
+
isDockerfileEntrypoint: () => isDockerfileEntrypoint,
|
|
147
|
+
parsePyModuleAttrEntrypoint: () => parsePyModuleAttrEntrypoint2,
|
|
148
|
+
parseScheduleEntrypoint: () => parseScheduleEntrypoint,
|
|
149
|
+
stripTrailingSlash: () => stripTrailingSlash
|
|
150
|
+
});
|
|
151
|
+
module2.exports = __toCommonJS2(entrypoint_exports);
|
|
152
|
+
var import_path2 = require("path");
|
|
153
|
+
var import_constants2 = require_constants();
|
|
154
|
+
var PYTHON_MODULE_ATTR_RE = /^([A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)*):([A-Za-z_][\w]*)$/;
|
|
155
|
+
var NODE_FILE_ENTRYPOINT_RE = /^(?!\/)(?!.*(?:^|\/)\.\.?(?:\/|$))(?:[\w@+.-]+\/)*[\w@+.-]+\.[cm]?[jt]s$/;
|
|
156
|
+
var NODE_DECLARATION_ENTRYPOINT_RE = /\.d\.[cm]?ts$/;
|
|
157
|
+
function parsePyModuleAttrEntrypoint2(entrypoint) {
|
|
158
|
+
const match = PYTHON_MODULE_ATTR_RE.exec(entrypoint);
|
|
159
|
+
if (!match)
|
|
160
|
+
return null;
|
|
161
|
+
const [, modulePart, attrName] = match;
|
|
162
|
+
if (!modulePart || !attrName)
|
|
163
|
+
return null;
|
|
164
|
+
return {
|
|
165
|
+
attrName,
|
|
166
|
+
filePath: modulePart.replace(/\./g, "/") + ".py",
|
|
167
|
+
moduleName: modulePart
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
var SCHEDULE_ENTRYPOINT_FORMS_HINT = 'Use a source file path like "jobs/nightly.ts" or a Python "module.path:function" reference.';
|
|
171
|
+
function parseScheduleEntrypoint(entrypoint) {
|
|
172
|
+
const python = parsePyModuleAttrEntrypoint2(entrypoint);
|
|
173
|
+
if (python) {
|
|
174
|
+
return { runtime: "python", ...python };
|
|
175
|
+
}
|
|
176
|
+
if (NODE_FILE_ENTRYPOINT_RE.test(entrypoint) && !NODE_DECLARATION_ENTRYPOINT_RE.test(entrypoint)) {
|
|
177
|
+
return { runtime: "node", filePath: entrypoint };
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
var CONTAINER_ENTRYPOINT_BASENAMES = new Set(
|
|
182
|
+
import_constants2.CONTAINER_ENTRYPOINT_CANDIDATES.map((name) => name.toLowerCase())
|
|
183
|
+
);
|
|
184
|
+
function isDockerfileEntrypoint(entrypoint) {
|
|
185
|
+
return CONTAINER_ENTRYPOINT_BASENAMES.has(
|
|
186
|
+
import_path2.posix.basename(entrypoint).toLowerCase()
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
function stripTrailingSlash(p) {
|
|
190
|
+
const stripped = p.replace(/\/+$/, "");
|
|
191
|
+
return stripped === "" ? "." : stripped;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// ../../internals/runtimes/dist/framework.js
|
|
197
|
+
var require_framework = __commonJS({
|
|
198
|
+
"../../internals/runtimes/dist/framework.js"(exports, module2) {
|
|
199
|
+
"use strict";
|
|
200
|
+
var __defProp2 = Object.defineProperty;
|
|
201
|
+
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
202
|
+
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
203
|
+
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
204
|
+
var __export2 = (target, all) => {
|
|
205
|
+
for (var name in all)
|
|
206
|
+
__defProp2(target, name, { get: all[name], enumerable: true });
|
|
207
|
+
};
|
|
208
|
+
var __copyProps2 = (to, from, except, desc) => {
|
|
209
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
210
|
+
for (let key of __getOwnPropNames2(from))
|
|
211
|
+
if (!__hasOwnProp2.call(to, key) && key !== except)
|
|
212
|
+
__defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
|
|
213
|
+
}
|
|
214
|
+
return to;
|
|
215
|
+
};
|
|
216
|
+
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
217
|
+
var framework_exports = {};
|
|
218
|
+
__export2(framework_exports, {
|
|
219
|
+
DETECTION_FRAMEWORKS: () => DETECTION_FRAMEWORKS,
|
|
220
|
+
filterFrameworksByRuntime: () => filterFrameworksByRuntime,
|
|
221
|
+
frameworksBySlug: () => frameworksBySlug,
|
|
222
|
+
inferBuilderRuntimeFromFramework: () => inferBuilderRuntimeFromFramework2,
|
|
223
|
+
inferRuntimeFromFramework: () => inferRuntimeFromFramework,
|
|
224
|
+
inferServerRuntimeFromFramework: () => inferServerRuntimeFromFramework,
|
|
225
|
+
isBFFFramework: () => isBFFFramework,
|
|
226
|
+
isFrontendFramework: () => isFrontendFramework
|
|
227
|
+
});
|
|
228
|
+
module2.exports = __toCommonJS2(framework_exports);
|
|
229
|
+
var import_build_utils3 = require("@vercel/build-utils");
|
|
230
|
+
var import_frameworks2 = require("@vercel/frameworks");
|
|
231
|
+
var import_constants2 = require_constants();
|
|
232
|
+
var frameworksBySlug = new Map(
|
|
233
|
+
import_frameworks2.frameworkList.flatMap((f) => typeof f.slug === "string" ? [[f.slug, f]] : [])
|
|
234
|
+
);
|
|
235
|
+
var DETECTION_FRAMEWORKS = import_frameworks2.frameworkList.filter(
|
|
236
|
+
(framework) => !framework.experimental || framework.runtimeFramework
|
|
237
|
+
);
|
|
238
|
+
function inferRuntimeFromFramework(framework) {
|
|
239
|
+
if (!framework)
|
|
240
|
+
return void 0;
|
|
241
|
+
if (framework in import_constants2.RUNTIME_BUILDERS)
|
|
242
|
+
return framework;
|
|
243
|
+
if ((0, import_build_utils3.isPythonFramework)(framework))
|
|
244
|
+
return "python";
|
|
245
|
+
if ((0, import_build_utils3.isBackendFramework)(framework))
|
|
246
|
+
return "node";
|
|
247
|
+
return void 0;
|
|
248
|
+
}
|
|
249
|
+
var STATIC_BUILDER_RUNTIMES = {
|
|
250
|
+
hugo: "go",
|
|
251
|
+
jekyll: "ruby",
|
|
252
|
+
middleman: "ruby",
|
|
253
|
+
zola: "rust"
|
|
254
|
+
};
|
|
255
|
+
function inferServerRuntimeFromFramework(framework) {
|
|
256
|
+
if (!framework || framework === "services")
|
|
257
|
+
return void 0;
|
|
258
|
+
const builder = frameworksBySlug.get(framework)?.useRuntime?.use;
|
|
259
|
+
if (!builder)
|
|
260
|
+
return void 0;
|
|
261
|
+
return import_constants2.BUILDER_RUNTIMES[builder] ?? "node";
|
|
262
|
+
}
|
|
263
|
+
function inferBuilderRuntimeFromFramework2(framework) {
|
|
264
|
+
if (!framework || framework === "container" || framework === "services")
|
|
265
|
+
return void 0;
|
|
266
|
+
const f = frameworksBySlug.get(framework);
|
|
267
|
+
const declaredBuilder = f?.useRuntime?.use;
|
|
268
|
+
if (declaredBuilder)
|
|
269
|
+
return import_constants2.BUILDER_RUNTIMES[declaredBuilder];
|
|
270
|
+
const detectorItems = [
|
|
271
|
+
...f?.detectors?.every ?? [],
|
|
272
|
+
...f?.detectors?.some ?? []
|
|
273
|
+
];
|
|
274
|
+
return STATIC_BUILDER_RUNTIMES[framework] ?? (detectorItems.some((d) => d.matchPackage !== void 0) ? "node" : void 0);
|
|
275
|
+
}
|
|
276
|
+
function isFrontendFramework(framework) {
|
|
277
|
+
return !!framework && !inferRuntimeFromFramework(framework);
|
|
278
|
+
}
|
|
279
|
+
var BFF_FRAMEWORKS = /* @__PURE__ */ new Set([
|
|
280
|
+
"nextjs",
|
|
281
|
+
"nuxtjs",
|
|
282
|
+
"sveltekit",
|
|
283
|
+
"remix",
|
|
284
|
+
"solidstart"
|
|
285
|
+
]);
|
|
286
|
+
function isBFFFramework(framework) {
|
|
287
|
+
return !!framework && BFF_FRAMEWORKS.has(framework);
|
|
288
|
+
}
|
|
289
|
+
function filterFrameworksByRuntime(frameworks, runtime) {
|
|
290
|
+
if (!runtime)
|
|
291
|
+
return [...frameworks];
|
|
292
|
+
return frameworks.filter((f) => inferRuntimeFromFramework(f.slug) === runtime);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// src/detect-builders.ts
|
|
29
298
|
var detect_builders_exports = {};
|
|
30
299
|
__export(detect_builders_exports, {
|
|
31
300
|
REGEX_MIDDLEWARE_FILES: () => REGEX_MIDDLEWARE_FILES,
|
|
@@ -43,17 +312,53 @@ __export(detect_builders_exports, {
|
|
|
43
312
|
});
|
|
44
313
|
module.exports = __toCommonJS(detect_builders_exports);
|
|
45
314
|
var import_minimatch = __toESM(require("minimatch"));
|
|
315
|
+
var import_entrypoint = __toESM(require_entrypoint());
|
|
46
316
|
var import_semver = require("semver");
|
|
47
317
|
var import_path = require("path");
|
|
48
318
|
var import_frameworks = require("@vercel/frameworks");
|
|
49
|
-
var import_framework =
|
|
50
|
-
var import_constants =
|
|
51
|
-
|
|
319
|
+
var import_framework = __toESM(require_framework());
|
|
320
|
+
var import_constants = __toESM(require_constants());
|
|
321
|
+
|
|
322
|
+
// src/is-official-runtime.ts
|
|
323
|
+
var isOfficialRuntime = (desired, name) => {
|
|
324
|
+
if (typeof name !== "string") {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
return name === `@vercel/${desired}` || name === `@now/${desired}` || name.startsWith(`@vercel/${desired}@`) || name.startsWith(`@now/${desired}@`);
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// src/detect-builders.ts
|
|
331
|
+
var import_build_utils2 = require("@vercel/build-utils");
|
|
332
|
+
|
|
333
|
+
// src/python.ts
|
|
334
|
+
var import_fs = __toESM(require("fs"));
|
|
52
335
|
var import_build_utils = require("@vercel/build-utils");
|
|
53
|
-
var
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
336
|
+
var import_python_analysis = require("@vercel/python-analysis");
|
|
337
|
+
async function isPythonEntrypoint(fsPath) {
|
|
338
|
+
try {
|
|
339
|
+
const content = await import_fs.default.promises.readFile(fsPath, "utf-8");
|
|
340
|
+
return await (0, import_python_analysis.findAppOrHandler)(content) !== null;
|
|
341
|
+
} catch (err) {
|
|
342
|
+
(0, import_build_utils.debug)(`Failed to check Python entrypoint: ${err}`);
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/buildpack-runtimes.ts
|
|
348
|
+
var BUILDPACK_PROJECT_MARKERS = /* @__PURE__ */ new Map([["ruby", ["Gemfile"]]]);
|
|
349
|
+
function isBuildpackRuntimeEnabled(runtime) {
|
|
350
|
+
return process.env[`VERCEL_EXPERIMENTAL_BUILDPACK_${runtime.toUpperCase()}`] === "1";
|
|
351
|
+
}
|
|
352
|
+
function toBuildpackRuntime(runtime) {
|
|
353
|
+
if (!runtime || !BUILDPACK_PROJECT_MARKERS.has(runtime) || !isBuildpackRuntimeEnabled(runtime)) {
|
|
354
|
+
return void 0;
|
|
355
|
+
}
|
|
356
|
+
return runtime;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/detect-builders.ts
|
|
360
|
+
var REGEX_MIDDLEWARE_FILES = "middleware.[jt]s";
|
|
361
|
+
var VERCEL_PLATFORM_FILES = [
|
|
57
362
|
"api/**",
|
|
58
363
|
"node_modules/**",
|
|
59
364
|
REGEX_MIDDLEWARE_FILES,
|
|
@@ -66,7 +371,7 @@ const VERCEL_PLATFORM_FILES = [
|
|
|
66
371
|
".gitignore",
|
|
67
372
|
"README.md"
|
|
68
373
|
];
|
|
69
|
-
|
|
374
|
+
var REGEX_VERCEL_PLATFORM_FILES = VERCEL_PLATFORM_FILES.join(",");
|
|
70
375
|
function escapeMinimatchPath(path) {
|
|
71
376
|
return path.replace(/([\\,*?[\]{}()!+@])/g, "\\$1");
|
|
72
377
|
}
|
|
@@ -76,8 +381,8 @@ function getStaticFilesPattern(additionalExclusions = []) {
|
|
|
76
381
|
...additionalExclusions.map(escapeMinimatchPath)
|
|
77
382
|
].join(",")}}`;
|
|
78
383
|
}
|
|
79
|
-
|
|
80
|
-
|
|
384
|
+
var REGEX_NON_VERCEL_PLATFORM_FILES = getStaticFilesPattern();
|
|
385
|
+
var builderToFrameworks = (() => {
|
|
81
386
|
const map = /* @__PURE__ */ new Map();
|
|
82
387
|
for (const f of import_frameworks.frameworkList) {
|
|
83
388
|
if (!f.useRuntime?.use)
|
|
@@ -110,7 +415,7 @@ function detectApiDirectory(builders) {
|
|
|
110
415
|
}
|
|
111
416
|
function getPublicBuilder(builders) {
|
|
112
417
|
for (const builder of builders) {
|
|
113
|
-
if (typeof builder.src === "string" &&
|
|
418
|
+
if (typeof builder.src === "string" && isOfficialRuntime("static", builder.use) && /^.*\/\*\*\/\*$/.test(builder.src) && builder.config?.zeroConfig === true) {
|
|
114
419
|
return builder;
|
|
115
420
|
}
|
|
116
421
|
}
|
|
@@ -160,6 +465,13 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
160
465
|
usedFunctions.add(key);
|
|
161
466
|
};
|
|
162
467
|
const absolutePathCache = /* @__PURE__ */ new Map();
|
|
468
|
+
const proxyFile = options.proxy ? parseProxyEntrypoint(options.proxy.entrypoint).file : null;
|
|
469
|
+
const reservedFunctionFiles = options.reservedFunctionFiles ?? [];
|
|
470
|
+
const claimedFiles = /* @__PURE__ */ new Set([
|
|
471
|
+
...proxyFile !== null ? [proxyFile] : [],
|
|
472
|
+
...reservedFunctionFiles
|
|
473
|
+
]);
|
|
474
|
+
const hasReservedFunctions = reservedFunctionFiles.length > 0;
|
|
163
475
|
const { buildCommand, outputDirectory } = projectSettings;
|
|
164
476
|
const frameworkConfig = import_framework.frameworksBySlug.get(framework || "");
|
|
165
477
|
const rustStaticOutput = isRustStaticOutput(framework, projectSettings);
|
|
@@ -186,7 +498,7 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
186
498
|
const apiRoutes = [];
|
|
187
499
|
const dynamicRoutes = [];
|
|
188
500
|
for (const fileName of sortedFiles) {
|
|
189
|
-
if (fileName
|
|
501
|
+
if (claimedFiles.has(fileName)) {
|
|
190
502
|
continue;
|
|
191
503
|
}
|
|
192
504
|
const apiBuilder = await maybeGetApiBuilder(fileName, apiMatches, options);
|
|
@@ -250,7 +562,7 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
250
562
|
options
|
|
251
563
|
);
|
|
252
564
|
} else {
|
|
253
|
-
if (pkg && !makeFrontendStatic && !apiBuilders.length && !options.ignoreBuildScript) {
|
|
565
|
+
if (pkg && !makeFrontendStatic && !apiBuilders.length && !hasReservedFunctions && !options.ignoreBuildScript) {
|
|
254
566
|
errors.push(getMissingBuildScriptError());
|
|
255
567
|
return {
|
|
256
568
|
errors,
|
|
@@ -271,19 +583,17 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
271
583
|
outputDirectory: usedOutputDirectory
|
|
272
584
|
}
|
|
273
585
|
};
|
|
274
|
-
} else if (apiBuilders.length && hasNoneApiFiles) {
|
|
586
|
+
} else if ((apiBuilders.length || hasReservedFunctions) && hasNoneApiFiles) {
|
|
275
587
|
frontendBuilder = {
|
|
276
588
|
use: "@vercel/static",
|
|
277
|
-
src: getStaticFilesPattern(
|
|
278
|
-
options.proxy ? [options.proxy.entrypoint] : []
|
|
279
|
-
),
|
|
589
|
+
src: getStaticFilesPattern([...claimedFiles]),
|
|
280
590
|
config: {
|
|
281
591
|
zeroConfig: true
|
|
282
592
|
}
|
|
283
593
|
};
|
|
284
594
|
}
|
|
285
595
|
}
|
|
286
|
-
if (options.proxy && frontendBuilder &&
|
|
596
|
+
if (options.proxy && frontendBuilder && isOfficialRuntime("next", frontendBuilder.use)) {
|
|
287
597
|
return {
|
|
288
598
|
builders: null,
|
|
289
599
|
errors: [
|
|
@@ -302,6 +612,7 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
302
612
|
const unusedFunctionError = checkUnusedFunctions(
|
|
303
613
|
frontendBuilder,
|
|
304
614
|
usedFunctions,
|
|
615
|
+
claimedFiles,
|
|
305
616
|
options
|
|
306
617
|
);
|
|
307
618
|
if (unusedFunctionError) {
|
|
@@ -326,7 +637,7 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
326
637
|
builders.push(...apiBuilders);
|
|
327
638
|
}
|
|
328
639
|
if (frontendBuilder) {
|
|
329
|
-
if (
|
|
640
|
+
if (isOfficialRuntime("express", frontendBuilder?.use) || isOfficialRuntime("hono", frontendBuilder?.use) || isOfficialRuntime("python", frontendBuilder?.use) || isOfficialRuntime("go", frontendBuilder?.use) || isOfficialRuntime("backends", frontendBuilder?.use)) {
|
|
330
641
|
builders.push({
|
|
331
642
|
src: "public/**/*",
|
|
332
643
|
use: "@vercel/static",
|
|
@@ -337,7 +648,7 @@ async function detectBuilders(files, pkg, options = {}) {
|
|
|
337
648
|
});
|
|
338
649
|
}
|
|
339
650
|
builders.push(frontendBuilder);
|
|
340
|
-
if (hasNextApiFiles && apiBuilders.some((b) =>
|
|
651
|
+
if (hasNextApiFiles && apiBuilders.some((b) => isOfficialRuntime("node", b.use))) {
|
|
341
652
|
warnings.push({
|
|
342
653
|
code: "conflicting_files",
|
|
343
654
|
message: "When using Next.js, it is recommended to place JavaScript Functions inside of the `pages/api` (provided by Next.js) directory instead of `api` (provided by Vercel). Other languages (Python, Go, etc) should still go in the `api` directory.",
|
|
@@ -386,7 +697,7 @@ async function maybeGetApiBuilder(fileName, apiMatches, options) {
|
|
|
386
697
|
}
|
|
387
698
|
if (fileName.endsWith(".py") && options.workPath) {
|
|
388
699
|
const fsPath = (0, import_path.join)(options.workPath, fileName);
|
|
389
|
-
const isEntrypoint = await
|
|
700
|
+
const isEntrypoint = await isPythonEntrypoint(fsPath);
|
|
390
701
|
if (!isEntrypoint) {
|
|
391
702
|
return null;
|
|
392
703
|
}
|
|
@@ -394,7 +705,7 @@ async function maybeGetApiBuilder(fileName, apiMatches, options) {
|
|
|
394
705
|
const nodeExtensions = [".js", ".mjs", ".ts", ".tsx"];
|
|
395
706
|
if (fileName.startsWith("api/") && process.env.VERCEL_NODE_FILTER_ENTRYPOINTS === "1" && nodeExtensions.some((ext) => fileName.endsWith(ext)) && options.workPath) {
|
|
396
707
|
const fsPath = (0, import_path.join)(options.workPath, fileName);
|
|
397
|
-
const isEntrypoint = await (0,
|
|
708
|
+
const isEntrypoint = await (0, import_build_utils2.isNodeEntrypoint)({ fsPath });
|
|
398
709
|
if (!isEntrypoint) {
|
|
399
710
|
return null;
|
|
400
711
|
}
|
|
@@ -438,14 +749,25 @@ function getFunction(fileName, { functions = {} }) {
|
|
|
438
749
|
const func = keys.find((key) => key === fileName || (0, import_minimatch.default)(fileName, key));
|
|
439
750
|
return func ? { fnPattern: func, func: functions[func] } : { fnPattern: null, func: null };
|
|
440
751
|
}
|
|
752
|
+
function parseProxyEntrypoint(entrypoint) {
|
|
753
|
+
if (process.env.VERCEL_PYTHON_PROXY) {
|
|
754
|
+
const parsed = (0, import_entrypoint.parsePyModuleAttrEntrypoint)(entrypoint);
|
|
755
|
+
if (parsed)
|
|
756
|
+
return { file: parsed.filePath, variable: parsed.attrName };
|
|
757
|
+
}
|
|
758
|
+
return { file: entrypoint };
|
|
759
|
+
}
|
|
441
760
|
function getProxyBuilder(proxy, tag, functions = {}) {
|
|
442
|
-
const {
|
|
761
|
+
const { file, variable } = parseProxyEntrypoint(proxy.entrypoint);
|
|
762
|
+
const isPython = (0, import_path.extname)(file) === ".py";
|
|
763
|
+
const { fnPattern, func } = getFunction(file, { functions });
|
|
443
764
|
const runtime = func?.runtime;
|
|
444
765
|
const config = {
|
|
445
766
|
zeroConfig: true,
|
|
446
767
|
middleware: true,
|
|
447
|
-
...!runtime ? { middlewareRuntime: "nodejs" } : {},
|
|
448
|
-
...proxy.matcher ? { middlewareMatcher: proxy.matcher } : {}
|
|
768
|
+
...!runtime && !isPython ? { middlewareRuntime: "nodejs" } : {},
|
|
769
|
+
...proxy.matcher ? { middlewareMatcher: proxy.matcher } : {},
|
|
770
|
+
...variable ? { handlerFunction: variable } : {}
|
|
449
771
|
};
|
|
450
772
|
if (fnPattern && func) {
|
|
451
773
|
config.functions = { [fnPattern]: func };
|
|
@@ -456,9 +778,10 @@ function getProxyBuilder(proxy, tag, functions = {}) {
|
|
|
456
778
|
config.excludeFiles = func.excludeFiles;
|
|
457
779
|
}
|
|
458
780
|
}
|
|
781
|
+
const defaultRuntime = isPython ? `@vercel/python${tag ? `@${tag}` : ""}` : `@vercel/node${tag ? `@${tag}` : ""}`;
|
|
459
782
|
return {
|
|
460
|
-
src:
|
|
461
|
-
use: runtime ||
|
|
783
|
+
src: file,
|
|
784
|
+
use: runtime || defaultRuntime,
|
|
462
785
|
config
|
|
463
786
|
};
|
|
464
787
|
}
|
|
@@ -481,21 +804,29 @@ function validateProxyConfig(proxy) {
|
|
|
481
804
|
if (typeof proxy !== "object" || typeof proxy.entrypoint !== "string" || !proxy.entrypoint) {
|
|
482
805
|
return {
|
|
483
806
|
code: "invalid_proxy",
|
|
484
|
-
message: "The `proxy` property must contain an `entrypoint` string
|
|
807
|
+
message: "The `proxy` property must contain an `entrypoint` string."
|
|
485
808
|
};
|
|
486
809
|
}
|
|
487
|
-
const
|
|
488
|
-
const
|
|
489
|
-
|
|
810
|
+
const { file, variable } = parseProxyEntrypoint(proxy.entrypoint);
|
|
811
|
+
const isPythonForm = (0, import_path.extname)(file) === ".py";
|
|
812
|
+
const isJsForm = /\.(?:js|ts)$/.test(file) && !file.endsWith(".d.ts");
|
|
813
|
+
const segments = file.split("/");
|
|
814
|
+
if (file.startsWith("/") || file.includes("\\") || segments.includes(".") || segments.includes("..") || /[?#\u0000-\u001f]/.test(file)) {
|
|
490
815
|
return {
|
|
491
816
|
code: "invalid_proxy_entrypoint",
|
|
492
817
|
message: "The `proxy.entrypoint` path must be relative to the project root and cannot contain traversal, query, fragment, or control characters."
|
|
493
818
|
};
|
|
494
819
|
}
|
|
495
|
-
if (
|
|
820
|
+
if (!isPythonForm && !isJsForm) {
|
|
496
821
|
return {
|
|
497
822
|
code: "invalid_proxy_entrypoint",
|
|
498
|
-
message: "The `proxy.entrypoint`
|
|
823
|
+
message: "The `proxy.entrypoint` must be a `.js` or `.ts` file path, or a Python `module:attr`."
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
if (isPythonForm && !variable) {
|
|
827
|
+
return {
|
|
828
|
+
code: "invalid_proxy_entrypoint",
|
|
829
|
+
message: "Python proxy entrypoints must use `module:attr` syntax, not a plain `.py` path."
|
|
499
830
|
};
|
|
500
831
|
}
|
|
501
832
|
if (proxy.matcher !== void 0) {
|
|
@@ -520,10 +851,11 @@ function validateProxy(options, files, framework) {
|
|
|
520
851
|
if (configError) {
|
|
521
852
|
return configError;
|
|
522
853
|
}
|
|
523
|
-
|
|
854
|
+
const { file } = parseProxyEntrypoint(proxy.entrypoint);
|
|
855
|
+
if (!files.includes(file)) {
|
|
524
856
|
return {
|
|
525
857
|
code: "proxy_entrypoint_not_found",
|
|
526
|
-
message: `The proxy entrypoint \`${proxy.entrypoint}\` does not exist
|
|
858
|
+
message: `The proxy entrypoint \`${proxy.entrypoint}\` does not exist.`
|
|
527
859
|
};
|
|
528
860
|
}
|
|
529
861
|
if (framework === "nextjs" || framework === "astro") {
|
|
@@ -533,7 +865,8 @@ function validateProxy(options, files, framework) {
|
|
|
533
865
|
};
|
|
534
866
|
}
|
|
535
867
|
const appRuntime = (0, import_framework.inferBuilderRuntimeFromFramework)(framework);
|
|
536
|
-
const
|
|
868
|
+
const { file: proxyFile } = parseProxyEntrypoint(proxy.entrypoint);
|
|
869
|
+
const proxyRuntime = import_constants.ENTRYPOINT_EXTENSIONS[(0, import_path.extname)(proxyFile)];
|
|
537
870
|
if (appRuntime !== void 0 && proxyRuntime !== void 0 && appRuntime !== proxyRuntime) {
|
|
538
871
|
return {
|
|
539
872
|
code: "proxy_runtime_mismatch",
|
|
@@ -596,8 +929,8 @@ function detectFrontBuilder(pkg, files, usedFunctions, fallbackEntrypoint, optio
|
|
|
596
929
|
}
|
|
597
930
|
const f = import_framework.frameworksBySlug.get(framework || "");
|
|
598
931
|
if (f && f.useRuntime && !isRustStaticOutput(framework, projectSettings)) {
|
|
599
|
-
const buildpackRuntime =
|
|
600
|
-
if (buildpackRuntime && (
|
|
932
|
+
const buildpackRuntime = toBuildpackRuntime(framework);
|
|
933
|
+
if (buildpackRuntime && (BUILDPACK_PROJECT_MARKERS.get(buildpackRuntime) ?? []).some(
|
|
601
934
|
(marker) => files.includes(marker)
|
|
602
935
|
)) {
|
|
603
936
|
config.buildpack = buildpackRuntime;
|
|
@@ -608,8 +941,8 @@ function detectFrontBuilder(pkg, files, usedFunctions, fallbackEntrypoint, optio
|
|
|
608
941
|
};
|
|
609
942
|
}
|
|
610
943
|
const { src, use } = f.useRuntime;
|
|
611
|
-
const shouldUseUnifiedBackend = (0,
|
|
612
|
-
const finalUse = shouldUseUnifiedBackend ?
|
|
944
|
+
const shouldUseUnifiedBackend = (0, import_build_utils2.isExperimentalBackendsEnabled)() && import_build_utils2.BACKEND_BUILDERS.includes(use);
|
|
945
|
+
const finalUse = shouldUseUnifiedBackend ? import_build_utils2.UNIFIED_BACKEND_BUILDER : use;
|
|
613
946
|
return { src, use: `${finalUse}${withTag}`, config };
|
|
614
947
|
}
|
|
615
948
|
const entrypoints = /* @__PURE__ */ new Set([
|
|
@@ -654,7 +987,7 @@ function validateFunctions({ functions = {} }) {
|
|
|
654
987
|
message: "Function must contain at least one property."
|
|
655
988
|
};
|
|
656
989
|
}
|
|
657
|
-
const maxDurationLimit = (0,
|
|
990
|
+
const maxDurationLimit = (0, import_build_utils2.getMaxDurationLimit)();
|
|
658
991
|
if (func.maxDuration !== void 0 && func.maxDuration !== "max" && (func.maxDuration < 1 || maxDurationLimit !== void 0 && func.maxDuration > maxDurationLimit || !Number.isInteger(func.maxDuration))) {
|
|
659
992
|
return {
|
|
660
993
|
code: "invalid_function_duration",
|
|
@@ -701,14 +1034,22 @@ function validateFunctions({ functions = {} }) {
|
|
|
701
1034
|
}
|
|
702
1035
|
return null;
|
|
703
1036
|
}
|
|
704
|
-
function checkUnusedFunctions(frontendBuilder, usedFunctions, options) {
|
|
1037
|
+
function checkUnusedFunctions(frontendBuilder, usedFunctions, claimedFiles, options) {
|
|
705
1038
|
const unusedFunctions = new Set(
|
|
706
1039
|
Object.keys(options.functions || {}).filter((key) => !usedFunctions.has(key))
|
|
707
1040
|
);
|
|
1041
|
+
for (const fnKey of unusedFunctions) {
|
|
1042
|
+
for (const filePath of claimedFiles) {
|
|
1043
|
+
if (filePath === fnKey || (0, import_minimatch.default)(filePath, fnKey)) {
|
|
1044
|
+
unusedFunctions.delete(fnKey);
|
|
1045
|
+
break;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
708
1049
|
if (!unusedFunctions.size) {
|
|
709
1050
|
return null;
|
|
710
1051
|
}
|
|
711
|
-
if (frontendBuilder &&
|
|
1052
|
+
if (frontendBuilder && isOfficialRuntime("next", frontendBuilder.use)) {
|
|
712
1053
|
for (const fnKey of unusedFunctions.values()) {
|
|
713
1054
|
if (fnKey.startsWith("pages/") || fnKey.startsWith("src/pages") || fnKey.startsWith("app/") || fnKey.startsWith("src/app/") || fnKey.startsWith("middleware") || fnKey.startsWith("src/middleware")) {
|
|
714
1055
|
unusedFunctions.delete(fnKey);
|
|
@@ -722,7 +1063,7 @@ function checkUnusedFunctions(frontendBuilder, usedFunctions, options) {
|
|
|
722
1063
|
}
|
|
723
1064
|
}
|
|
724
1065
|
}
|
|
725
|
-
if (frontendBuilder && (
|
|
1066
|
+
if (frontendBuilder && (isOfficialRuntime("express", frontendBuilder.use) || isOfficialRuntime("hono", frontendBuilder.use) || isOfficialRuntime("python", frontendBuilder.use) || isOfficialRuntime("backends", frontendBuilder.use))) {
|
|
726
1067
|
return null;
|
|
727
1068
|
}
|
|
728
1069
|
if (unusedFunctions.size) {
|
|
@@ -912,7 +1253,7 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
|
|
|
912
1253
|
const errorRoutes = [];
|
|
913
1254
|
const framework = frontendBuilder?.config?.framework || "";
|
|
914
1255
|
const isGatsby = framework === "gatsby";
|
|
915
|
-
const isNextjs = framework === "nextjs" ||
|
|
1256
|
+
const isNextjs = framework === "nextjs" || isOfficialRuntime("next", frontendBuilder?.use);
|
|
916
1257
|
const ignoreRuntimes = import_framework.frameworksBySlug.get(framework)?.ignoreRuntimes;
|
|
917
1258
|
if (apiRoutes && apiRoutes.length > 0) {
|
|
918
1259
|
if (options.featHandleMiss) {
|
|
@@ -961,7 +1302,7 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
|
|
|
961
1302
|
}
|
|
962
1303
|
}
|
|
963
1304
|
}
|
|
964
|
-
if (outputDirectory && frontendBuilder && !options.featHandleMiss &&
|
|
1305
|
+
if (outputDirectory && frontendBuilder && !options.featHandleMiss && isOfficialRuntime("static", frontendBuilder.use)) {
|
|
965
1306
|
defaultRoutes.push({
|
|
966
1307
|
src: "/(.*)",
|
|
967
1308
|
dest: `/${outputDirectory}/$1`
|
|
@@ -248,7 +248,7 @@ async function resolveConfiguredServiceV2(name, config, fs) {
|
|
|
248
248
|
}
|
|
249
249
|
};
|
|
250
250
|
}
|
|
251
|
-
const buildpackRuntime = flaggedBuildpackRuntime && !entrypointFile && !(0, import_framework.isFrontendFramework)(framework) && await (0, import_buildpack_runtimes.hasBuildpackProjectMarker)(
|
|
251
|
+
const buildpackRuntime = flaggedBuildpackRuntime && (!entrypointFile || flaggedBuildpackRuntime === "ruby" && entrypointFile === "config.ru") && !(0, import_framework.isFrontendFramework)(framework) && await (0, import_buildpack_runtimes.hasBuildpackProjectMarker)(
|
|
252
252
|
flaggedBuildpackRuntime,
|
|
253
253
|
(marker) => (0, import_utils.hasFile)(serviceFs, marker)
|
|
254
254
|
) ? flaggedBuildpackRuntime : void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/fs-detectors",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.7.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/
|
|
23
|
+
"@vercel/error-utils": "2.2.1",
|
|
24
|
+
"@vercel/build-utils": "14.11.0",
|
|
24
25
|
"@vercel/frameworks": "3.34.0",
|
|
25
|
-
"@vercel/python-analysis": "0.14.0",
|
|
26
26
|
"@vercel/routing-utils": "6.6.0",
|
|
27
|
-
"@vercel/
|
|
27
|
+
"@vercel/python-analysis": "0.14.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/glob": "7.2.0",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"@types/node": "20.11.0",
|
|
34
34
|
"@types/semver": "7.3.10",
|
|
35
35
|
"vitest": "4.1.10",
|
|
36
|
-
"@vercel-internals/runtimes": "1.1.
|
|
36
|
+
"@vercel-internals/runtimes": "1.1.2"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
|
-
"build": "node
|
|
39
|
+
"build": "node build.mjs",
|
|
40
40
|
"test": "vitest run --config ../../vitest.config.mts",
|
|
41
41
|
"test-unit": "vitest run --config ../../vitest.config.mts test/unit.",
|
|
42
42
|
"type-check": "tsc --noEmit"
|