@vercel/build-utils
Advanced tools
+6
-0
| # @vercel/build-utils | ||
| ## 13.13.0 | ||
| ### Minor Changes | ||
| - Extend `finalizeLambda` with pluggable ZIP strategy (`createZip`), pre-digest validation hook (`validateZip`), and optional trace tags. Widen `getLambdaEnvironment` buffer param to `{ byteLength: number }`. ([#15856](https://github.com/vercel/vercel/pull/15856)) | ||
| ## 13.12.2 | ||
@@ -4,0 +10,0 @@ |
@@ -10,3 +10,22 @@ /// <reference types="node" /> | ||
| */ | ||
| export type TraceFn = <T>(name: string, fn: () => Promise<T>) => Promise<T>; | ||
| export type TraceFn = <T>(name: string, fn: () => Promise<T>, tags?: Record<string, string>) => Promise<T>; | ||
| /** | ||
| * Result of a custom ZIP creation strategy. | ||
| */ | ||
| export interface CreateZipResult { | ||
| /** The zip as a Buffer (in-memory), or null for disk-based paths. */ | ||
| buffer: Buffer | null; | ||
| /** Path to the zip file on disk, or undefined for in-memory. */ | ||
| zipPath?: string; | ||
| /** SHA-256 hex digest of the zip contents. */ | ||
| digest: string; | ||
| /** Compressed size in bytes. */ | ||
| size: number; | ||
| } | ||
| /** | ||
| * Custom ZIP creation strategy. When provided, replaces the default | ||
| * in-memory `lambda.createZip()` + `sha256()` path. This allows callers | ||
| * to stream large zips to disk instead. | ||
| */ | ||
| export type CreateZipFn = (lambda: Lambda | NodejsLambda) => Promise<CreateZipResult>; | ||
| export interface FinalizeLambdaParams { | ||
@@ -22,6 +41,24 @@ lambda: Lambda | NodejsLambda; | ||
| trace?: TraceFn; | ||
| /** Custom ZIP creation strategy. Defaults to in-memory lambda.createZip(). */ | ||
| createZip?: CreateZipFn; | ||
| /** | ||
| * Called after ZIP creation but before digest/environment/streaming. | ||
| * Throw to abort (e.g. size validation). For the default in-memory path, | ||
| * this runs before sha256. | ||
| */ | ||
| validateZip?: (zip: { | ||
| buffer: Buffer | null; | ||
| zipPath?: string; | ||
| size: number; | ||
| }) => void; | ||
| } | ||
| export interface FinalizeLambdaResult { | ||
| buffer: Buffer; | ||
| /** The zip as a Buffer, or null when a custom createZip returns a disk path. */ | ||
| buffer: Buffer | null; | ||
| /** Path to zip on disk (set by custom createZip), undefined for in-memory. */ | ||
| zipPath?: string; | ||
| /** SHA-256 hex digest. */ | ||
| digest: string; | ||
| /** Compressed size in bytes. */ | ||
| size: number; | ||
| uncompressedBytes: number; | ||
@@ -37,6 +74,7 @@ /** Non-fatal streaming detection error, if any. Caller decides how to log. */ | ||
| * 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 | ||
| * 3. Creates the ZIP (in-memory or via custom strategy) | ||
| * 4. Runs optional validateZip hook (e.g. size check) | ||
| * 5. Computes SHA-256 digest (default path only; custom path provides its own) | ||
| * 6. Merges environment variables (bytecode caching, helpers, etc.) | ||
| * 7. Detects streaming support | ||
| * | ||
@@ -43,0 +81,0 @@ * Note: This function mutates the `lambda` (files, environment, |
@@ -38,3 +38,5 @@ "use strict"; | ||
| enableUncompressedLambdaSizeCheck, | ||
| trace = defaultTrace | ||
| trace = defaultTrace, | ||
| createZip: createZipOverride, | ||
| validateZip | ||
| } = params; | ||
@@ -62,7 +64,39 @@ const encryptedEnv = (0, import_get_encrypted_env_file.getEncryptedEnv)( | ||
| } | ||
| const buffer = lambda.zipBuffer || await trace("createZip", () => lambda.createZip()); | ||
| const digest = (0, import_stream_to_digest_async.sha256)(buffer); | ||
| const zipTags = { | ||
| fileCount: String(Object.keys(lambda.files ?? {}).length), | ||
| uncompressedBytes: String(uncompressedBytes) | ||
| }; | ||
| let zipResult; | ||
| if (createZipOverride) { | ||
| zipResult = await trace( | ||
| "createZip", | ||
| () => createZipOverride(lambda), | ||
| zipTags | ||
| ); | ||
| } else { | ||
| const buffer = lambda.zipBuffer || await trace("createZip", () => lambda.createZip(), zipTags); | ||
| zipResult = { | ||
| buffer, | ||
| digest: "", | ||
| // computed in step 5 | ||
| size: buffer.byteLength | ||
| }; | ||
| } | ||
| if (validateZip) { | ||
| validateZip({ | ||
| buffer: zipResult.buffer, | ||
| zipPath: zipResult.zipPath, | ||
| size: zipResult.size | ||
| }); | ||
| } | ||
| if (!createZipOverride && zipResult.buffer) { | ||
| zipResult.digest = (0, import_stream_to_digest_async.sha256)(zipResult.buffer); | ||
| } | ||
| lambda.environment = { | ||
| ...lambda.environment, | ||
| ...(0, import_get_lambda_environment.getLambdaEnvironment)(lambda, buffer, bytecodeCachingOptions) | ||
| ...(0, import_get_lambda_environment.getLambdaEnvironment)( | ||
| lambda, | ||
| zipResult.buffer ?? { byteLength: zipResult.size }, | ||
| bytecodeCachingOptions | ||
| ) | ||
| }; | ||
@@ -75,4 +109,6 @@ const streamingResult = await (0, import_get_lambda_supports_streaming.getLambdaSupportsStreaming)( | ||
| return { | ||
| buffer, | ||
| digest, | ||
| buffer: zipResult.buffer, | ||
| zipPath: zipResult.zipPath, | ||
| digest: zipResult.digest, | ||
| size: zipResult.size, | ||
| uncompressedBytes, | ||
@@ -79,0 +115,0 @@ streamingError: streamingResult.error |
+1
-1
@@ -50,3 +50,3 @@ import FileBlob from './file-blob'; | ||
| export { collectUncompressedSize } from './collect-uncompressed-size'; | ||
| export { finalizeLambda, type FinalizeLambdaParams, type FinalizeLambdaResult, type TraceFn, } from './finalize-lambda'; | ||
| export { finalizeLambda, type CreateZipResult, type CreateZipFn, 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'; |
@@ -1,2 +0,1 @@ | ||
| /// <reference types="node" /> | ||
| import { type BytecodeCachingOptions } from './get-lambda-preload-scripts'; | ||
@@ -17,3 +16,5 @@ interface LambdaLike { | ||
| */ | ||
| export declare function getLambdaEnvironment(lambda: LambdaLike, buffer: Buffer, options: BytecodeCachingOptions): Record<string, string>; | ||
| export declare function getLambdaEnvironment(lambda: LambdaLike, buffer: { | ||
| byteLength: number; | ||
| }, options: BytecodeCachingOptions): Record<string, string>; | ||
| export {}; |
@@ -1,2 +0,1 @@ | ||
| /// <reference types="node" /> | ||
| export interface BytecodeCachingOptions { | ||
@@ -20,3 +19,5 @@ vercelEnv: string | undefined; | ||
| */ | ||
| export declare function getLambdaPreloadScripts(lambda: LambdaLike, buffer: Buffer, options: BytecodeCachingOptions): string[]; | ||
| export declare function getLambdaPreloadScripts(lambda: LambdaLike, buffer: { | ||
| byteLength: number; | ||
| }, options: BytecodeCachingOptions): string[]; | ||
| export {}; |
+1
-1
| { | ||
| "name": "@vercel/build-utils", | ||
| "version": "13.12.2", | ||
| "version": "13.13.0", | ||
| "license": "Apache-2.0", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
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
1499963
0.24%33590
0.33%