@vercel/build-utils 13.12.1 → 13.12.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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @vercel/build-utils
2
2
 
3
+ ## 13.12.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Extract finalize/validate function utils for build-utils ([#15776](https://github.com/vercel/vercel/pull/15776))
8
+
3
9
  ## 13.12.1
4
10
 
5
11
  ### Patch Changes
@@ -0,0 +1,6 @@
1
+ import type { Files } from './types';
2
+ /**
3
+ * Collects the total uncompressed size of a set of Lambda files.
4
+ * Handles both FileBlob (in-memory) and FileFsRef (on-disk) file types.
5
+ */
6
+ export declare const collectUncompressedSize: (files: Files, ignoreFn?: ((fileKey: string) => boolean) | undefined) => Promise<number>;
@@ -0,0 +1,59 @@
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 collect_uncompressed_size_exports = {};
20
+ __export(collect_uncompressed_size_exports, {
21
+ collectUncompressedSize: () => collectUncompressedSize
22
+ });
23
+ module.exports = __toCommonJS(collect_uncompressed_size_exports);
24
+ var import_promises = require("fs/promises");
25
+ const fileSizeCache = /* @__PURE__ */ new Map();
26
+ const getFileSize = (path) => {
27
+ if (!path)
28
+ return Promise.resolve(0);
29
+ const cached = fileSizeCache.get(path);
30
+ if (cached) {
31
+ return cached;
32
+ }
33
+ const promise = (0, import_promises.lstat)(path).then((stats) => stats.size);
34
+ fileSizeCache.set(path, promise);
35
+ return promise;
36
+ };
37
+ const collectUncompressedSize = async (files, ignoreFn) => {
38
+ let size = 0;
39
+ await Promise.all(
40
+ Object.keys(files).map(async (fileKey) => {
41
+ if (ignoreFn?.(fileKey)) {
42
+ return;
43
+ }
44
+ const file = files[fileKey];
45
+ if (file.type === "FileBlob") {
46
+ size += file.data.length;
47
+ } else if (file.type === "FileFsRef") {
48
+ const fsRef = file;
49
+ const curSize = fsRef.size ?? await getFileSize(fsRef.fsPath);
50
+ size += curSize;
51
+ }
52
+ })
53
+ );
54
+ return size;
55
+ };
56
+ // Annotate the CommonJS export names for ESM import in node:
57
+ 0 && (module.exports = {
58
+ collectUncompressedSize
59
+ });
@@ -0,0 +1,43 @@
1
+ /// <reference types="node" />
2
+ import type { Lambda } from './lambda';
3
+ import type { NodejsLambda } from './nodejs-lambda';
4
+ import type { BytecodeCachingOptions } from './process-serverless/get-lambda-preload-scripts';
5
+ import type { SupportsStreamingResult } from './process-serverless/get-lambda-supports-streaming';
6
+ /**
7
+ * Optional wrapper around async work, allowing callers to inject tracing
8
+ * (e.g. dd-trace spans) without coupling the shared code to a tracer.
9
+ */
10
+ export type TraceFn = <T>(name: string, fn: () => Promise<T>) => Promise<T>;
11
+ export interface FinalizeLambdaParams {
12
+ lambda: Lambda | NodejsLambda;
13
+ encryptedEnvFilename?: string;
14
+ encryptedEnvContent?: string;
15
+ bytecodeCachingOptions: BytecodeCachingOptions;
16
+ forceStreamingRuntime: boolean;
17
+ /** When true, collect the uncompressed size of lambda files before zipping. */
18
+ enableUncompressedLambdaSizeCheck?: boolean;
19
+ /** Optional tracing wrapper for `collectUncompressedSize` and `createZip`. */
20
+ trace?: TraceFn;
21
+ }
22
+ export interface FinalizeLambdaResult {
23
+ buffer: Buffer;
24
+ digest: string;
25
+ uncompressedBytes: number;
26
+ /** Non-fatal streaming detection error, if any. Caller decides how to log. */
27
+ streamingError?: SupportsStreamingResult['error'];
28
+ }
29
+ /**
30
+ * Core Lambda finalization logic shared between BYOF and build-container.
31
+ *
32
+ * This function:
33
+ * 1. Injects encrypted env file into lambda.files when provided
34
+ * 2. Collects uncompressed size when enabled
35
+ * 3. Creates the ZIP buffer
36
+ * 4. Computes SHA-256 digest
37
+ * 5. Merges environment variables (bytecode caching, helpers, etc.)
38
+ * 6. Detects streaming support
39
+ *
40
+ * Note: This function mutates the `lambda` (files, environment,
41
+ * supportsResponseStreaming).
42
+ */
43
+ export declare function finalizeLambda(params: FinalizeLambdaParams): Promise<FinalizeLambdaResult>;
@@ -0,0 +1,82 @@
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 finalize_lambda_exports = {};
20
+ __export(finalize_lambda_exports, {
21
+ finalizeLambda: () => finalizeLambda
22
+ });
23
+ module.exports = __toCommonJS(finalize_lambda_exports);
24
+ var import_get_encrypted_env_file = require("./process-serverless/get-encrypted-env-file");
25
+ var import_get_lambda_environment = require("./process-serverless/get-lambda-environment");
26
+ var import_get_lambda_supports_streaming = require("./process-serverless/get-lambda-supports-streaming");
27
+ var import_stream_to_digest_async = require("./fs/stream-to-digest-async");
28
+ var import_collect_uncompressed_size = require("./collect-uncompressed-size");
29
+ const defaultTrace = (_name, fn) => fn();
30
+ async function finalizeLambda(params) {
31
+ const {
32
+ lambda,
33
+ encryptedEnvFilename,
34
+ encryptedEnvContent,
35
+ bytecodeCachingOptions,
36
+ forceStreamingRuntime,
37
+ enableUncompressedLambdaSizeCheck,
38
+ trace = defaultTrace
39
+ } = params;
40
+ const encryptedEnv = (0, import_get_encrypted_env_file.getEncryptedEnv)(
41
+ encryptedEnvFilename,
42
+ encryptedEnvContent
43
+ );
44
+ if (encryptedEnv) {
45
+ const [envFilename, envFile] = encryptedEnv;
46
+ lambda.zipBuffer = void 0;
47
+ lambda.files = {
48
+ ...lambda.files,
49
+ [envFilename]: envFile
50
+ };
51
+ }
52
+ let uncompressedBytes = 0;
53
+ if (enableUncompressedLambdaSizeCheck) {
54
+ if (lambda.files) {
55
+ uncompressedBytes = await trace(
56
+ "collectUncompressedSize",
57
+ () => (0, import_collect_uncompressed_size.collectUncompressedSize)(lambda.files ?? {})
58
+ );
59
+ }
60
+ }
61
+ const buffer = lambda.zipBuffer || await trace("createZip", () => lambda.createZip());
62
+ const digest = (0, import_stream_to_digest_async.sha256)(buffer);
63
+ lambda.environment = {
64
+ ...lambda.environment,
65
+ ...(0, import_get_lambda_environment.getLambdaEnvironment)(lambda, buffer, bytecodeCachingOptions)
66
+ };
67
+ const streamingResult = await (0, import_get_lambda_supports_streaming.getLambdaSupportsStreaming)(
68
+ lambda,
69
+ forceStreamingRuntime
70
+ );
71
+ lambda.supportsResponseStreaming = streamingResult.supportsStreaming;
72
+ return {
73
+ buffer,
74
+ digest,
75
+ uncompressedBytes,
76
+ streamingError: streamingResult.error
77
+ };
78
+ }
79
+ // Annotate the CommonJS export names for ESM import in node:
80
+ 0 && (module.exports = {
81
+ finalizeLambda
82
+ });
package/dist/index.d.ts CHANGED
@@ -46,3 +46,6 @@ export { getLambdaByOutputPath } from './collect-build-result/get-lambda-by-outp
46
46
  export { isRouteMiddleware } from './collect-build-result/is-route-middleware';
