@vercel/build-utils 13.36.3 → 14.0.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,60 @@
1
1
  # @vercel/build-utils
2
2
 
3
+ ## 14.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - b7ec19b: Scope the pre-compilation install's `VERCEL_INSTALL_COMPLETED` marker to the `package.json` it installed. Previously, a `vercel.toml`/`vercel.ts` config caused `vc build` to install at the repo root and then silently skip every later default install, so services whose install root is a different workspace (its own `package.json`/lockfile) built without dependencies.
8
+
9
+ ## 14.0.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 6d7fbfa: Bump all workspace packages to trigger a full publish from vercel-internal.
14
+ - Updated dependencies [6d7fbfa]
15
+ - @vercel/python-analysis@0.13.1
16
+
17
+ ## 14.0.0
18
+
19
+ ### Major Changes
20
+
21
+ - 5c33351: Remove `getOsRelease()`, and stop deriving the provided runtime from the build host.
22
+
23
+ `getProvidedRuntime()` is retained and now always resolves to `'provided.al2023'`. It previously read `/etc/os-release` and returned `'provided.al2'` on Amazon Linux 2 hosts, so the emitted runtime depended on where the build ran — a `vercel build` on an AL2 machine produced output that is rejected at deploy time, because `provided.al2` is no longer an accepted Lambda runtime. Custom runtimes calling `getProvidedRuntime()` need no changes and are fixed by this release.
24
+
25
+ `getOsRelease()` is removed with no replacement.
26
+
27
+ `validateBuildResult()` no longer accepts an `osRelease` option. Its runtime allowlist check was previously skipped unless the caller passed `osRelease.VERSION === '2023'`; it now always runs.
28
+
29
+ ### Minor Changes
30
+
31
+ - b747ab4: Replace the inferred PPR fields on `Prerender` with the Next.js prerender taxonomy.
32
+
33
+ `hasPostponed`, `hasFallback`, `isDynamicRoute` and `htmlSize` were derived by
34
+ `@vercel/next` from build artifacts (the `.meta` postponed state, which manifest
35
+ section a route came from, and a `statSync` of the `.html` shell). Next.js
36
+ `>= 16.3.0-canary.96` publishes its own classification in the prerender
37
+ manifest, so those four fields are removed in favour of a single optional
38
+ `prerenderClassification` on `Prerender` / `PrerenderOptions`:
39
+
40
+ - `routeType` — `'route' | 'page' | 'shell' | 'fallback'`
41
+ - `response` — `'empty' | 'initial' | 'complete'`
42
+ - `compute` — `'blocking' | 'resuming' | 'static'`
43
+ - `htmlSize` — byte size of the prerendered HTML shell, when the entry has one
44
+
45
+ The values are carried through unvalidated so a taxonomy value added by a future
46
+ Next.js release cannot hard-fail a deploy. `@vercel/next` sets the field only
47
+ when Next.js supplied the complete group — absence is legitimate for
48
+ `notFoundRoutes` and Pages Router `fallback: false` templates — and only on the
49
+ primary output of each prerender group, so a route is classified exactly once.
50
+
51
+ - 5619873: Fix api dir builds receiving incorrect framework or runtime.
52
+
53
+ ### Patch Changes
54
+
55
+ - Updated dependencies [08a2618]
56
+ - @vercel/python-analysis@0.13.0
57
+
3
58
  ## 13.36.3
4
59
 
5
60
  ### Patch Changes
@@ -9,13 +9,11 @@ export interface ValidateBuildResultParams {
9
9
  allowInvalidRuntime?: boolean;
10
10
  buildConfig?: BuildConfigWithVercelConfig;
11
11
  buildResponse: BuildResultV2Typical | BuildResultV3;
12
- osRelease?: OsRelease | null;
13
12
  vercelBaseUrl?: string;
14
13
  }
15
14
  export interface ValidateBuildResultResult {
16
15
  buildOutputMap: BuildResultV2Typical['output'];
17
16
  customFunctionConfiguration?: BuilderFunctions[string];
18
17
  }
19
- type OsRelease = Record<string, string>;
20
- export declare function validateBuildResult({ allowInvalidRuntime, buildConfig, buildResponse, osRelease, vercelBaseUrl, }: ValidateBuildResultParams): Promise<ValidateBuildResultResult>;
18
+ export declare function validateBuildResult({ allowInvalidRuntime, buildConfig, buildResponse, vercelBaseUrl, }: ValidateBuildResultParams): Promise<ValidateBuildResultResult>;
21
19
  export {};
