@vercel/backends 0.8.6 → 0.8.7

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/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { basename, delimiter, dirname, extname, isAbsolute, join, posix, relativ
3
3
  import { delimiter as delimiter$1, dirname as dirname$1, join as join$1 } from "path";
4
4
  import { FileBlob, FileFsRef, NodejsLambda, Span, createDiagnostics, debug, defaultCachePathGlob, download, execCommand, generateProjectManifest, getEnvForPackageManager, getInternalServiceCronPath, getLambdaOptionsFromFunction, getNodeBinPaths, getNodeVersion, getReportedServiceType, glob, isBackendFramework, isBunVersion, isExperimentalBackendsWithoutIntrospectionEnabled, isScheduleTriggeredService, runNpmInstall, runPackageJsonScript, scanParentDirs } from "@vercel/build-utils";
5
5
  import { createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
6
- import { lstat, readFile, rm, stat } from "node:fs/promises";
6
+ import { lstat, readFile, readlink, rm, stat } from "node:fs/promises";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { build as build$2 } from "rolldown";
9
9
  import { exports } from "resolve.exports";
@@ -973,8 +973,13 @@ const srvxOptions = {
973
973
  const nft = async (args) => {
974
974
  const nftSpan = args.span.child("vc.builder.backends.nft");
975
975
  const runNft = async () => {
976
+ const virtualFiles = /* @__PURE__ */ new Map();
977
+ if (args.traceFiles) for (const [relPath, file] of Object.entries(args.files)) {
978
+ if (!isJsLikeExtension(relPath) || file.type !== "FileBlob") continue;
979
+ virtualFiles.set(join(args.repoRootPath, relPath), typeof file.data === "string" ? file.data : Buffer.from(new Uint8Array(file.data)));
980
+ }
976
981
  const ignorePatterns = [...args.ignoreNodeModules ? ["**/node_modules/**"] : [], ...args.ignore ? Array.isArray(args.ignore) ? args.ignore : [args.ignore] : []];
977
- const nftResult = await nodeFileTrace$1(Array.from(args.localBuildFiles).filter((p) => existsSync(p)), {
982
+ const nftResult = await nodeFileTrace$1([...Array.from(args.localBuildFiles).filter((p) => existsSync(p) || virtualFiles.has(p)), ...virtualFiles.keys()], {
978
983
  base: args.repoRootPath,
979
984
  processCwd: args.workPath,
980
985
  ts: true,
@@ -982,7 +987,26 @@ const nft = async (args) => {
982
987
  moduleSyncCatchall: true,
983
988
  conditions: args.conditions,
984
989
  ignore: ignorePatterns.length > 0 ? ignorePatterns : void 0,
990
+ async stat(fsPath) {
991
+ if (virtualFiles.has(fsPath)) return createVirtualFileStat(virtualFiles.get(fsPath));
992
+ try {
993
+ return await stat(fsPath);
994
+ } catch (error) {
995
+ if (isNativeError(error) && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")) return null;
996
+ throw error;
997
+ }
998
+ },
999
+ async readlink(fsPath) {
1000
+ if (virtualFiles.has(fsPath)) return null;
1001
+ try {
1002
+ return await readlink(fsPath);
1003
+ } catch (error) {
1004
+ if (isNativeError(error) && "code" in error && (error.code === "EINVAL" || error.code === "ENOENT" || error.code === "ENOTDIR")) return null;
1005
+ throw error;
1006
+ }
1007
+ },
985
1008
  async readFile(fsPath) {
1009
+ if (virtualFiles.has(fsPath)) return virtualFiles.get(fsPath);
986
1010
  try {
987
1011
  let source = await readFile(fsPath);
988
1012
  if (isTypeScriptFile(fsPath)) source = (await transform(fsPath, source.toString())).code;
@@ -995,6 +1019,7 @@ const nft = async (args) => {
995
1019
  });
996
1020
  for (const file of nftResult.fileList) {
997
1021
  const absolutePath = join(args.repoRootPath, file);
1022
+ if (virtualFiles.has(absolutePath)) continue;
998
1023
  let stats;
999
1024
  try {
1000
1025
  stats = await lstat(absolutePath);
@@ -1002,7 +1027,7 @@ const nft = async (args) => {
1002
1027
  if (isNativeError(error) && "code" in error && error.code === "ENOENT") continue;
1003
1028
  throw error;
1004
1029
  }
1005
- const outputPath = file;
1030
+ const outputPath = file.split(sep).join("/");
1006
1031
  if (args.localBuildFiles.has(join(args.repoRootPath, outputPath))) continue;
1007
1032
  if (stats.isSymbolicLink() || stats.isFile()) if (args.ignoreNodeModules) {
1008
1033
  if ((stats.isSymbolicLink() ? await stat(absolutePath) : stats).isFile()) {
@@ -1020,6 +1045,53 @@ const nft = async (args) => {
1020
1045
  };
1021
1046
  await nftSpan.trace(runNft);
1022
1047
  };
1048
+ const JS_LIKE_EXTENSIONS = new Set([
1049
+ ".js",
1050
+ ".cjs",
1051
+ ".mjs",
1052
+ ".ts",
1053
+ ".cts",
1054
+ ".mts",
1055
+ ".tsx",
1056
+ ".jsx",
1057
+ ".json",
1058
+ ".node"
1059
+ ]);
1060
+ const isJsLikeExtension = (path) => {
1061
+ const dot = path.lastIndexOf(".");
1062
+ if (dot === -1) return false;
1063
+ return JS_LIKE_EXTENSIONS.has(path.slice(dot).toLowerCase());
1064
+ };
1065
+ const createVirtualFileStat = (data) => {
1066
+ const now = /* @__PURE__ */ new Date();
1067
+ return {
1068
+ isFile: () => true,
1069
+ isDirectory: () => false,
1070
+ isBlockDevice: () => false,
1071
+ isCharacterDevice: () => false,
1072
+ isSymbolicLink: () => false,
1073
+ isFIFO: () => false,
1074
+ isSocket: () => false,
1075
+ dev: 0,
1076
+ ino: 0,
1077
+ mode: 33188,
1078
+ nlink: 1,
1079
+ uid: 0,
1080
+ gid: 0,
1081
+ rdev: 0,
1082
+ size: typeof data === "string" ? Buffer.byteLength(data) : data.length,
1083
+ blksize: 4096,
1084
+ blocks: 1,
1085
+ atimeMs: now.getTime(),
1086
+ mtimeMs: now.getTime(),
1087
+ ctimeMs: now.getTime(),
1088
+ birthtimeMs: now.getTime(),
1089
+ atime: now,
1090
+ mtime: now,
1091
+ ctime: now,
1092
+ birthtime: now
1093
+ };
1094
+ };
1023
1095
  const isTypeScriptFile = (fsPath) => {
1024
1096
  if (fsPath.endsWith(".d.ts") || fsPath.endsWith(".d.mts") || fsPath.endsWith(".d.cts")) return false;
1025
1097
  return fsPath.endsWith(".ts") || fsPath.endsWith(".tsx") || fsPath.endsWith(".mts") || fsPath.endsWith(".cts");
@@ -1745,6 +1817,7 @@ const build = async (args) => {
1745
1817
  ignoreNodeModules: false,
1746
1818
  ignore: args.config.excludeFiles,
1747
1819
  conditions: isBun ? ["bun"] : void 0,
1820
+ traceFiles: true,
1748
1821
  span: buildSpan
1749
1822
  });
1750
1823
  try {
@@ -1,8 +1,8 @@
1
1
  import { builtinModules } from "node:module";
2
2
  import { FileBlob, FileFsRef, Span, isBackendFramework } from "@vercel/build-utils";
3
- import { dirname, extname, join, relative } from "node:path";
3
+ import { dirname, extname, join, relative, sep } from "node:path";
4
4
  import { existsSync } from "node:fs";
5
- import { lstat, readFile, stat } from "node:fs/promises";
5
+ import { lstat, readFile, readlink, stat } from "node:fs/promises";
6
6
  import { build } from "rolldown";
7
7
  import { nodeFileTrace } from "@vercel/nft";
8
8
  import { isNativeError } from "node:util/types";
@@ -93,8 +93,13 @@ const resolveEntrypointAndFormat = async (args) => {
93
93
  const nft = async (args) => {
94
94
  const nftSpan = args.span.child("vc.builder.backends.nft");
95
95
  const runNft = async () => {
96
+ const virtualFiles = /* @__PURE__ */ new Map();
97
+ if (args.traceFiles) for (const [relPath, file] of Object.entries(args.files)) {
98
+ if (!isJsLikeExtension(relPath) || file.type !== "FileBlob") continue;
99
+ virtualFiles.set(join(args.repoRootPath, relPath), typeof file.data === "string" ? file.data : Buffer.from(new Uint8Array(file.data)));
100
+ }
96
101
  const ignorePatterns = [...args.ignoreNodeModules ? ["**/node_modules/**"] : [], ...args.ignore ? Array.isArray(args.ignore) ? args.ignore : [args.ignore] : []];
97
- const nftResult = await nodeFileTrace(Array.from(args.localBuildFiles).filter((p) => existsSync(p)), {
102
+ const nftResult = await nodeFileTrace([...Array.from(args.localBuildFiles).filter((p) => existsSync(p) || virtualFiles.has(p)), ...virtualFiles.keys()], {
98
103
  base: args.repoRootPath,
99
104
  processCwd: args.workPath,
100
105
  ts: true,
@@ -102,7 +107,26 @@ const nft = async (args) => {
102
107
  moduleSyncCatchall: true,
103
108
  conditions: args.conditions,
104
109
  ignore: ignorePatterns.length > 0 ? ignorePatterns : void 0,
110
+ async stat(fsPath) {
111
+ if (virtualFiles.has(fsPath)) return createVirtualFileStat(virtualFiles.get(fsPath));
112
+ try {
113
+ return await stat(fsPath);
114
+ } catch (error) {
115
+ if (isNativeError(error) && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")) return null;
116
+ throw error;
117
+ }
118
+ },
119
+ async readlink(fsPath) {
120
+ if (virtualFiles.has(fsPath)) return null;
121
+ try {
122
+ return await readlink(fsPath);
123
+ } catch (error) {
124
+ if (isNativeError(error) && "code" in error && (error.code === "EINVAL" || error.code === "ENOENT" || error.code === "ENOTDIR")) return null;
125
+ throw error;
126
+ }
127
+ },
105
128
  async readFile(fsPath) {
129
+ if (virtualFiles.has(fsPath)) return virtualFiles.get(fsPath);
106
130
  try {
107
131
  let source = await readFile(fsPath);
108
132
  if (isTypeScriptFile(fsPath)) source = (await transform(fsPath, source.toString())).code;
@@ -115,6 +139,7 @@ const nft = async (args) => {
115
139
  });
116
140
  for (const file of nftResult.fileList) {
117
141
  const absolutePath = join(args.repoRootPath, file);
142
+ if (virtualFiles.has(absolutePath)) continue;
118
143
  let stats;
119
144
  try {
120
145
  stats = await lstat(absolutePath);
@@ -122,7 +147,7 @@ const nft = async (args) => {
122
147
  if (isNativeError(error) && "code" in error && error.code === "ENOENT") continue;
123
148
  throw error;
124
149
  }
125
- const outputPath = file;
150
+ const outputPath = file.split(sep).join("/");
126
151
  if (args.localBuildFiles.has(join(args.repoRootPath, outputPath))) continue;
127
152
  if (stats.isSymbolicLink() || stats.isFile()) if (args.ignoreNodeModules) {
128
153
  if ((stats.isSymbolicLink() ? await stat(absolutePath) : stats).isFile()) {
@@ -140,6 +165,53 @@ const nft = async (args) => {
140
165
  };
141
166
  await nftSpan.trace(runNft);
142
167
  };
168
+ const JS_LIKE_EXTENSIONS = new Set([
169
+ ".js",
170
+ ".cjs",
171
+ ".mjs",
172
+ ".ts",
173
+ ".cts",
174
+ ".mts",
175
+ ".tsx",
176
+ ".jsx",
177
+ ".json",
178
+ ".node"
179
+ ]);
180
+ const isJsLikeExtension = (path) => {
181
+ const dot = path.lastIndexOf(".");
182
+ if (dot === -1) return false;
183
+ return JS_LIKE_EXTENSIONS.has(path.slice(dot).toLowerCase());
184
+ };
185
+ const createVirtualFileStat = (data) => {
186
+ const now = /* @__PURE__ */ new Date();
187
+ return {
188
+ isFile: () => true,
189
+ isDirectory: () => false,
190
+ isBlockDevice: () => false,
191
+ isCharacterDevice: () => false,
192
+ isSymbolicLink: () => false,
193
+ isFIFO: () => false,
194
+ isSocket: () => false,
195
+ dev: 0,
196
+ ino: 0,
197
+ mode: 33188,
198
+ nlink: 1,
199
+ uid: 0,
200
+ gid: 0,
201
+ rdev: 0,
202
+ size: typeof data === "string" ? Buffer.byteLength(data) : data.length,
203
+ blksize: 4096,
204
+ blocks: 1,
205
+ atimeMs: now.getTime(),
206
+ mtimeMs: now.getTime(),
207
+ ctimeMs: now.getTime(),
208
+ birthtimeMs: now.getTime(),
209
+ atime: now,
210
+ mtime: now,
211
+ ctime: now,
212
+ birthtime: now
213
+ };
214
+ };
143
215
  const isTypeScriptFile = (fsPath) => {
144
216
  if (fsPath.endsWith(".d.ts") || fsPath.endsWith(".d.mts") || fsPath.endsWith(".d.cts")) return false;
145
217
  return fsPath.endsWith(".ts") || fsPath.endsWith(".tsx") || fsPath.endsWith(".mts") || fsPath.endsWith(".cts");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/backends",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index.mjs",
6
6
  "homepage": "https://vercel.com/docs",
@@ -36,7 +36,7 @@
36
36
  "srvx": "0.8.9",
37
37
  "tsx": "4.21.0",
38
38
  "zod": "3.22.4",
39
- "@vercel/build-utils": "13.27.0"
39
+ "@vercel/build-utils": "13.27.1"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/express": "5.0.3",