@vercel/build-utils
Advanced tools
| import type { Files } from './types'; | ||
| /** | ||
| * Collects the total uncompressed size of a set of Lambda files. | ||
| * Handles both FileBlob (in-memory) and FileFsRef (on-disk) file types. | ||
| */ | ||
| export declare const collectUncompressedSize: (files: Files, ignoreFn?: ((fileKey: string) => boolean) | undefined) => Promise<number>; |
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var collect_uncompressed_size_exports = {}; | ||
| __export(collect_uncompressed_size_exports, { | ||
| collectUncompressedSize: () => collectUncompressedSize | ||
| }); | ||
| module.exports = __toCommonJS(collect_uncompressed_size_exports); | ||
| var import_promises = require("fs/promises"); | ||
| const fileSizeCache = /* @__PURE__ */ new Map(); | ||
| const getFileSize = (path) => { | ||
| if (!path) | ||
| return Promise.resolve(0); | ||
| const cached = fileSizeCache.get(path); | ||
| if (cached) { | ||
| return cached; | ||
| } | ||
| const promise = (0, import_promises.lstat)(path).then((stats) => stats.size); | ||
| fileSizeCache.set(path, promise); | ||
| return promise; | ||
| }; | ||
| const collectUncompressedSize = async (files, ignoreFn) => { | ||
| let size = 0; | ||
| await Promise.all( | ||
| Object.keys(files).map(async (fileKey) => { | ||
| if (ignoreFn?.(fileKey)) { | ||
| return; | ||
| } | ||
| const file = files[fileKey]; | ||
| if (file.type === "FileBlob") { | ||
| size += file.data.length; | ||
| } else if (file.type === "FileFsRef") { | ||
| const fsRef = file; | ||
| const curSize = fsRef.size ?? await getFileSize(fsRef.fsPath); | ||
| size += curSize; | ||
| } | ||
| }) | ||
| ); | ||
| return size; | ||
| }; | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| collectUncompressedSize | ||
| }); |
| /// <reference types="node" /> | ||
| import type { Lambda } from './lambda'; | ||
| import type { NodejsLambda } from './nodejs-lambda'; | ||
| import type { BytecodeCachingOptions } from './process-serverless/get-lambda-preload-scripts'; | ||
| import type { SupportsStreamingResult } from './process-serverless/get-lambda-supports-streaming'; | ||
| /** | ||
| * Optional wrapper around async work, allowing callers to inject tracing | ||
| * (e.g. dd-trace spans) without coupling the shared code to a tracer. | ||
| */ | ||
| export type TraceFn = <T>(name: string, fn: () => Promise<T>) => Promise<T>; | ||
| export interface FinalizeLambdaParams { | ||
| lambda: Lambda | NodejsLambda; | ||
| encryptedEnvFilename?: string; | ||
| encryptedEnvContent?: string; | ||
| bytecodeCachingOptions: BytecodeCachingOptions; | ||
| forceStreamingRuntime: boolean; | ||
| /** When true, collect the uncompressed size of lambda files before zipping. */ | ||
| enableUncompressedLambdaSizeCheck?: boolean; | ||
| /** Optional tracing wrapper for `collectUncompressedSize` and `createZip`. */ | ||
| trace?: TraceFn; | ||
| } | ||
| export interface FinalizeLambdaResult { | ||
| buffer: Buffer; | ||
| digest: string; | ||
| uncompressedBytes: number; | ||
| /** Non-fatal streaming detection error, if any. Caller decides how to log. */ | ||
| streamingError?: SupportsStreamingResult['error']; | ||
| } | ||
| /** | ||
| * Core Lambda finalization logic shared between BYOF and build-container. | ||
| * | ||
| * This function: | ||
| * 1. Injects encrypted env file into lambda.files when provided | ||
| * 2. Collects uncompressed size when enabled | ||
| * 3. Creates the ZIP buffer | ||
| * 4. Computes SHA-256 digest | ||
| * 5. Merges environment variables (bytecode caching, helpers, etc.) | ||
| * 6. Detects streaming support | ||
| * | ||
| * Note: This function mutates the `lambda` (files, environment, | ||
| * supportsResponseStreaming). | ||
| */ | ||
| export declare function finalizeLambda(params: FinalizeLambdaParams): Promise<FinalizeLambdaResult>; |
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var finalize_lambda_exports = {}; | ||
| __export(finalize_lambda_exports, { | ||
| finalizeLambda: () => finalizeLambda | ||
| }); | ||
| module.exports = __toCommonJS(finalize_lambda_exports); | ||
| var import_get_encrypted_env_file = require("./process-serverless/get-encrypted-env-file"); | ||
| var import_get_lambda_environment = require("./process-serverless/get-lambda-environment"); | ||
| var import_get_lambda_supports_streaming = require("./process-serverless/get-lambda-supports-streaming"); | ||
| var import_stream_to_digest_async = require("./fs/stream-to-digest-async"); | ||
| var import_collect_uncompressed_size = require("./collect-uncompressed-size"); | ||
| const defaultTrace = (_name, fn) => fn(); | ||
| async function finalizeLambda(params) { | ||
| const { | ||
| lambda, | ||
| encryptedEnvFilename, | ||
| encryptedEnvContent, | ||
| bytecodeCachingOptions, | ||
| forceStreamingRuntime, | ||
| enableUncompressedLambdaSizeCheck, | ||
| trace = defaultTrace | ||
| } = params; | ||
| const encryptedEnv = (0, import_get_encrypted_env_file.getEncryptedEnv)( | ||
| encryptedEnvFilename, | ||
| encryptedEnvContent | ||
| ); | ||
| if (encryptedEnv) { | ||
| const [envFilename, envFile] = encryptedEnv; | ||
| lambda.zipBuffer = void 0; | ||
| lambda.files = { | ||
| ...lambda.files, | ||
| [envFilename]: envFile | ||
| }; | ||
| } | ||
| let uncompressedBytes = 0; | ||
| if (enableUncompressedLambdaSizeCheck) { | ||
| if (lambda.files) { | ||
| uncompressedBytes = await trace( | ||
| "collectUncompressedSize", | ||
| () => (0, import_collect_uncompressed_size.collectUncompressedSize)(lambda.files ?? {}) | ||
| ); | ||
| } | ||
| } | ||
| const buffer = lambda.zipBuffer || await trace("createZip", () => lambda.createZip()); | ||
| const digest = (0, import_stream_to_digest_async.sha256)(buffer); | ||
| lambda.environment = { | ||
| ...lambda.environment, | ||
| ...(0, import_get_lambda_environment.getLambdaEnvironment)(lambda, buffer, bytecodeCachingOptions) | ||
| }; | ||
| const streamingResult = await (0, import_get_lambda_supports_streaming.getLambdaSupportsStreaming)( | ||
| lambda, | ||
| forceStreamingRuntime | ||
| ); | ||
| lambda.supportsResponseStreaming = streamingResult.supportsStreaming; | ||
| return { | ||
| buffer, | ||
| digest, | ||
| uncompressedBytes, | ||
| streamingError: streamingResult.error | ||
| }; | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| finalizeLambda | ||
| }); |
| /// <reference types="node" /> | ||
| import { NowBuildError } from './errors'; | ||
| /** | ||
| * Max compressed ZIP size (300 MB). | ||
| * Limit is 250 MB uncompressed; we set 300 MB compressed as a safety | ||
| * buffer. Python is exempt because AI workloads commonly exceed this. | ||
| */ | ||
| export declare const MAX_LAMBDA_SIZE: number; | ||
| /** | ||
| * Max uncompressed size (250 MB). | ||
| */ | ||
| export declare const MAX_LAMBDA_UNCOMPRESSED_SIZE: number; | ||
| /** | ||
| * Error thrown when a Lambda's compressed ZIP exceeds the allowed size. | ||
| */ | ||
| export declare class FunctionSizeError extends NowBuildError { | ||
| size: number; | ||
| maxSize: number; | ||
| constructor(outputPath: string, size: number); | ||
| } | ||
| /** | ||
| * Validates the compressed size of a Lambda function. | ||
| * Python runtimes are exempt because AI workloads commonly exceed 300 MB. | ||
| */ | ||
| export declare function validateLambdaSize(outputPath: string, runtime: string, size: number): void; | ||
| /** | ||
| * Validates the uncompressed size of a Lambda function. | ||
| */ | ||
| export declare function validateUncompressedLambdaSize(outputPath: string, uncompressedBytes: number): void; | ||
| /** | ||
| * Runtimes that support env wrapper. | ||
| */ | ||
| export declare const ENV_WRAPPER_SUPPORTED_FAMILIES: string[]; | ||
| interface LambdaLikeForEnvWrapper { | ||
| createZip?: () => Promise<Buffer>; | ||
| runtime: string; | ||
| supportsWrapper?: boolean; | ||
| } | ||
| /** | ||
| * When the function requires a file for the encrypted environment variables, | ||
| * it needs to support wrappers. Also, the function must have a `createZip` | ||
| * function since we need to "re-compress" to include the file in the final | ||
| * lambda. | ||
| */ | ||
| export declare function validateEnvWrapperSupport(encryptedEnvFilename: string | undefined, encryptedEnvContent: string | undefined, lambda: LambdaLikeForEnvWrapper): void; | ||
| export {}; |
| "use strict"; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var validate_lambda_size_exports = {}; | ||
| __export(validate_lambda_size_exports, { | ||
| ENV_WRAPPER_SUPPORTED_FAMILIES: () => ENV_WRAPPER_SUPPORTED_FAMILIES, | ||
| FunctionSizeError: () => FunctionSizeError, | ||
| MAX_LAMBDA_SIZE: () => MAX_LAMBDA_SIZE, | ||
| MAX_LAMBDA_UNCOMPRESSED_SIZE: () => MAX_LAMBDA_UNCOMPRESSED_SIZE, | ||
| validateEnvWrapperSupport: () => validateEnvWrapperSupport, | ||
| validateLambdaSize: () => validateLambdaSize, | ||
| validateUncompressedLambdaSize: () => validateUncompressedLambdaSize | ||
| }); | ||
| module.exports = __toCommonJS(validate_lambda_size_exports); | ||
| var import_errors = require("./errors"); | ||
| var import_bytes = __toESM(require("bytes")); | ||
| const MAX_LAMBDA_SIZE = (0, import_bytes.default)("300mb"); | ||
| const MAX_LAMBDA_UNCOMPRESSED_SIZE = 250 * 1024 * 1024; | ||
| class FunctionSizeError extends import_errors.NowBuildError { | ||
| constructor(outputPath, size) { | ||
| super({ | ||
| code: "NOW_SANDBOX_WORKER_MAX_LAMBDA_SIZE", | ||
| message: `The Vercel Function "${outputPath}" is ${(0, import_bytes.default)( | ||
| size | ||
| ).toLowerCase()} which exceeds the maximum size limit of ${(0, import_bytes.default)( | ||
| MAX_LAMBDA_SIZE | ||
| ).toLowerCase()}.`, | ||
| link: "https://vercel.link/serverless-function-size", | ||
| action: "Learn More" | ||
| }); | ||
| this.size = size; | ||
| this.maxSize = MAX_LAMBDA_SIZE; | ||
| } | ||
| } | ||
| function validateLambdaSize(outputPath, runtime, size) { | ||
| if (runtime.startsWith("python")) { | ||
| return; | ||
| } | ||
| if (size > MAX_LAMBDA_SIZE) { | ||
| throw new FunctionSizeError(outputPath, size); | ||
| } | ||
| } | ||
| function validateUncompressedLambdaSize(outputPath, uncompressedBytes) { | ||
| if (uncompressedBytes >= MAX_LAMBDA_UNCOMPRESSED_SIZE) { | ||
| throw new import_errors.NowBuildError({ | ||
| code: "NOW_SANDBOX_WORKER_MAX_UNCOMPRESSED_LAMBDA_SIZE", | ||
| message: `The Vercel Function "${outputPath}" is ${(0, import_bytes.default)( | ||
| uncompressedBytes | ||
| ).toLowerCase()} uncompressed which exceeds the maximum uncompressed size limit of ${(0, import_bytes.default)( | ||
| MAX_LAMBDA_UNCOMPRESSED_SIZE | ||
| ).toLowerCase()}.`, | ||
| link: "https://vercel.link/serverless-function-size", | ||
| action: "Learn More" | ||
| }); | ||
| } | ||
| } | ||
| const ENV_WRAPPER_SUPPORTED_FAMILIES = [ | ||
| "nodejs", | ||
| "python", | ||
| "ruby", | ||
| "java", | ||
| "dotnetcore", | ||
| "bun", | ||
| "executable" | ||
| ]; | ||
| function validateEnvWrapperSupport(encryptedEnvFilename, encryptedEnvContent, lambda) { | ||
| if (!encryptedEnvFilename || !encryptedEnvContent) { | ||
| return; | ||
| } | ||
| if (!lambda.supportsWrapper && !ENV_WRAPPER_SUPPORTED_FAMILIES.some( | ||
| (family) => lambda.runtime.startsWith(family) | ||
| )) { | ||
| throw new Error( | ||
| `Serverless Function runtime ${lambda.runtime} does not support more than 4KB for environment variables` | ||
| ); | ||
| } | ||
| if (typeof lambda.createZip !== "function") { | ||
| throw new Error( | ||
| `Serverless Function with runtime ${lambda.runtime} has no createZip function` | ||
| ); | ||
| } | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| ENV_WRAPPER_SUPPORTED_FAMILIES, | ||
| FunctionSizeError, | ||
| MAX_LAMBDA_SIZE, | ||
| MAX_LAMBDA_UNCOMPRESSED_SIZE, | ||
| validateEnvWrapperSupport, | ||
| validateLambdaSize, | ||
| validateUncompressedLambdaSize | ||
| }); |
+6
-0
| # @vercel/build-utils | ||
| ## 13.12.2 | ||
| ### Patch Changes | ||
| - Extract finalize/validate function utils for build-utils ([#15776](https://github.com/vercel/vercel/pull/15776)) | ||
| ## 13.12.1 | ||
@@ -4,0 +10,0 @@ |
+3
-0
@@ -49,1 +49,4 @@ import FileBlob from './file-blob'; | ||
| export { streamWithExtendedPayload, type ExtendedBodyData, } from './collect-build-result/stream-with-extended-payload'; | ||
| export { collectUncompressedSize } from './collect-uncompressed-size'; | ||
| export { finalizeLambda, type FinalizeLambdaParams, type FinalizeLambdaResult, type TraceFn, } from './finalize-lambda'; | ||
| export { validateLambdaSize, validateUncompressedLambdaSize, FunctionSizeError, MAX_LAMBDA_SIZE, MAX_LAMBDA_UNCOMPRESSED_SIZE, validateEnvWrapperSupport, ENV_WRAPPER_SUPPORTED_FAMILIES, } from './validate-lambda-size'; |
+3
-1
| { | ||
| "name": "@vercel/build-utils", | ||
| "version": "13.12.1", | ||
| "version": "13.12.2", | ||
| "license": "Apache-2.0", | ||
@@ -19,4 +19,6 @@ "main": "./dist/index.js", | ||
| "devDependencies": { | ||
| "bytes": "3.1.2", | ||
| "smol-toml": "1.5.2", | ||
| "@types/async-retry": "^1.2.1", | ||
| "@types/bytes": "3.1.1", | ||
| "@types/cross-spawn": "6.0.0", | ||
@@ -23,0 +25,0 @@ "@types/end-of-stream": "^1.4.0", |
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 11 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 3 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 11 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 3 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1496370
1.52%116
5.45%33478
1.89%40
5.26%46
2.22%