@vercel/build-utils 13.27.1 → 13.27.2
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/CHANGELOG.md +7 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +348 -156
- package/dist/max-duration.d.ts +44 -0
- package/dist/max-duration.js +54 -0
- package/dist/node-entrypoint.d.ts +8 -7
- package/dist/node-entrypoint.js +49 -20
- package/dist/schemas.d.ts +1 -3
- package/dist/schemas.js +2 -6
- package/dist/strip-comments-and-literals.d.ts +16 -0
- package/dist/strip-comments-and-literals.js +39 -0
- package/package.json +1 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vercel Functions have historically had a hard timeout limit of 900 seconds
|
|
3
|
+
* (15 minutes), which has long doubled as the client-side upper bound for
|
|
4
|
+
* `maxDuration` in `vercel.json` and zero-config function detection.
|
|
5
|
+
*
|
|
6
|
+
* The authoritative limit is enforced by server-side validation at deploy time.
|
|
7
|
+
* The CLI and `@vercel/build-utils` cannot know that limit at build time, so
|
|
8
|
+
* this client-side bound is intentionally coarse — it exists only to give fast
|
|
9
|
+
* local feedback on obviously-invalid values.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_MAX_DURATION_LIMIT = 900;
|
|
12
|
+
/**
|
|
13
|
+
* Internal env var used to skip the client-side `maxDuration` upper-bound check.
|
|
14
|
+
* When set to `'1'`, the client-side maximum ({@link DEFAULT_MAX_DURATION_LIMIT})
|
|
15
|
+
* is not applied and validation defers to the server, so the limit can be
|
|
16
|
+
* adjusted centrally without requiring users to upgrade their CLI. The lower
|
|
17
|
+
* bound and integer checks are always enforced regardless of this flag.
|
|
18
|
+
*/
|
|
19
|
+
export declare const SKIP_MAX_DURATION_LIMIT_ENV = "VERCEL_CLI_SKIP_MAX_DURATION_LIMIT";
|
|
20
|
+
/**
|
|
21
|
+
* Returns the client-side upper bound for `maxDuration` in seconds, or
|
|
22
|
+
* `undefined` when the bound is skipped via {@link SKIP_MAX_DURATION_LIMIT_ENV}
|
|
23
|
+
* (server-side validation governs the real limit in that case). The lower bound
|
|
24
|
+
* and integer checks are always enforced by callers regardless of this flag.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getMaxDurationLimit(): number | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Returns the JSON Schema fragment used to validate a function's `maxDuration`
|
|
29
|
+
* in `vercel.json`. When the client-side upper bound is active the integer
|
|
30
|
+
* branch includes a `maximum`; when skipped via
|
|
31
|
+
* {@link SKIP_MAX_DURATION_LIMIT_ENV} the `maximum` is omitted so any positive
|
|
32
|
+
* integer passes schema validation and the server enforces the limit.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getMaxDurationSchema(): {
|
|
35
|
+
oneOf: ({
|
|
36
|
+
maximum?: number | undefined;
|
|
37
|
+
type: string;
|
|
38
|
+
minimum: number;
|
|
39
|
+
enum?: undefined;
|
|
40
|
+
} | {
|
|
41
|
+
type: string;
|
|
42
|
+
enum: string[];
|
|
43
|
+
})[];
|
|
44
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
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 max_duration_exports = {};
|
|
20
|
+
__export(max_duration_exports, {
|
|
21
|
+
DEFAULT_MAX_DURATION_LIMIT: () => DEFAULT_MAX_DURATION_LIMIT,
|
|
22
|
+
SKIP_MAX_DURATION_LIMIT_ENV: () => SKIP_MAX_DURATION_LIMIT_ENV,
|
|
23
|
+
getMaxDurationLimit: () => getMaxDurationLimit,
|
|
24
|
+
getMaxDurationSchema: () => getMaxDurationSchema
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(max_duration_exports);
|
|
27
|
+
const DEFAULT_MAX_DURATION_LIMIT = 900;
|
|
28
|
+
const SKIP_MAX_DURATION_LIMIT_ENV = "VERCEL_CLI_SKIP_MAX_DURATION_LIMIT";
|
|
29
|
+
function getMaxDurationLimit() {
|
|
30
|
+
if (process.env[SKIP_MAX_DURATION_LIMIT_ENV] === "1") {
|
|
31
|
+
return void 0;
|
|
32
|
+
}
|
|
33
|
+
return DEFAULT_MAX_DURATION_LIMIT;
|
|
34
|
+
}
|
|
35
|
+
function getMaxDurationSchema() {
|
|
36
|
+
const limit = getMaxDurationLimit();
|
|
37
|
+
return {
|
|
38
|
+
oneOf: [
|
|
39
|
+
{
|
|
40
|
+
type: "integer",
|
|
41
|
+
minimum: 1,
|
|
42
|
+
...limit !== void 0 ? { maximum: limit } : {}
|
|
43
|
+
},
|
|
44
|
+
{ type: "string", enum: ["max"] }
|
|
45
|
+
]
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
49
|
+
0 && (module.exports = {
|
|
50
|
+
DEFAULT_MAX_DURATION_LIMIT,
|
|
51
|
+
SKIP_MAX_DURATION_LIMIT_ENV,
|
|
52
|
+
getMaxDurationLimit,
|
|
53
|
+
getMaxDurationSchema
|
|
54
|
+
});
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type FileFsRef from './file-fs-ref';
|
|
2
2
|
/**
|
|
3
3
|
* Check if a Node.js/TypeScript file is a valid API entrypoint by detecting
|
|
4
|
-
*
|
|
5
|
-
* - Default
|
|
6
|
-
* - Named HTTP method exports (GET
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
4
|
+
* the handler export shapes supported by `@vercel/node`:
|
|
5
|
+
* - Default export (`(req, res)` handler, Web handler, or object of handlers)
|
|
6
|
+
* - Named HTTP method exports (`GET`, `POST`, …) or a `fetch` export
|
|
7
|
+
* - `module.exports = <fn>`
|
|
8
|
+
* - A server that calls `.listen()`
|
|
9
9
|
*
|
|
10
|
-
* Returns `true` on error as a safe default — if we can't read
|
|
11
|
-
* let the existing build pipeline handle it
|
|
10
|
+
* Returns `true` on error as a safe default — if we can't read or confidently
|
|
11
|
+
* analyze the file, let the existing build pipeline handle it rather than risk
|
|
12
|
+
* dropping a real Vercel Function.
|
|
12
13
|
*/
|
|
13
14
|
export declare function isNodeEntrypoint(file: FileFsRef | {
|
|
14
15
|
fsPath?: string;
|
package/dist/node-entrypoint.js
CHANGED
|
@@ -32,26 +32,48 @@ __export(node_entrypoint_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(node_entrypoint_exports);
|
|
34
34
|
var import_fs = __toESM(require("fs"));
|
|
35
|
+
var import_es_module_lexer = require("es-module-lexer");
|
|
36
|
+
var import_cjs_module_lexer = require("cjs-module-lexer");
|
|
35
37
|
var import_debug = __toESM(require("./debug"));
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
var import_strip_comments_and_literals = require("./strip-comments-and-literals");
|
|
39
|
+
const HANDLER_EXPORTS = /* @__PURE__ */ new Set([
|
|
40
|
+
"GET",
|
|
41
|
+
"HEAD",
|
|
42
|
+
"OPTIONS",
|
|
43
|
+
"POST",
|
|
44
|
+
"PUT",
|
|
45
|
+
"DELETE",
|
|
46
|
+
"PATCH",
|
|
47
|
+
"fetch",
|
|
48
|
+
"default"
|
|
49
|
+
]);
|
|
50
|
+
const EXTRA_HANDLER_PATTERNS = [
|
|
51
|
+
/\bmodule\.exports\s*=(?!=)/,
|
|
52
|
+
/\.listen\s*\(/,
|
|
53
|
+
/\bexport\s*=(?!=)/,
|
|
54
|
+
/\bexport\s*\*\s*from\b/
|
|
52
55
|
];
|
|
53
|
-
function
|
|
54
|
-
|
|
56
|
+
async function getHandlerExportNames(content) {
|
|
57
|
+
const names = /* @__PURE__ */ new Set();
|
|
58
|
+
let esmUnparsed = false;
|
|
59
|
+
await import_es_module_lexer.init;
|
|
60
|
+
try {
|
|
61
|
+
const [, exports] = (0, import_es_module_lexer.parse)(content);
|
|
62
|
+
for (const { n } of exports) {
|
|
63
|
+
if (n)
|
|
64
|
+
names.add(n);
|
|
65
|
+
}
|
|
66
|
+
} catch {
|
|
67
|
+
esmUnparsed = true;
|
|
68
|
+
}
|
|
69
|
+
await (0, import_cjs_module_lexer.init)();
|
|
70
|
+
try {
|
|
71
|
+
for (const name of (0, import_cjs_module_lexer.parse)(content).exports) {
|
|
72
|
+
names.add(name);
|
|
73
|
+
}
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
return { names, esmUnparsed };
|
|
55
77
|
}
|
|
56
78
|
async function isNodeEntrypoint(file) {
|
|
57
79
|
try {
|
|
@@ -61,8 +83,15 @@ async function isNodeEntrypoint(file) {
|
|
|
61
83
|
const content = await import_fs.default.promises.readFile(fsPath, "utf-8");
|
|
62
84
|
if (!content.trim())
|
|
63
85
|
return false;
|
|
64
|
-
const
|
|
65
|
-
|
|
86
|
+
const { names, esmUnparsed } = await getHandlerExportNames(content);
|
|
87
|
+
for (const name of names) {
|
|
88
|
+
if (HANDLER_EXPORTS.has(name))
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
if (esmUnparsed)
|
|
92
|
+
return true;
|
|
93
|
+
const code = (0, import_strip_comments_and_literals.stripCommentsAndLiterals)(content);
|
|
94
|
+
return EXTRA_HANDLER_PATTERNS.some((pattern) => pattern.test(code));
|
|
66
95
|
} catch (err) {
|
|
67
96
|
(0, import_debug.default)(`Failed to check Node.js entrypoint: ${err}`);
|
|
68
97
|
return true;
|
package/dist/schemas.d.ts
CHANGED
|
@@ -22,15 +22,13 @@ export declare const functionsSchema: {
|
|
|
22
22
|
};
|
|
23
23
|
maxDuration: {
|
|
24
24
|
oneOf: ({
|
|
25
|
+
maximum?: number | undefined;
|
|
25
26
|
type: string;
|
|
26
27
|
minimum: number;
|
|
27
|
-
maximum: number;
|
|
28
28
|
enum?: undefined;
|
|
29
29
|
} | {
|
|
30
30
|
type: string;
|
|
31
31
|
enum: string[];
|
|
32
|
-
minimum?: undefined;
|
|
33
|
-
maximum?: undefined;
|
|
34
32
|
})[];
|
|
35
33
|
};
|
|
36
34
|
regions: {
|
package/dist/schemas.js
CHANGED
|
@@ -23,6 +23,7 @@ __export(schemas_exports, {
|
|
|
23
23
|
packageManifestSchema: () => packageManifestSchema
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(schemas_exports);
|
|
26
|
+
var import_max_duration = require("./max-duration");
|
|
26
27
|
const triggerEventSchemaV1 = {
|
|
27
28
|
type: "object",
|
|
28
29
|
properties: {
|
|
@@ -114,12 +115,7 @@ const functionsSchema = {
|
|
|
114
115
|
minimum: 128,
|
|
115
116
|
maximum: 10240
|
|
116
117
|
},
|
|
117
|
-
maxDuration:
|
|
118
|
-
oneOf: [
|
|
119
|
-
{ type: "integer", minimum: 1, maximum: 900 },
|
|
120
|
-
{ type: "string", enum: ["max"] }
|
|
121
|
-
]
|
|
122
|
-
},
|
|
118
|
+
maxDuration: (0, import_max_duration.getMaxDurationSchema)(),
|
|
123
119
|
regions: {
|
|
124
120
|
type: "array",
|
|
125
121
|
items: {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replace comments and string / template literals with single spaces, leaving
|
|
3
|
+
* only the code structure behind.
|
|
4
|
+
*
|
|
5
|
+
* Comments and literals are matched by one alternation. Because a literal is
|
|
6
|
+
* matched as a single token, the engine consumes it whole before it can look
|
|
7
|
+
* inside — so a comment-like sequence that appears inside a string (for
|
|
8
|
+
* example an `Accept` header value containing a wildcard media range, or a URL
|
|
9
|
+
* with `//`) is never treated as the start of a comment. Literals are blanked
|
|
10
|
+
* rather than preserved so their contents cannot be misread as code either.
|
|
11
|
+
*
|
|
12
|
+
* This is intentionally not aware of regex literals: an unescaped `/` cannot
|
|
13
|
+
* appear inside a regex body, so a comment-opening slash-star sequence cannot
|
|
14
|
+
* occur there, and callers only test the result for plain code-level tokens.
|
|
15
|
+
*/
|
|
16
|
+
export declare function stripCommentsAndLiterals(content: string): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
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 strip_comments_and_literals_exports = {};
|
|
20
|
+
__export(strip_comments_and_literals_exports, {
|
|
21
|
+
stripCommentsAndLiterals: () => stripCommentsAndLiterals
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(strip_comments_and_literals_exports);
|
|
24
|
+
const BLOCK_COMMENT = /\/\*[\s\S]*?(?:\*\/|$)/;
|
|
25
|
+
const LINE_COMMENT = /\/\/[^\n]*/;
|
|
26
|
+
const DOUBLE_QUOTED = /"(?:\\[\s\S]|[^"\\])*"?/;
|
|
27
|
+
const SINGLE_QUOTED = /'(?:\\[\s\S]|[^'\\])*'?/;
|
|
28
|
+
const TEMPLATE_LITERAL = /`(?:\\[\s\S]|[^`\\])*`?/;
|
|
29
|
+
const COMMENT_OR_LITERAL = new RegExp(
|
|
30
|
+
[BLOCK_COMMENT, LINE_COMMENT, DOUBLE_QUOTED, SINGLE_QUOTED, TEMPLATE_LITERAL].map((pattern) => pattern.source).join("|"),
|
|
31
|
+
"g"
|
|
32
|
+
);
|
|
33
|
+
function stripCommentsAndLiterals(content) {
|
|
34
|
+
return content.replace(COMMENT_OR_LITERAL, " ");
|
|
35
|
+
}
|
|
36
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
37
|
+
0 && (module.exports = {
|
|
38
|
+
stripCommentsAndLiterals
|
|
39
|
+
});
|