47
47
  export { getPrerenderChain } from './collect-build-result/get-prerender-chain';
48
48
  export { streamWithExtendedPayload, type ExtendedBodyData, } from './collect-build-result/stream-with-extended-payload';
49
+ export { collectUncompressedSize } from './collect-uncompressed-size';
50
+ export { finalizeLambda, type FinalizeLambdaParams, type FinalizeLambdaResult, type TraceFn, } from './finalize-lambda';
51
+ export { validateLambdaSize, validateUncompressedLambdaSize, FunctionSizeError, MAX_LAMBDA_SIZE, MAX_LAMBDA_UNCOMPRESSED_SIZE, validateEnvWrapperSupport, ENV_WRAPPER_SUPPORTED_FAMILIES, } from './validate-lambda-size';
package/dist/index.js CHANGED
@@ -11924,18 +11924,18 @@ var require_sync = __commonJS({
11924
11924
  if (this.follow)
11925
11925
  return this._readdir(abs, false);
11926
11926
  var entries;
11927
- var lstat2;
11927
+ var lstat3;
11928
11928
  var stat;
11929
11929
  try {
11930
- lstat2 = this.fs.lstatSync(abs);
11930
+ lstat3 = this.fs.lstatSync(abs);
11931
11931
  } catch (er) {
11932
11932
  if (er.code === "ENOENT") {
11933
11933
  return null;
11934
11934
  }
11935
11935
  }
11936
- var isSym = lstat2 && lstat2.isSymbolicLink();
11936
+ var isSym = lstat3 && lstat3.isSymbolicLink();
11937
11937
  this.symlinks[abs] = isSym;
11938
- if (!isSym && lstat2 && !lstat2.isDirectory())
11938
+ if (!isSym && lstat3 && !lstat3.isDirectory())
11939
11939
  this.cache[abs] = "FILE";
11940
11940
  else
11941
11941
  entries = this._readdir(abs, false);
@@ -12060,23 +12060,23 @@ var require_sync = __commonJS({
12060
12060
  var exists;
12061
12061
  var stat = this.statCache[abs];
12062
12062
  if (!stat) {
12063
- var lstat2;
12063
+ var lstat3;
12064
12064
  try {
12065
- lstat2 = this.fs.lstatSync(abs);
12065
+ lstat3 = this.fs.lstatSync(abs);
12066
12066
  } catch (er) {
12067
12067
  if (er && (er.code === "ENOENT" || er.code === "ENOTDIR")) {
12068
12068
  this.statCache[abs] = false;
12069
12069
  return false;
12070
12070
  }
12071
12071
  }
12072
- if (lstat2 && lstat2.isSymbolicLink()) {
12072
+ if (lstat3 && lstat3.isSymbolicLink()) {
12073
12073
  try {
12074
12074
  stat = this.fs.statSync(abs);
12075
12075
  } catch (er) {
12076
- stat = lstat2;
12076
+ stat = lstat3;
12077
12077
  }
12078
12078
  } else {
12079
- stat = lstat2;
12079
+ stat = lstat3;
12080
12080
  }
12081
12081
  }
12082
12082
  this.statCache[abs] = stat;
@@ -12493,12 +12493,12 @@ var require_glob = __commonJS({
12493
12493
  var lstatcb = inflight(lstatkey, lstatcb_);
12494
12494
  if (lstatcb)
12495
12495
  self2.fs.lstat(abs, lstatcb);
12496
- function lstatcb_(er, lstat2) {
12496
+ function lstatcb_(er, lstat3) {
12497
12497
  if (er && er.code === "ENOENT")
12498
12498
  return cb();
12499
- var isSym = lstat2 && lstat2.isSymbolicLink();
12499
+ var isSym = lstat3 && lstat3.isSymbolicLink();
12500
12500
  self2.symlinks[abs] = isSym;
12501
- if (!isSym && lstat2 && !lstat2.isDirectory()) {
12501
+ if (!isSym && lstat3 && !lstat3.isDirectory()) {
12502
12502
  self2.cache[abs] = "FILE";
12503
12503
  cb();
12504
12504
  } else
@@ -12666,16 +12666,16 @@ var require_glob = __commonJS({
12666
12666
  var statcb = inflight("stat\0" + abs, lstatcb_);
12667
12667
  if (statcb)
12668
12668
  self2.fs.lstat(abs, statcb);
12669
- function lstatcb_(er, lstat2) {
12670
- if (lstat2 && lstat2.isSymbolicLink()) {
12669
+ function lstatcb_(er, lstat3) {
12670
+ if (lstat3 && lstat3.isSymbolicLink()) {
12671
12671
  return self2.fs.stat(abs, function(er2, stat2) {
12672
12672
  if (er2)
12673
- self2._stat2(f, abs, null, lstat2, cb);
12673
+ self2._stat2(f, abs, null, lstat3, cb);
12674
12674
  else
12675
12675
  self2._stat2(f, abs, er2, stat2, cb);
12676
12676
  });
12677
12677
  } else {
12678
- self2._stat2(f, abs, er, lstat2, cb);
12678
+ self2._stat2(f, abs, er, lstat3, cb);
12679
12679
  }
12680
12680
  }
12681
12681
  };
@@ -19806,6 +19806,95 @@ var require_ignore = __commonJS({
19806
19806
  }
19807
19807
  });
19808
19808
 
19809
+ // ../../node_modules/.pnpm/bytes@3.1.2/node_modules/bytes/index.js
19810
+ var require_bytes = __commonJS({
19811
+ "../../node_modules/.pnpm/bytes@3.1.2/node_modules/bytes/index.js"(exports, module2) {
19812
+ "use strict";
19813
+ module2.exports = bytes2;
19814
+ module2.exports.format = format;
19815
+ module2.exports.parse = parse6;
19816
+ var formatThousandsRegExp = /\B(?=(\d{3})+(?!\d))/g;
19817
+ var formatDecimalsRegExp = /(?:\.0*|(\.[^0]+)0+)$/;
19818
+ var map = {
19819
+ b: 1,
19820
+ kb: 1 << 10,
19821
+ mb: 1 << 20,
19822
+ gb: 1 << 30,
19823
+ tb: Math.pow(1024, 4),
19824
+ pb: Math.pow(1024, 5)
19825
+ };
19826
+ var parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb|pb)$/i;
19827
+ function bytes2(value, options) {
19828
+ if (typeof value === "string") {
19829
+ return parse6(value);
19830
+ }
19831
+ if (typeof value === "number") {
19832
+ return format(value, options);
19833
+ }
19834
+ return null;
19835
+ }
19836
+ function format(value, options) {
19837
+ if (!Number.isFinite(value)) {
19838
+ return null;
19839
+ }
19840
+ var mag = Math.abs(value);
19841
+ var thousandsSeparator = options && options.thousandsSeparator || "";
19842
+ var unitSeparator = options && options.unitSeparator || "";
19843
+ var decimalPlaces = options && options.decimalPlaces !== void 0 ? options.decimalPlaces : 2;
19844
+ var fixedDecimals = Boolean(options && options.fixedDecimals);
19845
+ var unit = options && options.unit || "";
19846
+ if (!unit || !map[unit.toLowerCase()]) {
19847
+ if (mag >= map.pb) {
19848
+ unit = "PB";
19849
+ } else if (mag >= map.tb) {
19850
+ unit = "TB";
19851
+ } else if (mag >= map.gb) {
19852
+ unit = "GB";
19853
+ } else if (mag >= map.mb) {
19854
+ unit = "MB";
19855
+ } else if (mag >= map.kb) {
19856
+ unit = "KB";
19857
+ } else {
19858
+ unit = "B";
19859
+ }
19860
+ }
19861
+ var val = value / map[unit.toLowerCase()];
19862
+ var str = val.toFixed(decimalPlaces);
19863
+ if (!fixedDecimals) {
19864
+ str = str.replace(formatDecimalsRegExp, "$1");
19865
+ }
19866
+ if (thousandsSeparator) {
19867
+ str = str.split(".").map(function(s, i) {
19868
+ return i === 0 ? s.replace(formatThousandsRegExp, thousandsSeparator) : s;
19869
+ }).join(".");
19870
+ }
19871
+ return str + unitSeparator + unit;
19872
+ }
19873
+ function parse6(val) {
19874
+ if (typeof val === "number" && !isNaN(val)) {
19875
+ return val;
19876
+ }
19877
+ if (typeof val !== "string") {
19878
+ return null;
19879
+ }
19880
+ var results = parseRegExp.exec(val);
19881
+ var floatValue;
19882
+ var unit = "b";
19883
+ if (!results) {
19884
+ floatValue = parseInt(val, 10);
19885
+ unit = "b";
19886
+ } else {
19887
+ floatValue = parseFloat(results[1]);
19888
+ unit = results[4].toLowerCase();
19889
+ }
19890
+ if (isNaN(floatValue)) {
19891
+ return null;
19892
+ }
19893
+ return Math.floor(map[unit] * floatValue);
19894
+ }
19895
+ }
19896
+ });
19897
+
19809
19898
  // src/index.ts
19810
19899
  var src_exports = {};
19811
19900
  __export(src_exports, {
@@ -19814,11 +19903,15 @@ __export(src_exports, {
19814
19903
  BUILDER_COMPILE_STEP: () => BUILDER_COMPILE_STEP,
19815
19904
  BUILDER_INSTALLER_STEP: () => BUILDER_INSTALLER_STEP,
19816
19905
  BunVersion: () => BunVersion,
19906
+ ENV_WRAPPER_SUPPORTED_FAMILIES: () => ENV_WRAPPER_SUPPORTED_FAMILIES,
19817
19907
  EdgeFunction: () => EdgeFunction,
19818
19908
  FileBlob: () => FileBlob,
19819
19909
  FileFsRef: () => file_fs_ref_default,
19820
19910
  FileRef: () => FileRef,
19911
+ FunctionSizeError: () => FunctionSizeError,
19821
19912
  Lambda: () => Lambda,
19913
+ MAX_LAMBDA_SIZE: () => MAX_LAMBDA_SIZE,
19914
+ MAX_LAMBDA_UNCOMPRESSED_SIZE: () => MAX_LAMBDA_UNCOMPRESSED_SIZE,
19822
19915
  NODE_VERSIONS: () => NODE_VERSIONS,
19823
19916
  NodeVersion: () => NodeVersion,
19824
19917
  NodejsLambda: () => NodejsLambda,
@@ -19830,6 +19923,7 @@ __export(src_exports, {
19830
19923
  Version: () => Version,
19831
19924
  buildsSchema: () => buildsSchema,
19832
19925
  cloneEnv: () => cloneEnv,
19926
+ collectUncompressedSize: () => collectUncompressedSize,
19833
19927
  createLambda: () => createLambda,
19834
19928
  debug: () => debug,
19835
19929
  defaultCachePathGlob: () => defaultCachePathGlob,
@@ -19837,6 +19931,7 @@ __export(src_exports, {
19837
19931
  download: () => download,
19838
19932
  downloadFile: () => downloadFile,
19839
19933
  execCommand: () => execCommand,
19934
+ finalizeLambda: () => finalizeLambda,
19840
19935
  findPackageJson: () => findPackageJson,
19841
19936
  functionsSchema: () => functionsSchema,
19842
19937
  generateNodeBuilderFunctions: () => generateNodeBuilderFunctions,
@@ -19908,7 +20003,10 @@ __export(src_exports, {
19908
20003
  streamToDigestAsync: () => streamToDigestAsync,
19909
20004
  streamWithExtendedPayload: () => streamWithExtendedPayload,
19910
20005
  traverseUpDirectories: () => traverseUpDirectories,
20006
+ validateEnvWrapperSupport: () => validateEnvWrapperSupport,
20007
+ validateLambdaSize: () => validateLambdaSize,
19911
20008
  validateNpmrc: () => validateNpmrc,
20009
+ validateUncompressedLambdaSize: () => validateUncompressedLambdaSize,
19912
20010
  walkParentDirs: () => walkParentDirs
19913
20011
  });
19914
20012
  module.exports = __toCommonJS(src_exports);
@@ -24343,6 +24441,161 @@ var MultipartContentStream = class extends import_stream.Readable {
24343
24441
  _read() {
24344
24442
  }
24345
24443
  };
24444
+
24445
+ // src/collect-uncompressed-size.ts
24446
+ var import_promises2 = require("fs/promises");
24447
+ var fileSizeCache = /* @__PURE__ */ new Map();
24448
+ var getFileSize = (path7) => {
24449
+ if (!path7)
24450
+ return Promise.resolve(0);
24451
+ const cached = fileSizeCache.get(path7);
24452
+ if (cached) {
24453
+ return cached;
24454
+ }
24455
+ const promise = (0, import_promises2.lstat)(path7).then((stats) => stats.size);
24456
+ fileSizeCache.set(path7, promise);
24457
+ return promise;
24458
+ };
24459
+ var collectUncompressedSize = async (files, ignoreFn) => {
24460
+ let size = 0;
24461
+ await Promise.all(
24462
+ Object.keys(files).map(async (fileKey) => {
24463
+ if (ignoreFn?.(fileKey)) {
24464
+ return;
24465
+ }
24466
+ const file = files[fileKey];
24467
+ if (file.type === "FileBlob") {
24468
+ size += file.data.length;
24469
+ } else if (file.type === "FileFsRef") {
24470
+ const fsRef = file;
24471
+ const curSize = fsRef.size ?? await getFileSize(fsRef.fsPath);
24472
+ size += curSize;
24473
+ }
24474
+ })
24475
+ );
24476
+ return size;
24477
+ };
24478
+
24479
+ // src/finalize-lambda.ts
24480
+ var defaultTrace = (_name, fn) => fn();
24481
+ async function finalizeLambda(params) {
24482
+ const {
24483
+ lambda,
24484
+ encryptedEnvFilename,
24485
+ encryptedEnvContent,
24486
+ bytecodeCachingOptions,
24487
+ forceStreamingRuntime,
24488
+ enableUncompressedLambdaSizeCheck,
24489
+ trace = defaultTrace
24490
+ } = params;
24491
+ const encryptedEnv = getEncryptedEnv(
24492
+ encryptedEnvFilename,
24493
+ encryptedEnvContent
24494
+ );
24495
+ if (encryptedEnv) {
24496
+ const [envFilename, envFile] = encryptedEnv;
24497
+ lambda.zipBuffer = void 0;
24498
+ lambda.files = {
24499
+ ...lambda.files,
24500
+ [envFilename]: envFile
24501
+ };
24502
+ }
24503
+ let uncompressedBytes = 0;
24504
+ if (enableUncompressedLambdaSizeCheck) {
24505
+ if (lambda.files) {
24506
+ uncompressedBytes = await trace(
24507
+ "collectUncompressedSize",
24508
+ () => collectUncompressedSize(lambda.files ?? {})
24509
+ );
24510
+ }
24511
+ }
24512
+ const buffer = lambda.zipBuffer || await trace("createZip", () => lambda.createZip());
24513
+ const digest = sha256(buffer);
24514
+ lambda.environment = {
24515
+ ...lambda.environment,
24516
+ ...getLambdaEnvironment(lambda, buffer, bytecodeCachingOptions)
24517
+ };
24518
+ const streamingResult = await getLambdaSupportsStreaming(
24519
+ lambda,
24520
+ forceStreamingRuntime
24521
+ );
24522
+ lambda.supportsResponseStreaming = streamingResult.supportsStreaming;
24523
+ return {
24524
+ buffer,
24525
+ digest,
24526
+ uncompressedBytes,
24527
+ streamingError: streamingResult.error
24528
+ };
24529
+ }
24530
+
24531
+ // src/validate-lambda-size.ts
24532
+ var import_bytes = __toESM(require_bytes());
24533
+ var MAX_LAMBDA_SIZE = (0, import_bytes.default)("300mb");
24534
+ var MAX_LAMBDA_UNCOMPRESSED_SIZE = 250 * 1024 * 1024;
24535
+ var FunctionSizeError = class extends NowBuildError {
24536
+ constructor(outputPath, size) {
24537
+ super({
24538
+ code: "NOW_SANDBOX_WORKER_MAX_LAMBDA_SIZE",
24539
+ message: `The Vercel Function "${outputPath}" is ${(0, import_bytes.default)(
24540
+ size
24541
+ ).toLowerCase()} which exceeds the maximum size limit of ${(0, import_bytes.default)(
24542
+ MAX_LAMBDA_SIZE
24543
+ ).toLowerCase()}.`,
24544
+ link: "https://vercel.link/serverless-function-size",
24545
+ action: "Learn More"
24546
+ });
24547
+ this.size = size;
24548
+ this.maxSize = MAX_LAMBDA_SIZE;
24549
+ }
24550
+ };
24551
+ function validateLambdaSize(outputPath, runtime, size) {
24552
+ if (runtime.startsWith("python")) {
24553
+ return;
24554
+ }
24555
+ if (size > MAX_LAMBDA_SIZE) {
24556
+ throw new FunctionSizeError(outputPath, size);
24557
+ }
24558
+ }
24559
+ function validateUncompressedLambdaSize(outputPath, uncompressedBytes) {
24560
+ if (uncompressedBytes >= MAX_LAMBDA_UNCOMPRESSED_SIZE) {
24561
+ throw new NowBuildError({
24562
+ code: "NOW_SANDBOX_WORKER_MAX_UNCOMPRESSED_LAMBDA_SIZE",
24563
+ message: `The Vercel Function "${outputPath}" is ${(0, import_bytes.default)(
24564
+ uncompressedBytes
24565
+ ).toLowerCase()} uncompressed which exceeds the maximum uncompressed size limit of ${(0, import_bytes.default)(
24566
+ MAX_LAMBDA_UNCOMPRESSED_SIZE
24567
+ ).toLowerCase()}.`,
24568
+ link: "https://vercel.link/serverless-function-size",
24569
+ action: "Learn More"
24570
+ });
24571
+ }
24572
+ }
24573
+ var ENV_WRAPPER_SUPPORTED_FAMILIES = [
24574
+ "nodejs",
24575
+ "python",
24576
+ "ruby",
24577
+ "java",
24578
+ "dotnetcore",
24579
+ "bun",
24580
+ "executable"
24581
+ ];
24582
+ function validateEnvWrapperSupport(encryptedEnvFilename, encryptedEnvContent, lambda) {
24583
+ if (!encryptedEnvFilename || !encryptedEnvContent) {
24584
+ return;
24585
+ }
24586
+ if (!lambda.supportsWrapper && !ENV_WRAPPER_SUPPORTED_FAMILIES.some(
24587
+ (family) => lambda.runtime.startsWith(family)
24588
+ )) {
24589
+ throw new Error(
24590
+ `Serverless Function runtime ${lambda.runtime} does not support more than 4KB for environment variables`
24591
+ );
24592
+ }
24593
+ if (typeof lambda.createZip !== "function") {
24594
+ throw new Error(
24595
+ `Serverless Function with runtime ${lambda.runtime} has no createZip function`
24596
+ );
24597
+ }
24598
+ }
24346
24599
  // Annotate the CommonJS export names for ESM import in node:
24347
24600
  0 && (module.exports = {
24348
24601
  BACKEND_BUILDERS,
@@ -24350,11 +24603,15 @@ var MultipartContentStream = class extends import_stream.Readable {
24350
24603
  BUILDER_COMPILE_STEP,
24351
24604
  BUILDER_INSTALLER_STEP,
24352
24605
  BunVersion,
24606
+ ENV_WRAPPER_SUPPORTED_FAMILIES,
24353
24607
  EdgeFunction,
24354
24608
  FileBlob,
24355
24609
  FileFsRef,
24356
24610
  FileRef,
24611
+ FunctionSizeError,
24357
24612
  Lambda,
24613
+ MAX_LAMBDA_SIZE,
24614
+ MAX_LAMBDA_UNCOMPRESSED_SIZE,
24358
24615
  NODE_VERSIONS,
24359
24616
  NodeVersion,
24360
24617
  NodejsLambda,
@@ -24366,6 +24623,7 @@ var MultipartContentStream = class extends import_stream.Readable {
24366
24623
  Version,
24367
24624
  buildsSchema,
24368
24625
  cloneEnv,
24626
+ collectUncompressedSize,
24369
24627
  createLambda,
24370
24628
  debug,
24371
24629
  defaultCachePathGlob,
@@ -24373,6 +24631,7 @@ var MultipartContentStream = class extends import_stream.Readable {
24373
24631
  download,
24374
24632
  downloadFile,
24375
24633
  execCommand,
24634
+ finalizeLambda,
24376
24635
  findPackageJson,
24377
24636
  functionsSchema,
24378
24637
  generateNodeBuilderFunctions,
@@ -24444,11 +24703,22 @@ var MultipartContentStream = class extends import_stream.Readable {
24444
24703
  streamToDigestAsync,
24445
24704
  streamWithExtendedPayload,
24446
24705
  traverseUpDirectories,
24706
+ validateEnvWrapperSupport,
24707
+ validateLambdaSize,
24447
24708
  validateNpmrc,
24709
+ validateUncompressedLambdaSize,
24448
24710
  walkParentDirs
24449
24711
  });
24450
24712
  /*! Bundled license information:
24451
24713
 
24714
+ bytes/index.js:
24715
+ (*!
24716
+ * bytes
24717
+ * Copyright(c) 2012-2014 TJ Holowaychuk
24718
+ * Copyright(c) 2015 Jed Watson
24719
+ * MIT Licensed
24720
+ *)
24721
+
24452
24722
  smol-toml/dist/error.js:
24453
24723
  (*!
24454
24724
  * Copyright (c) Squirrel Chat et al., All rights reserved.
@@ -0,0 +1,46 @@
1
+ /// <reference types="node" />
2
+ import { NowBuildError } from './errors';
3
+ /**
4
+ * Max compressed ZIP size (300 MB).
5
+ * Limit is 250 MB uncompressed; we set 300 MB compressed as a safety
6
+ * buffer. Python is exempt because AI workloads commonly exceed this.
7
+ */
8
+ export declare const MAX_LAMBDA_SIZE: number;
9
+ /**
10
+ * Max uncompressed size (250 MB).
11
+ */
12
+ export declare const MAX_LAMBDA_UNCOMPRESSED_SIZE: number;
13
+ /**
14
+ * Error thrown when a Lambda's compressed ZIP exceeds the allowed size.
15
+ */
16
+ export declare class FunctionSizeError extends NowBuildError {
17
+ size: number;
18
+ maxSize: number;
19
+ constructor(outputPath: string, size: number);
20
+ }
21
+ /**
22
+ * Validates the compressed size of a Lambda function.
23
+ * Python runtimes are exempt because AI workloads commonly exceed 300 MB.
24
+ */
25
+ export declare function validateLambdaSize(outputPath: string, runtime: string, size: number): void;
26
+ /**
27
+ * Validates the uncompressed size of a Lambda function.
28
+ */
29
+ export declare function validateUncompressedLambdaSize(outputPath: string, uncompressedBytes: number): void;
30
+ /**
31
+ * Runtimes that support env wrapper.
32
+ */
33
+ export declare const ENV_WRAPPER_SUPPORTED_FAMILIES: string[];
34
+ interface LambdaLikeForEnvWrapper {
35
+ createZip?: () => Promise<Buffer>;
36
+ runtime: string;
37
+ supportsWrapper?: boolean;
38
+ }
39
+ /**
40
+ * When the function requires a file for the encrypted environment variables,
41
+ * it needs to support wrappers. Also, the function must have a `createZip`
42
+ * function since we need to "re-compress" to include the file in the final
43
+ * lambda.
44
+ */
45
+ export declare function validateEnvWrapperSupport(encryptedEnvFilename: string | undefined, encryptedEnvContent: string | undefined, lambda: LambdaLikeForEnvWrapper): void;
46
+ export {};
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var validate_lambda_size_exports = {};
30
+ __export(validate_lambda_size_exports, {
31
+ ENV_WRAPPER_SUPPORTED_FAMILIES: () => ENV_WRAPPER_SUPPORTED_FAMILIES,
32
+ FunctionSizeError: () => FunctionSizeError,
33
+ MAX_LAMBDA_SIZE: () => MAX_LAMBDA_SIZE,
34
+ MAX_LAMBDA_UNCOMPRESSED_SIZE: () => MAX_LAMBDA_UNCOMPRESSED_SIZE,
35
+ validateEnvWrapperSupport: () => validateEnvWrapperSupport,
36
+ validateLambdaSize: () => validateLambdaSize,
37
+ validateUncompressedLambdaSize: () => validateUncompressedLambdaSize
38
+ });
39
+ module.exports = __toCommonJS(validate_lambda_size_exports);
40
+ var import_errors = require("./errors");
41
+ var import_bytes = __toESM(require("bytes"));
42
+ const MAX_LAMBDA_SIZE = (0, import_bytes.default)("300mb");
43
+ const MAX_LAMBDA_UNCOMPRESSED_SIZE = 250 * 1024 * 1024;
44
+ class FunctionSizeError extends import_errors.NowBuildError {
45
+ constructor(outputPath, size) {
46
+ super({
47
+ code: "NOW_SANDBOX_WORKER_MAX_LAMBDA_SIZE",
48
+ message: `The Vercel Function "${outputPath}" is ${(0, import_bytes.default)(
49
+ size
50
+ ).toLowerCase()} which exceeds the maximum size limit of ${(0, import_bytes.default)(
51
+ MAX_LAMBDA_SIZE
52
+ ).toLowerCase()}.`,
53
+ link: "https://vercel.link/serverless-function-size",
54
+ action: "Learn More"
55
+ });
56
+ this.size = size;
57
+ this.maxSize = MAX_LAMBDA_SIZE;
58
+ }
59
+ }
60
+ function validateLambdaSize(outputPath, runtime, size) {
61
+ if (runtime.startsWith("python")) {
62
+ return;
63
+ }
64
+ if (size > MAX_LAMBDA_SIZE) {
65
+ throw new FunctionSizeError(outputPath, size);
66
+ }
67
+ }
68
+ function validateUncompressedLambdaSize(outputPath, uncompressedBytes) {
69
+ if (uncompressedBytes >= MAX_LAMBDA_UNCOMPRESSED_SIZE) {
70
+ throw new import_errors.NowBuildError({
71
+ code: "NOW_SANDBOX_WORKER_MAX_UNCOMPRESSED_LAMBDA_SIZE",
72
+ message: `The Vercel Function "${outputPath}" is ${(0, import_bytes.default)(
73
+ uncompressedBytes
74
+ ).toLowerCase()} uncompressed which exceeds the maximum uncompressed size limit of ${(0, import_bytes.default)(
75
+ MAX_LAMBDA_UNCOMPRESSED_SIZE
76
+ ).toLowerCase()}.`,
77
+ link: "https://vercel.link/serverless-function-size",
78
+ action: "Learn More"
79
+ });
80
+ }
81
+ }
82
+ const ENV_WRAPPER_SUPPORTED_FAMILIES = [
83
+ "nodejs",
84
+ "python",
85
+ "ruby",
86
+ "java",
87
+ "dotnetcore",
88
+ "bun",
89
+ "executable"
90
+ ];
91
+ function validateEnvWrapperSupport(encryptedEnvFilename, encryptedEnvContent, lambda) {
92
+ if (!encryptedEnvFilename || !encryptedEnvContent) {
93
+ return;
94
+ }
95
+ if (!lambda.supportsWrapper && !ENV_WRAPPER_SUPPORTED_FAMILIES.some(
96
+ (family) => lambda.runtime.startsWith(family)
97
+ )) {
98
+ throw new Error(
99
+ `Serverless Function runtime ${lambda.runtime} does not support more than 4KB for environment variables`
100
+ );
101
+ }
102
+ if (typeof lambda.createZip !== "function") {
103
+ throw new Error(
104
+ `Serverless Function with runtime ${lambda.runtime} has no createZip function`
105
+ );
106
+ }
107
+ }
108
+ // Annotate the CommonJS export names for ESM import in node:
109
+ 0 && (module.exports = {
110
+ ENV_WRAPPER_SUPPORTED_FAMILIES,
111
+ FunctionSizeError,
112
+ MAX_LAMBDA_SIZE,
113
+ MAX_LAMBDA_UNCOMPRESSED_SIZE,
114
+ validateEnvWrapperSupport,
115
+ validateLambdaSize,
116
+ validateUncompressedLambdaSize
117
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/build-utils",
3
- "version": "13.12.1",
3
+ "version": "13.12.2",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",
@@ -16,8 +16,10 @@
16
16
  "@vercel/python-analysis": "0.11.0"
17
17
  },
18
18
  "devDependencies": {
19
+ "bytes": "3.1.2",
19
20
  "smol-toml": "1.5.2",
20
21
  "@types/async-retry": "^1.2.1",
22
+ "@types/bytes": "3.1.1",
21
23
  "@types/cross-spawn": "6.0.0",
22
24
  "@types/end-of-stream": "^1.4.0",
23
25
  "@types/fs-extra": "9.0.13",