@@ -55,7 +55,6 @@ async function validateBuildResult({
55
55
  allowInvalidRuntime = false,
56
56
  buildConfig,
57
57
  buildResponse,
58
- osRelease,
59
58
  vercelBaseUrl
60
59
  }) {
61
60
  if (!("output" in buildResponse)) {
@@ -71,33 +70,31 @@ async function validateBuildResult({
71
70
  });
72
71
  }
73
72
  const buildOutputMap = getAndVerifyOutputLambdasOrEdgeFuncs(buildResponse);
74
- if (osRelease?.VERSION === "2023") {
75
- const invalidRuntimes = [];
76
- for (const [name, entry] of Object.entries(buildOutputMap)) {
77
- let lambda;
78
- if (entry.type === "Prerender") {
79
- lambda = entry.lambda;
80
- } else if (entry.type === "Lambda") {
81
- lambda = entry;
82
- }
83
- if (!lambda)
84
- continue;
85
- if (!isSupportedAl2023Runtime(lambda.runtime)) {
86
- invalidRuntimes.push({ name, lambda });
87
- }
73
+ const invalidRuntimes = [];
74
+ for (const [name, entry] of Object.entries(buildOutputMap)) {
75
+ let lambda;
76
+ if (entry.type === "Prerender") {
77
+ lambda = entry.lambda;
78
+ } else if (entry.type === "Lambda") {
79
+ lambda = entry;
88
80
  }
89
- if (invalidRuntimes.length > 0 && !allowInvalidRuntime) {
90
- throw new import_errors.NowBuildError({
91
- code: "NOW_SANDBOX_WORKER_INVALID_RUNTIME",
92
- message: `The following Serverless Functions contain an invalid "runtime":
93
- ${invalidRuntimes.map(({ name, lambda }) => ` - ${name} (${lambda.runtime})`).join("\n")}`,
94
- link: getVercelUrl(
95
- "/docs/functions/runtimes#official-runtimes",
96
- vercelBaseUrl
97
- )
98
- });
81
+ if (!lambda)
82
+ continue;
83
+ if (!isSupportedAl2023Runtime(lambda.runtime)) {
84
+ invalidRuntimes.push({ name, lambda });
99
85
  }
100
86
  }
87
+ if (invalidRuntimes.length > 0 && !allowInvalidRuntime) {
88
+ throw new import_errors.NowBuildError({
89
+ code: "NOW_SANDBOX_WORKER_INVALID_RUNTIME",
90
+ message: `The following Serverless Functions contain an invalid "runtime":
91
+ ${invalidRuntimes.map(({ name, lambda }) => ` - ${name} (${lambda.runtime})`).join("\n")}`,
92
+ link: getVercelUrl(
93
+ "/docs/functions/runtimes#official-runtimes",
94
+ vercelBaseUrl
95
+ )
96
+ });
97
+ }
101
98
  const customFunctionConfiguration = getCustomFunctionConfigMaybe(buildConfig);
102
99
  if (customFunctionConfiguration?.runtime) {
103
100
  throw new import_errors.NowBuildError({
@@ -592,6 +592,16 @@ function checkIfAlreadyInstalled(runNpmInstallSet, packageJsonPath) {
592
592
  return { alreadyInstalled, runNpmInstallSet: initializedRunNpmInstallSet };
593
593
  }
594
594
  const runNpmInstallSema = new import_async_sema.default(1);
595
+ function installCompletedCovers(packageJsonPath) {
596
+ if (process.env.VERCEL_INSTALL_COMPLETED !== "1") {
597
+ return false;
598
+ }
599
+ const completedPath = process.env.VERCEL_INSTALL_COMPLETED_PATH;
600
+ if (!completedPath) {
601
+ return true;
602
+ }
603
+ return packageJsonPath !== void 0 && import_path.default.normalize(completedPath) === import_path.default.normalize(packageJsonPath);
604
+ }
595
605
  let customInstallCommandSet;
596
606
  function resetCustomInstallCommandSet() {
597
607
  customInstallCommandSet = void 0;
@@ -627,7 +637,7 @@ async function runNpmInstall(destPath, args = [], spawnOpts, meta, projectCreate
627
637
  if (alreadyInstalled) {
628
638
  return false;
629
639
  }
630
- if (process.env.VERCEL_INSTALL_COMPLETED === "1") {
640
+ if (installCompletedCovers(packageJsonPath)) {
631
641
  (0, import_debug.default)(
632
642
  `Skipping dependency installation for ${packageJsonPath} because VERCEL_INSTALL_COMPLETED is set`
633
643
  );
@@ -1041,20 +1051,21 @@ async function runCustomInstallCommand({
1041
1051
  );
1042
1052
  return false;
1043
1053
  }
1044
- if (process.env.VERCEL_INSTALL_COMPLETED === "1") {
1045
- (0, import_debug.default)(
1046
- `Skipping custom install command for ${normalizedPath} because VERCEL_INSTALL_COMPLETED is set`
1047
- );
1048
- return false;
1049
- }
1050
- console.log(`Running "install" command: \`${installCommand}\`...`);
1051
1054
  const {
1052
1055
  cliType,
1053
1056
  lockfileVersion,
1054
1057
  packageJson,
1058
+ packageJsonPath,
1055
1059
  packageJsonPackageManager,
1056
1060
  turboSupportsCorepackHome
1057
1061
  } = await scanParentDirs(destPath, true);
1062
+ if (installCompletedCovers(packageJsonPath)) {
1063
+ (0, import_debug.default)(
1064
+ `Skipping custom install command for ${normalizedPath} because VERCEL_INSTALL_COMPLETED is set`
1065
+ );
1066
+ return false;
1067
+ }
1068
+ console.log(`Running "install" command: \`${installCommand}\`...`);
1058
1069
  const env = getEnvForPackageManager({
1059
1070
  cliType,
1060
1071
  lockfileVersion,
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import FileFsRef from './file-fs-ref';
3
3
  import FileRef from './file-ref';
4
4
  import { Lambda, createLambda, getLambdaOptionsFromFunction, sanitizeConsumerName } from './lambda';
5
5
  import { NodejsLambda, type NodejsLambdaOptions } from './nodejs-lambda';
6
- import { Prerender } from './prerender';
6
+ import { Prerender, type PrerenderClassification } from './prerender';
7
7
  import download, { downloadFile, DownloadedFiles, isSymbolicLink, isDirectory, isExternalSymlink, isExternalSymlinkTarget, getSymlinkTarget } from './fs/download';
8
8
  import getWriteableDirectory from './fs/get-writable-directory';
9
9
  import glob, { GlobOptions } from './fs/glob';
@@ -19,14 +19,14 @@ import { getServiceUrlEnvVars, getExperimentalServiceUrlEnvVars } from './get-se
19
19
  import { cloneEnv } from './clone-env';
20
20
  import { hardLinkDir } from './hard-link-dir';
21
21
  import { validateNpmrc } from './validate-npmrc';
22
- export type { NodejsLambdaOptions };
22
+ export type { NodejsLambdaOptions, PrerenderClassification };
23
23
  export { FileBlob, FileFsRef, FileRef, Lambda, NodejsLambda, createLambda, Prerender, download, downloadFile, DownloadedFiles, getWriteableDirectory, glob, GlobOptions, rename, spawnAsync, getScriptName, installDependencies, runPackageJsonScript, execCommand, spawnCommand, walkParentDirs, getNodeBinPath, getNodeBinPaths, getSupportedNodeVersion, isBunVersion, getSupportedBunVersion, detectPackageManager, runNpmInstall, NpmInstallOutput, runBundleInstall, runPipInstall, PipInstallResult, runShellScript, runCustomInstallCommand, resetCustomInstallCommandSet, getEnvForPackageManager, getNodeVersion, getPathForPackageManager, getLatestNodeVersion, getDiscontinuedNodeVersions, getSpawnOptions, getPlatformEnv, getPrefixedEnvVars, getServiceUrlEnvVars, getExperimentalServiceUrlEnvVars, streamToBuffer, streamToBufferChunks, debug, isSymbolicLink, isDirectory, isExternalSymlink, isExternalSymlinkTarget, getSymlinkTarget, getLambdaOptionsFromFunction, sanitizeConsumerName, scanParentDirs, findPackageJson, getIgnoreFilter, cloneEnv, hardLinkDir, traverseUpDirectories, validateNpmrc, type CliType, };
24
24
  export { EdgeFunction } from './edge-function';
25
25
  export { ContainerImage } from './container-image';
26
26
  export type { ContainerImageConfig } from './container-image';
27
27
  export { readConfigFile, getPackageJson } from './fs/read-config-file';
28
28
  export { normalizePath } from './fs/normalize-path';
29
- export { getOsRelease, getProvidedRuntime } from './os';
29
+ export { getProvidedRuntime } from './provided-runtime';
30
30
  export * from './should-serve';
31
31
  export * from './schemas';
32
32
  export { DEFAULT_MAX_DURATION_LIMIT, SKIP_MAX_DURATION_LIMIT_ENV, getMaxDurationLimit, getMaxDurationSchema, } from './max-duration';
package/dist/index.js CHANGED
@@ -2918,8 +2918,8 @@ var require_graceful_fs = __commonJS({
2918
2918
  fs13.createReadStream = createReadStream;
2919
2919
  fs13.createWriteStream = createWriteStream;
2920
2920
  var fs$readFile = fs13.readFile;
2921
- fs13.readFile = readFile4;
2922
- function readFile4(path8, options, cb) {
2921
+ fs13.readFile = readFile3;
2922
+ function readFile3(path8, options, cb) {
2923
2923
  if (typeof options === "function")
2924
2924
  cb = options, options = null;
2925
2925
  return go$readFile(path8, options, cb);
@@ -4667,7 +4667,7 @@ var require_jsonfile = __commonJS({
4667
4667
  }
4668
4668
  return obj;
4669
4669
  }
4670
- var readFile4 = universalify.fromPromise(_readFile);
4670
+ var readFile3 = universalify.fromPromise(_readFile);
4671
4671
  function readFileSync(file, options = {}) {
4672
4672
  if (typeof options === "string") {
4673
4673
  options = { encoding: options };
@@ -4699,7 +4699,7 @@ var require_jsonfile = __commonJS({
4699
4699
  return fs12.writeFileSync(file, str, options);
4700
4700
  }
4701
4701
  module2.exports = {
4702
- readFile: readFile4,
4702
+ readFile: readFile3,
4703
4703
  readFileSync,
4704
4704
  writeFile,
4705
4705
  writeFileSync
@@ -15412,7 +15412,7 @@ var require_dist = __commonJS({
15412
15412
  errorToString: () => errorToString,
15413
15413
  errorToStringFriendly: () => errorToStringFriendly,
15414
15414
  getSystemErrorMessage: () => getSystemErrorMessage,
15415
- isErrnoException: () => isErrnoException3,
15415
+ isErrnoException: () => isErrnoException2,
15416
15416
  isError: () => isError,
15417
15417
  isErrorLike: () => isErrorLike,
15418
15418
  isObject: () => isObject,
@@ -15425,7 +15425,7 @@ var require_dist = __commonJS({
15425
15425
  var isError = (error) => {
15426
15426
  return import_node_util.default.types.isNativeError(error);
15427
15427
  };
15428
- var isErrnoException3 = (error) => {
15428
+ var isErrnoException2 = (error) => {
15429
15429
  return isError(error) && "code" in error;
15430
15430
  };
15431
15431
  var nativeGetSystemErrorMessage = import_node_util.default.getSystemErrorMessage;
@@ -15442,7 +15442,7 @@ var require_dist = __commonJS({
15442
15442
  };
15443
15443
  var getSystemErrorMessage = nativeGetSystemErrorMessage ?? getSystemErrorMessageFallback;
15444
15444
  var errorToStringFriendly = (error, fallback) => {
15445
- if (isErrnoException3(error) && typeof error.errno === "number") {
15445
+ if (isErrnoException2(error) && typeof error.errno === "number") {
15446
15446
  return getSystemErrorMessage(error.errno);
15447
15447
  }
15448
15448
  return errorToString(error, fallback);
@@ -15454,7 +15454,7 @@ var require_dist = __commonJS({
15454
15454
  return isErrorLike(error) ? Object.assign(new Error(errorMessage), error) : new Error(errorMessage);
15455
15455
  };
15456
15456
  function isSpawnError(v) {
15457
- return isErrnoException3(v) && "spawnargs" in v;
15457
+ return isErrnoException2(v) && "spawnargs" in v;
15458
15458
  }
15459
15459
  }
15460
15460
  });
@@ -31618,7 +31618,6 @@ __export(src_exports, {
31618
31618
  getNodeBinPath: () => getNodeBinPath,
31619
31619
  getNodeBinPaths: () => getNodeBinPaths,
31620
31620
  getNodeVersion: () => getNodeVersion,
31621
- getOsRelease: () => getOsRelease,
31622
31621
  getPackageJson: () => getPackageJson,
31623
31622
  getPathForPackageManager: () => getPathForPackageManager,
31624
31623
  getPlatformEnv: () => getPlatformEnv,
@@ -32616,13 +32615,6 @@ var NodejsLambda = class extends Lambda {
32616
32615
  };
32617
32616
 
32618
32617
  // src/prerender.ts
32619
- function assertOptionalBoolean(value, name) {
32620
- if (value !== void 0 && typeof value !== "boolean") {
32621
- throw new Error(
32622
- `The \`${name}\` argument for \`Prerender\` must be a boolean or undefined.`
32623
- );
32624
- }
32625
- }
32626
32618
  var Prerender = class {
32627
32619
  constructor({
32628
32620
  expiration,
@@ -32642,27 +32634,13 @@ var Prerender = class {
32642
32634
  chain,
32643
32635
  exposeErrBody,
32644
32636
  partialFallback,
32645
- hasPostponed,
32646
- hasFallback,
32647
- htmlSize,
32648
- isDynamicRoute
32637
+ prerenderClassification
32649
32638
  }) {
32650
32639
  this.type = "Prerender";
32651
32640
  this.expiration = expiration;
32652
32641
  this.staleExpiration = staleExpiration;
32653
32642
  this.sourcePath = sourcePath;
32654
- assertOptionalBoolean(hasPostponed, "hasPostponed");
32655
- this.hasPostponed = hasPostponed;
32656
- assertOptionalBoolean(hasFallback, "hasFallback");
32657
- this.hasFallback = hasFallback;
32658
- assertOptionalBoolean(isDynamicRoute, "isDynamicRoute");
32659
- this.isDynamicRoute = isDynamicRoute;
32660
- if (htmlSize !== void 0 && (!Number.isInteger(htmlSize) || htmlSize < 0)) {
32661
- throw new Error(
32662
- "The `htmlSize` argument for `Prerender` must be a non-negative integer or undefined."
32663
- );
32664
- }
32665
- this.htmlSize = htmlSize;
32643
+ this.prerenderClassification = prerenderClassification;
32666
32644
  this.lambda = lambda;
32667
32645
  if (this.lambda) {
32668
32646
  this.lambda.operationType = this.lambda.operationType || "ISR";
@@ -34455,6 +34433,16 @@ function checkIfAlreadyInstalled(runNpmInstallSet, packageJsonPath) {
34455
34433
  return { alreadyInstalled, runNpmInstallSet: initializedRunNpmInstallSet };
34456
34434
  }
34457
34435
  var runNpmInstallSema = new import_async_sema4.default(1);
34436
+ function installCompletedCovers(packageJsonPath) {
34437
+ if (process.env.VERCEL_INSTALL_COMPLETED !== "1") {
34438
+ return false;
34439
+ }
34440
+ const completedPath = process.env.VERCEL_INSTALL_COMPLETED_PATH;
34441
+ if (!completedPath) {
34442
+ return true;
34443
+ }
34444
+ return packageJsonPath !== void 0 && import_path6.default.normalize(completedPath) === import_path6.default.normalize(packageJsonPath);
34445
+ }
34458
34446
  var customInstallCommandSet;
34459
34447
  function resetCustomInstallCommandSet() {
34460
34448
  customInstallCommandSet = void 0;
@@ -34490,7 +34478,7 @@ async function runNpmInstall(destPath, args = [], spawnOpts, meta, projectCreate
34490
34478
  if (alreadyInstalled) {
34491
34479
  return false;
34492
34480
  }
34493
- if (process.env.VERCEL_INSTALL_COMPLETED === "1") {
34481
+ if (installCompletedCovers(packageJsonPath)) {
34494
34482
  debug(
34495
34483
  `Skipping dependency installation for ${packageJsonPath} because VERCEL_INSTALL_COMPLETED is set`
34496
34484
  );
@@ -34904,20 +34892,21 @@ async function runCustomInstallCommand({
34904
34892
  );
34905
34893
  return false;
34906
34894
  }
34907
- if (process.env.VERCEL_INSTALL_COMPLETED === "1") {
34908
- debug(
34909
- `Skipping custom install command for ${normalizedPath} because VERCEL_INSTALL_COMPLETED is set`
34910
- );
34911
- return false;
34912
- }
34913
- console.log(`Running "install" command: \`${installCommand}\`...`);
34914
34895
  const {
34915
34896
  cliType,
34916
34897
  lockfileVersion,
34917
34898
  packageJson,
34899
+ packageJsonPath,
34918
34900
  packageJsonPackageManager,
34919
34901
  turboSupportsCorepackHome
34920
34902
  } = await scanParentDirs(destPath, true);
34903
+ if (installCompletedCovers(packageJsonPath)) {
34904
+ debug(
34905
+ `Skipping custom install command for ${normalizedPath} because VERCEL_INSTALL_COMPLETED is set`
34906
+ );
34907
+ return false;
34908
+ }
34909
+ console.log(`Running "install" command: \`${installCommand}\`...`);
34921
34910
  const env = getEnvForPackageManager({
34922
34911
  cliType,
34923
34912
  lockfileVersion,
@@ -35035,7 +35024,7 @@ function clearRelative(s) {
35035
35024
  return s.replace(/(\n|^)\.\//g, "$1");
35036
35025
  }
35037
35026
  async function get_ignore_filter_default(downloadPath, rootDirectory) {
35038
- const readFile4 = async (p) => {
35027
+ const readFile3 = async (p) => {
35039
35028
  try {
35040
35029
  return await import_fs_extra8.default.readFile(p, "utf8");
35041
35030
  } catch (error) {
@@ -35058,7 +35047,7 @@ async function get_ignore_filter_default(downloadPath, rootDirectory) {
35058
35047
  const ignoreContents = [];
35059
35048
  try {
35060
35049
  ignoreContents.push(
35061
- ...(await Promise.all([readFile4(vercelIgnorePath), readFile4(nowIgnorePath)])).filter(Boolean)
35050
+ ...(await Promise.all([readFile3(vercelIgnorePath), readFile3(nowIgnorePath)])).filter(Boolean)
35062
35051
  );
35063
35052
  } catch (error) {
35064
35053
  if (isCodedError(error) && error.code === "ENOTDIR") {
@@ -35334,37 +35323,9 @@ var ContainerImage = class {
35334
35323
  }
35335
35324
  };
35336
35325
 
35337
- // src/os.ts
35338
- var import_fs_extra9 = __toESM(require_lib());
35339
- var import_error_utils2 = __toESM(require_dist());
35340
- async function getOsRelease() {
35341
- try {
35342
- const data = await (0, import_fs_extra9.readFile)("/etc/os-release", "utf8");
35343
- return await parseOsRelease(data);
35344
- } catch (err) {
35345
- if ((0, import_error_utils2.isErrnoException)(err) && err.code === "ENOENT") {
35346
- return null;
35347
- }
35348
- throw err;
35349
- }
35350
- }
35351
- async function parseOsRelease(data) {
35352
- const obj = {};
35353
- for (const line of data.trim().split("\n")) {
35354
- const m = /(?<key>.*)="(?<value>.*)"/.exec(line);
35355
- if (!m?.groups) {
35356
- continue;
35357
- }
35358
- obj[m.groups.key] = m.groups.value;
35359
- }
35360
- return obj;
35361
- }
35326
+ // src/provided-runtime.ts
35362
35327
  async function getProvidedRuntime() {
35363
- const os = await getOsRelease();
35364
- if (!os) {
35365
- return "provided.al2023";
35366
- }
35367
- return os.PRETTY_NAME === "Amazon Linux 2" ? "provided.al2" : "provided.al2023";
35328
+ return "provided.al2023";
35368
35329
  }
35369
35330
 
35370
35331
  // src/should-serve.ts
@@ -36022,7 +35983,8 @@ async function generateProjectManifest({
36022
35983
  lockfilePath,
36023
35984
  lockfileVersion,
36024
35985
  framework,
36025
- serviceType
35986
+ serviceType,
35987
+ outputRuntime = "node"
36026
35988
  }) {
36027
35989
  try {
36028
35990
  const pkgJson = await readPackageJson(workPath);
@@ -36097,7 +36059,7 @@ async function generateProjectManifest({
36097
36059
  ...transitiveDeps.sort((a, b) => a.name.localeCompare(b.name))
36098
36060
  ]
36099
36061
  };
36100
- await writeProjectManifest(manifest, workPath, "node");
36062
+ await writeProjectManifest(manifest, workPath, outputRuntime);
36101
36063
  } catch (err) {
36102
36064
  debug(
36103
36065
  `generateProjectManifest: ${err instanceof Error ? err.message : String(err)}`
@@ -36221,7 +36183,8 @@ async function generateRubyProjectManifest({
36221
36183
  workPath,
36222
36184
  gemfileLockPath,
36223
36185
  framework,
36224
- serviceType
36186
+ serviceType,
36187
+ outputRuntime = "ruby"
36225
36188
  }) {
36226
36189
  try {
36227
36190
  if (!gemfileLockPath)
@@ -36275,7 +36238,7 @@ async function generateRubyProjectManifest({
36275
36238
  ...transitiveEntries.sort((a, b) => a.name.localeCompare(b.name))
36276
36239
  ]
36277
36240
  };
36278
- await writeProjectManifest(manifest, workPath, "ruby");
36241
+ await writeProjectManifest(manifest, workPath, outputRuntime);
36279
36242
  } catch {
36280
36243
  }
36281
36244
  }
@@ -37074,7 +37037,6 @@ async function validateBuildResult({
37074
37037
  allowInvalidRuntime = false,
37075
37038
  buildConfig,
37076
37039
  buildResponse,
37077
- osRelease,
37078
37040
  vercelBaseUrl
37079
37041
  }) {
37080
37042
  if (!("output" in buildResponse)) {
@@ -37090,32 +37052,30 @@ async function validateBuildResult({
37090
37052
  });
37091
37053
  }
37092
37054
  const buildOutputMap = getAndVerifyOutputLambdasOrEdgeFuncs(buildResponse);
37093
- if (osRelease?.VERSION === "2023") {
37094
- const invalidRuntimes = [];
37095
- for (const [name, entry] of Object.entries(buildOutputMap)) {
37096
- let lambda;
37097
- if (entry.type === "Prerender") {
37098
- lambda = entry.lambda;
37099
- } else if (entry.type === "Lambda") {
37100
- lambda = entry;
37101
- }
37102
- if (!lambda)
37103
- continue;
37104
- if (!isSupportedAl2023Runtime(lambda.runtime)) {
37105
- invalidRuntimes.push({ name, lambda });
37106
- }
37055
+ const invalidRuntimes = [];
37056
+ for (const [name, entry] of Object.entries(buildOutputMap)) {
37057
+ let lambda;
37058
+ if (entry.type === "Prerender") {
37059
+ lambda = entry.lambda;
37060
+ } else if (entry.type === "Lambda") {
37061
+ lambda = entry;
37062
+ }
37063
+ if (!lambda)
37064
+ continue;
37065
+ if (!isSupportedAl2023Runtime(lambda.runtime)) {
37066
+ invalidRuntimes.push({ name, lambda });
37107
37067
  }
37108
- if (invalidRuntimes.length > 0 && !allowInvalidRuntime) {
37109
- throw new NowBuildError({
37110
- code: "NOW_SANDBOX_WORKER_INVALID_RUNTIME",
37111
- message: `The following Serverless Functions contain an invalid "runtime":
37068
+ }
37069
+ if (invalidRuntimes.length > 0 && !allowInvalidRuntime) {
37070
+ throw new NowBuildError({
37071
+ code: "NOW_SANDBOX_WORKER_INVALID_RUNTIME",
37072
+ message: `The following Serverless Functions contain an invalid "runtime":
37112
37073
  ${invalidRuntimes.map(({ name, lambda }) => ` - ${name} (${lambda.runtime})`).join("\n")}`,
37113
- link: getVercelUrl(
37114
- "/docs/functions/runtimes#official-runtimes",
37115
- vercelBaseUrl
37116
- )
37117
- });
37118
- }
37074
+ link: getVercelUrl(
37075
+ "/docs/functions/runtimes#official-runtimes",
37076
+ vercelBaseUrl
37077
+ )
37078
+ });
37119
37079
  }
37120
37080
  const customFunctionConfiguration = getCustomFunctionConfigMaybe(buildConfig);
37121
37081
  if (customFunctionConfiguration?.runtime) {
@@ -37425,12 +37385,12 @@ async function fileFsRefCached(fsPath, cache) {
37425
37385
 
37426
37386
  // src/deserialize/create-functions-iterator.ts
37427
37387
  var import_path14 = require("path");
37428
- var import_fs_extra10 = __toESM(require_lib());
37388
+ var import_fs_extra9 = __toESM(require_lib());
37429
37389
  var SUFFIX = ".func";
37430
37390
  async function* createFunctionsIterator(dir, root = dir) {
37431
37391
  let paths;
37432
37392
  try {
37433
- paths = await (0, import_fs_extra10.readdir)(dir);
37393
+ paths = await (0, import_fs_extra9.readdir)(dir);
37434
37394
  } catch (err) {
37435
37395
  if (err.code !== "ENOENT" && err.code !== "ENOTDIR") {
37436
37396
  throw err;
@@ -37439,7 +37399,7 @@ async function* createFunctionsIterator(dir, root = dir) {
37439
37399
  }
37440
37400
  for (const path8 of paths) {
37441
37401
  const abs = (0, import_path14.join)(dir, path8);
37442
- const s = await (0, import_fs_extra10.stat)(abs);
37402
+ const s = await (0, import_fs_extra9.stat)(abs);
37443
37403
  if (s.isDirectory()) {
37444
37404
  if (path8.endsWith(SUFFIX)) {
37445
37405
  yield (0, import_path14.relative)(root, abs.substring(0, abs.length - SUFFIX.length));
@@ -37451,10 +37411,10 @@ async function* createFunctionsIterator(dir, root = dir) {
37451
37411
  }
37452
37412
 
37453
37413
  // src/deserialize/maybe-read-json.ts
37454
- var import_fs_extra11 = __toESM(require_lib());
37414
+ var import_fs_extra10 = __toESM(require_lib());
37455
37415
  async function maybeReadJSON(path8) {
37456
37416
  try {
37457
- return await (0, import_fs_extra11.readJSON)(path8);
37417
+ return await (0, import_fs_extra10.readJSON)(path8);
37458
37418
  } catch (err) {
37459
37419
  if (err.code !== "ENOENT")
37460
37420
  throw err;
@@ -37763,10 +37723,10 @@ async function deserializeLambda(files, config, repoRootPath, fileFsRefsCache, o
37763
37723
  }
37764
37724
 
37765
37725
  // src/collect-build-result/validate-regular-file.ts
37766
- var import_fs_extra12 = __toESM(require_lib());
37726
+ var import_fs_extra11 = __toESM(require_lib());
37767
37727
  async function validateRegularFile(file) {
37768
37728
  if ("fsPath" in file && typeof file.fsPath === "string") {
37769
- const stat2 = await (0, import_fs_extra12.lstat)(file.fsPath);
37729
+ const stat2 = await (0, import_fs_extra11.lstat)(file.fsPath);
37770
37730
  if (!stat2.isFile() && !stat2.isDirectory() && !stat2.isSymbolicLink()) {
37771
37731
  throw new NowBuildError({
37772
37732
  message: `Output file path is actually not a (regular) file: \`${file.fsPath}\``,
@@ -37946,7 +37906,6 @@ function getExtendedPayload({
37946
37906
  getNodeBinPath,
37947
37907
  getNodeBinPaths,
37948
37908
  getNodeVersion,
37949
- getOsRelease,
37950
37909
  getPackageJson,
37951
37910
  getPathForPackageManager,
37952
37911
  getPlatformEnv,
@@ -1,6 +1,6 @@
1
1
  import type { NodeVersion } from './types';
2
2
  type CliType = 'yarn' | 'npm' | 'pnpm' | 'bun' | 'vlt';
3
- export declare function generateProjectManifest({ workPath, nodeVersion, cliType, lockfilePath, lockfileVersion, framework, serviceType, }: {
3
+ export declare function generateProjectManifest({ workPath, nodeVersion, cliType, lockfilePath, lockfileVersion, framework, serviceType, outputRuntime, }: {
4
4
  workPath: string;
5
5
  nodeVersion: NodeVersion;
6
6
  cliType: CliType;
@@ -8,5 +8,6 @@ export declare function generateProjectManifest({ workPath, nodeVersion, cliType
8
8
  lockfileVersion: number | undefined;
9
9
  framework?: string;
10
10
  serviceType?: string;
11
+ outputRuntime?: string;
11
12
  }): Promise<void>;
12
13
  export {};
@@ -387,7 +387,8 @@ async function generateProjectManifest({
387
387
  lockfilePath,
388
388
  lockfileVersion,
389
389
  framework,
390
- serviceType
390
+ serviceType,
391
+ outputRuntime = "node"
391
392
  }) {
392
393
  try {
393
394
  const pkgJson = await readPackageJson(workPath);
@@ -462,7 +463,7 @@ async function generateProjectManifest({
462
463
  ...transitiveDeps.sort((a, b) => a.name.localeCompare(b.name))
463
464
  ]
464
465
  };
465
- await (0, import_package_manifest.writeProjectManifest)(manifest, workPath, "node");
466
+ await (0, import_package_manifest.writeProjectManifest)(manifest, workPath, outputRuntime);
466
467
  } catch (err) {
467
468
  (0, import_debug.default)(
468
469
  `generateProjectManifest: ${err instanceof Error ? err.message : String(err)}`
@@ -1,5 +1,19 @@
1
1
  import type { File, HasField, Chain } from './types';
2
2
  import { Lambda } from './lambda';
3
+ /**
4
+ * The framework's own description of what it prerendered, mirroring the
5
+ * Next.js prerender taxonomy rather than re-deriving it from build artifacts.
6
+ */
7
+ export interface PrerenderClassification {
8
+ /** What kind of entry this is within its route group. */
9
+ routeType: 'route' | 'page' | 'shell' | 'fallback';
10
+ /** How much of the response the prerender contains. */
11
+ response: 'empty' | 'initial' | 'complete';
12
+ /** What has to happen at request time to finish the response. */
13
+ compute: 'blocking' | 'resuming' | 'static';
14
+ /** Byte size of the prerendered HTML shell, when the entry has one. */
15
+ htmlSize?: number;
16
+ }
3
17
  interface PrerenderOptions {
4
18
  expiration: number | false;
5
19
  staleExpiration?: number;
@@ -18,10 +32,7 @@ interface PrerenderOptions {
18
32
  chain?: Chain;
19
33
  exposeErrBody?: boolean;
20
34
  partialFallback?: boolean;
21
- hasPostponed?: boolean;
22
- hasFallback?: boolean;
23
- htmlSize?: number;
24
- isDynamicRoute?: boolean;
35
+ prerenderClassification?: PrerenderClassification;
25
36
  }
26
37
  export declare class Prerender {
27
38
  type: 'Prerender';
@@ -52,31 +63,11 @@ export declare class Prerender {
52
63
  exposeErrBody?: boolean;
53
64
  partialFallback?: boolean;
54
65
  /**
55
- * Set to `true` when the route's `.meta` postponed state is present (React
56
- * suspended during build prerender). `false` when the framework prerendered
57
- * a Prerender route without postponing. `undefined` when the framework did
58
- * not provide the signal.
59
- */
60
- hasPostponed?: boolean;
61
- /**
62
- * `true` when the route's dynamic template had a static fallback page (the
63
- * prerender-manifest `fallback` was a string). `false` for blocking/omitted
64
- * dynamic templates (manifest `fallback` was `null`/`false`). `undefined` for
65
- * concrete prerenders, where the notion of a fallback doesn't apply.
66
- */
67
- hasFallback?: boolean;
68
- /**
69
- * Byte size on disk of the route's prerendered `.html` shell. `0` for an
70
- * empty shell (PPR template that postponed everything). `undefined` when
71
- * there's no `.html` on disk (pages router, route handlers, edge).
72
- */
73
- htmlSize?: number;
74
- /**
75
- * `true` when this entry came from a dynamic route template (the
76
- * prerender-manifest `dynamicRoutes` section: fallback, blocking, or omitted)
77
- * rather than a concrete prerender.
66
+ * The framework's classification of this prerender. `undefined` when the
67
+ * framework did not provide one, which is legitimate: not-found routes and
68
+ * Pages Router `fallback: false` templates have no classification.
78
69
  */
79
- isDynamicRoute?: boolean;
80
- constructor({ expiration, staleExpiration, lambda, fallback, group, bypassToken, allowQuery, allowHeader, initialHeaders, initialStatus, passQuery, sourcePath, experimentalBypassFor, experimentalStreamingLambdaPath, chain, exposeErrBody, partialFallback, hasPostponed, hasFallback, htmlSize, isDynamicRoute, }: PrerenderOptions);
70
+ prerenderClassification?: PrerenderClassification;
71
+ constructor({ expiration, staleExpiration, lambda, fallback, group, bypassToken, allowQuery, allowHeader, initialHeaders, initialStatus, passQuery, sourcePath, experimentalBypassFor, experimentalStreamingLambdaPath, chain, exposeErrBody, partialFallback, prerenderClassification, }: PrerenderOptions);
81
72
  }
82
73
  export {};
package/dist/prerender.js CHANGED
@@ -21,13 +21,6 @@ __export(prerender_exports, {
21
21
  Prerender: () => Prerender
22
22
  });
23
23
  module.exports = __toCommonJS(prerender_exports);
24
- function assertOptionalBoolean(value, name) {
25
- if (value !== void 0 && typeof value !== "boolean") {
26
- throw new Error(
27
- `The \`${name}\` argument for \`Prerender\` must be a boolean or undefined.`
28
- );
29
- }
30
- }
31
24
  class Prerender {
32
25
  constructor({
33
26
  expiration,
@@ -47,27 +40,13 @@ class Prerender {
47
40
  chain,
48
41
  exposeErrBody,
49
42
  partialFallback,
50
- hasPostponed,
51
- hasFallback,
52
- htmlSize,
53
- isDynamicRoute
43
+ prerenderClassification
54
44
  }) {
55
45
  this.type = "Prerender";
56
46
  this.expiration = expiration;
57
47
  this.staleExpiration = staleExpiration;
58
48
  this.sourcePath = sourcePath;
59
- assertOptionalBoolean(hasPostponed, "hasPostponed");
60
- this.hasPostponed = hasPostponed;
61
- assertOptionalBoolean(hasFallback, "hasFallback");
62
- this.hasFallback = hasFallback;
63
- assertOptionalBoolean(isDynamicRoute, "isDynamicRoute");
64
- this.isDynamicRoute = isDynamicRoute;
65
- if (htmlSize !== void 0 && (!Number.isInteger(htmlSize) || htmlSize < 0)) {
66
- throw new Error(
67
- "The `htmlSize` argument for `Prerender` must be a non-negative integer or undefined."
68
- );
69
- }
70
- this.htmlSize = htmlSize;
49
+ this.prerenderClassification = prerenderClassification;
71
50
  this.lambda = lambda;
72
51
  if (this.lambda) {
73
52
  this.lambda.operationType = this.lambda.operationType || "ISR";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The Lambda runtime that custom runtimes must target.
3
+ *
4
+ * Builds run on Amazon Linux 2023, so this is a constant. It is deliberately
5
+ * not derived from the build host's `/etc/os-release`: `vercel build` also runs
6
+ * on developer machines and in CI, and the emitted runtime has to match the
7
+ * deploy target rather than wherever the build happened to run.
8
+ *
9
+ * This stays a function so that custom runtimes pick up any future base image
10
+ * migration without having to change their own code.
11
+ */
12
+ export declare function getProvidedRuntime(): Promise<'provided.al2023'>;
@@ -0,0 +1,30 @@
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 provided_runtime_exports = {};
20
+ __export(provided_runtime_exports, {
21
+ getProvidedRuntime: () => getProvidedRuntime
22
+ });
23
+ module.exports = __toCommonJS(provided_runtime_exports);
24
+ async function getProvidedRuntime() {
25
+ return "provided.al2023";
26
+ }
27
+ // Annotate the CommonJS export names for ESM import in node:
28
+ 0 && (module.exports = {
29
+ getProvidedRuntime
30
+ });
@@ -12,10 +12,11 @@ export declare function parseGemfileLock(content: string): {
12
12
  gems: Map<string, GemEntry>;
13
13
  directGems: Map<string, string | undefined>;
14
14
  };
15
- export declare function generateRubyProjectManifest({ workPath, gemfileLockPath, framework, serviceType, }: {
15
+ export declare function generateRubyProjectManifest({ workPath, gemfileLockPath, framework, serviceType, outputRuntime, }: {
16
16
  workPath: string;
17
17
  gemfileLockPath: string | undefined;
18
18
  framework?: string | null;
19
19
  serviceType?: string | null;
20
+ outputRuntime?: string;
20
21
  }): Promise<void>;
21
22
  export {};
@@ -154,7 +154,8 @@ async function generateRubyProjectManifest({
154
154
  workPath,
155
155
  gemfileLockPath,
156
156
  framework,
157
- serviceType
157
+ serviceType,
158
+ outputRuntime = "ruby"
158
159
  }) {
159
160
  try {
160
161
  if (!gemfileLockPath)
@@ -208,7 +209,7 @@ async function generateRubyProjectManifest({
208
209
  ...transitiveEntries.sort((a, b) => a.name.localeCompare(b.name))
209
210
  ]
210
211
  };
211
- await (0, import_package_manifest.writeProjectManifest)(manifest, workPath, "ruby");
212
+ await (0, import_package_manifest.writeProjectManifest)(manifest, workPath, outputRuntime);
212
213
  } catch {
213
214
  }
214
215
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/build-utils",
3
- "version": "13.36.3",
3
+ "version": "14.0.2",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",
@@ -13,7 +13,7 @@
13
13
  "dependencies": {
14
14
  "cjs-module-lexer": "1.2.3",
15
15
  "es-module-lexer": "1.5.0",
16
- "@vercel/python-analysis": "0.12.0"
16
+ "@vercel/python-analysis": "0.13.1"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/async-retry": "^1.2.1",
@@ -53,14 +53,14 @@
53
53
  "vitest": "2.0.1",
54
54
  "typescript": "4.9.5",
55
55
  "yazl": "2.5.1",
56
- "@vercel/routing-utils": "6.4.0",
57
- "@vercel/error-utils": "2.2.0"
56
+ "@vercel/error-utils": "2.2.1",
57
+ "@vercel/routing-utils": "6.4.1"
58
58
  },
59
59
  "scripts": {
60
60
  "build": "node build.mjs",
61
61
  "test": "vitest run --config ../../vitest.config.mts",
62
62
  "vitest-run": "vitest -c ../../vitest.config.mts",
63
- "vitest-unit": "glob --absolute 'test/unit.*test.ts'",
63
+ "vitest-unit": "pnpm vitest-run --run test/unit.",
64
64
  "vitest-e2e": "glob --absolute 'test/integration*.test.ts'",
65
65
  "type-check": "tsc --noEmit"
66
66
  }
package/dist/os.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export declare function getOsRelease(): Promise<Record<string, string> | null>;
2
- export declare function parseOsRelease(data: string): Promise<Record<string, string>>;
3
- export declare function getProvidedRuntime(): Promise<"provided.al2023" | "provided.al2">;
package/dist/os.js DELETED
@@ -1,62 +0,0 @@
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 os_exports = {};
20
- __export(os_exports, {
21
- getOsRelease: () => getOsRelease,
22
- getProvidedRuntime: () => getProvidedRuntime,
23
- parseOsRelease: () => parseOsRelease
24
- });
25
- module.exports = __toCommonJS(os_exports);
26
- var import_fs_extra = require("fs-extra");
27
- var import_error_utils = require("@vercel/error-utils");
28
- async function getOsRelease() {
29
- try {
30
- const data = await (0, import_fs_extra.readFile)("/etc/os-release", "utf8");
31
- return await parseOsRelease(data);
32
- } catch (err) {
33
- if ((0, import_error_utils.isErrnoException)(err) && err.code === "ENOENT") {
34
- return null;
35
- }
36
- throw err;
37
- }
38
- }
39
- async function parseOsRelease(data) {
40
- const obj = {};
41
- for (const line of data.trim().split("\n")) {
42
- const m = /(?<key>.*)="(?<value>.*)"/.exec(line);
43
- if (!m?.groups) {
44
- continue;
45
- }
46
- obj[m.groups.key] = m.groups.value;
47
- }
48
- return obj;
49
- }
50
- async function getProvidedRuntime() {
51
- const os = await getOsRelease();
52
- if (!os) {
53
- return "provided.al2023";
54
- }
55
- return os.PRETTY_NAME === "Amazon Linux 2" ? "provided.al2" : "provided.al2023";
56
- }
57
- // Annotate the CommonJS export names for ESM import in node:
58
- 0 && (module.exports = {
59
- getOsRelease,
60
- getProvidedRuntime,
61
- parseOsRelease
62
- });