@vercel/backends 0.0.27 → 0.0.28

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.
@@ -0,0 +1,301 @@
1
+ import { builtinModules } from "node:module";
2
+ import { FileBlob, FileFsRef, Span, isBackendFramework } from "@vercel/build-utils";
3
+ import { dirname, extname, join, relative } from "node:path";
4
+ import { existsSync } from "node:fs";
5
+ import { lstat, readFile } from "node:fs/promises";
6
+ import { build } from "rolldown";
7
+ import { nodeFileTrace } from "@vercel/nft";
8
+ import { isNativeError } from "node:util/types";
9
+ import { transform } from "oxc-transform";
10
+ import { exports } from "resolve.exports";
11
+
12
+ //#region src/rolldown/resolve-format.ts
13
+ const resolveEntrypointAndFormat = async (args) => {
14
+ const extension = extname(args.entrypoint);
15
+ const extensionMap = {
16
+ ".ts": {
17
+ format: "auto",
18
+ extension: "js"
19
+ },
20
+ ".mts": {
21
+ format: "esm",
22
+ extension: "mjs"
23
+ },
24
+ ".cts": {
25
+ format: "cjs",
26
+ extension: "cjs"
27
+ },
28
+ ".cjs": {
29
+ format: "cjs",
30
+ extension: "cjs"
31
+ },
32
+ ".js": {
33
+ format: "auto",
34
+ extension: "js"
35
+ },
36
+ ".mjs": {
37
+ format: "esm",
38
+ extension: "mjs"
39
+ }
40
+ };
41
+ const extensionInfo = extensionMap[extension] || extensionMap[".js"];
42
+ let resolvedFormat = extensionInfo.format === "auto" ? void 0 : extensionInfo.format;
43
+ const packageJsonPath = join(args.workPath, "package.json");
44
+ let pkg = {};
45
+ if (existsSync(packageJsonPath)) {
46
+ const source = await readFile(packageJsonPath, "utf8");
47
+ try {
48
+ pkg = JSON.parse(source.toString());
49
+ } catch (_e) {
50
+ pkg = {};
51
+ }
52
+ if (extensionInfo.format === "auto") if (pkg.type === "module") resolvedFormat = "esm";
53
+ else resolvedFormat = "cjs";
54
+ }
55
+ if (!resolvedFormat) throw new Error(`Unable to resolve format for ${args.entrypoint}`);
56
+ return {
57
+ format: resolvedFormat,
58
+ extension: resolvedFormat === "esm" ? "mjs" : "cjs"
59
+ };
60
+ };
61
+
62
+ //#endregion
63
+ //#region src/rolldown/nft.ts
64
+ const nft = async (args) => {
65
+ const nftSpan = args.span.child("vc.builder.backends.nft");
66
+ const runNft = async () => {
67
+ const nftResult = await nodeFileTrace(Array.from(args.localBuildFiles), {
68
+ base: args.repoRootPath,
69
+ processCwd: args.workPath,
70
+ ts: true,
71
+ mixedModules: true,
72
+ ignore: args.ignoreNodeModules ? (path) => path.includes("node_modules") : void 0,
73
+ async readFile(fsPath) {
74
+ try {
75
+ let source = await readFile(fsPath);
76
+ if (isTypeScriptFile(fsPath)) source = (await transform(fsPath, source.toString())).code;
77
+ return source;
78
+ } catch (error) {
79
+ if (isNativeError(error) && "code" in error && (error.code === "ENOENT" || error.code === "EISDIR")) return null;
80
+ throw error;
81
+ }
82
+ }
83
+ });
84
+ for (const file of nftResult.fileList) {
85
+ const absolutePath = join(args.repoRootPath, file);
86
+ const stats = await lstat(absolutePath);
87
+ const outputPath = file;
88
+ if (args.localBuildFiles.has(join(args.repoRootPath, outputPath))) continue;
89
+ if (stats.isSymbolicLink() || stats.isFile()) if (args.ignoreNodeModules) {
90
+ const content = await readFile(absolutePath, "utf-8");
91
+ args.files[outputPath] = new FileBlob({
92
+ data: content,
93
+ mode: stats.mode
94
+ });
95
+ } else args.files[outputPath] = new FileFsRef({
96
+ fsPath: absolutePath,
97
+ mode: stats.mode
98
+ });
99
+ }
100
+ };
101
+ await nftSpan.trace(runNft);
102
+ };
103
+ const isTypeScriptFile = (fsPath) => {
104
+ return fsPath.endsWith(".ts") || fsPath.endsWith(".tsx") || fsPath.endsWith(".mts") || fsPath.endsWith(".cts");
105
+ };
106
+
107
+ //#endregion
108
+ //#region src/rolldown/index.ts
109
+ const PLUGIN_NAME = "vercel:backends";
110
+ const CJS_SHIM_PREFIX = "\0cjs-shim:";
111
+ const rolldown = async (args) => {
112
+ const files = {};
113
+ const { format, extension } = await resolveEntrypointAndFormat(args);
114
+ const localBuildFiles = /* @__PURE__ */ new Set();
115
+ let handler = null;
116
+ const packageJsonCache = /* @__PURE__ */ new Map();
117
+ const shimMeta = /* @__PURE__ */ new Map();
118
+ const framework = {
119
+ slug: "",
120
+ version: ""
121
+ };
122
+ const getPackageJson = async (pkgPath) => {
123
+ if (packageJsonCache.has(pkgPath)) return packageJsonCache.get(pkgPath);
124
+ try {
125
+ const contents = await readFile(pkgPath, "utf-8");
126
+ const parsed = JSON.parse(contents);
127
+ packageJsonCache.set(pkgPath, parsed);
128
+ return parsed;
129
+ } catch {
130
+ packageJsonCache.set(pkgPath, null);
131
+ return null;
132
+ }
133
+ };
134
+ const isCommonJS = async (bareImport, resolvedPath, resolvedInfo) => {
135
+ const ext = extname(resolvedPath);
136
+ if (ext === ".cjs") return true;
137
+ if (ext === ".mjs") return false;
138
+ if (ext === ".js" || ext === ".ts") {
139
+ const pkgJsonPath = resolvedInfo.packageJsonPath;
140
+ if (!pkgJsonPath) return true;
141
+ const pkgJson = await getPackageJson(pkgJsonPath);
142
+ if (!pkgJson) return true;
143
+ const pkgDir = dirname(pkgJsonPath);
144
+ const relativePath = resolvedPath.slice(pkgDir.length + 1).replace(/\\/g, "/");
145
+ const pkgName = pkgJson.name || "";
146
+ const subpath = bareImport.startsWith(pkgName) ? `.${bareImport.slice(pkgName.length)}` || "." : ".";
147
+ try {
148
+ if (exports(pkgJson, subpath, {
149
+ require: false,
150
+ conditions: ["node", "import"]
151
+ })?.some((p) => p === relativePath || p === `./${relativePath}`)) return false;
152
+ if (exports(pkgJson, subpath, {
153
+ require: true,
154
+ conditions: ["node", "require"]
155
+ })?.some((p) => p === relativePath || p === `./${relativePath}`)) return true;
156
+ } catch {}
157
+ if (pkgJson.module) return false;
158
+ return pkgJson.type !== "module";
159
+ }
160
+ return true;
161
+ };
162
+ const isBareImport = (id) => {
163
+ return !id.startsWith(".") && !id.startsWith("/") && !/^[a-z][a-z0-9+.-]*:/i.test(id);
164
+ };
165
+ const isNodeModule = (resolved) => {
166
+ return resolved?.id?.includes("node_modules") ?? false;
167
+ };
168
+ const isNodeBuiltin = (id) => {
169
+ const normalizedId = id.includes(":") ? id.split(":")[1] : id;
170
+ return builtinModules.includes(normalizedId);
171
+ };
172
+ const isLocalImport = (id) => {
173
+ return !id.startsWith("node:") && !id.includes("node_modules");
174
+ };
175
+ const plugin = () => {
176
+ return {
177
+ name: PLUGIN_NAME,
178
+ resolveId: {
179
+ order: "pre",
180
+ async handler(id, importer, rOpts) {
181
+ if (id.startsWith(CJS_SHIM_PREFIX)) return {
182
+ id,
183
+ external: false
184
+ };
185
+ const resolved = await this.resolve(id, importer, rOpts);
186
+ if (isNodeBuiltin(id)) return {
187
+ id: id.startsWith("node:") ? id : `node:${id}`,
188
+ external: true
189
+ };
190
+ if (resolved?.id && isLocalImport(resolved.id)) localBuildFiles.add(resolved.id);
191
+ else if (!resolved) localBuildFiles.add(join(args.workPath, id));
192
+ if (importer?.startsWith(CJS_SHIM_PREFIX) && isBareImport(id)) return {
193
+ id,
194
+ external: true
195
+ };
196
+ if (importer && isBareImport(id) && isNodeModule(resolved)) {
197
+ if (isBackendFramework(id) && resolved?.packageJsonPath) try {
198
+ const pkg = await readFile(resolved.packageJsonPath, "utf8");
199
+ const pkgJson = JSON.parse(pkg);
200
+ framework.slug = pkgJson.name;
201
+ framework.version = pkgJson.version;
202
+ } catch {}
203
+ if (resolved ? await isCommonJS(id, resolved.id, resolved) : false) {
204
+ const importerPkgJsonPath = (await this.resolve(importer))?.packageJsonPath;
205
+ if (importerPkgJsonPath) {
206
+ const importerPkgDir = relative(args.repoRootPath, dirname(importerPkgJsonPath));
207
+ const shimId$1 = `${CJS_SHIM_PREFIX}${importerPkgDir.replace(/\//g, "_")}_${id.replace(/\//g, "_")}`;
208
+ shimMeta.set(shimId$1, {
209
+ pkgDir: importerPkgDir,
210
+ pkgName: id
211
+ });
212
+ return {
213
+ id: shimId$1,
214
+ external: false
215
+ };
216
+ }
217
+ const shimId = `${CJS_SHIM_PREFIX}${id.replace(/\//g, "_")}`;
218
+ shimMeta.set(shimId, {
219
+ pkgDir: "",
220
+ pkgName: id
221
+ });
222
+ return {
223
+ id: shimId,
224
+ external: false
225
+ };
226
+ }
227
+ return {
228
+ id,
229
+ external: true
230
+ };
231
+ }
232
+ if (importer && isBareImport(id)) return resolved;
233
+ if (resolved && !isNodeModule(resolved)) return resolved;
234
+ return resolved;
235
+ }
236
+ },
237
+ load: { async handler(id) {
238
+ if (id.startsWith(CJS_SHIM_PREFIX)) {
239
+ const meta = shimMeta.get(id);
240
+ if (!meta) return { code: `module.exports = require('${id.slice(10)}');` };
241
+ const { pkgDir, pkgName } = meta;
242
+ return { code: `
243
+ import { createRequire } from 'node:module';
244
+ import { fileURLToPath } from 'node:url';
245
+ import { dirname, join } from 'node:path';
246
+
247
+ const requireFromContext = createRequire(join(dirname(fileURLToPath(import.meta.url)), '${pkgDir ? join("..", pkgDir, "package.json") : "../package.json"}'));
248
+ module.exports = requireFromContext('${pkgName}');
249
+ `.trim() };
250
+ }
251
+ return null;
252
+ } }
253
+ };
254
+ };
255
+ const runRolldown = () => build({
256
+ input: args.entrypoint,
257
+ write: false,
258
+ cwd: args.workPath,
259
+ platform: "node",
260
+ transform: { define: format === "esm" ? {
261
+ __dirname: "import.meta.dirname",
262
+ __filename: "import.meta.filename"
263
+ } : void 0 },
264
+ tsconfig: true,
265
+ plugins: [plugin()],
266
+ output: {
267
+ cleanDir: true,
268
+ format,
269
+ entryFileNames: `[name].${extension}`,
270
+ preserveModules: true,
271
+ preserveModulesRoot: args.repoRootPath,
272
+ sourcemap: false
273
+ }
274
+ });
275
+ const rolldownSpan = args.span?.child("vc.builder.backends.rolldown");
276
+ const out = await rolldownSpan?.trace(runRolldown) || await runRolldown();
277
+ for (const file of out.output) if (file.type === "chunk") {
278
+ if (file.isEntry) handler = file.fileName;
279
+ files[file.fileName] = new FileBlob({
280
+ data: file.code,
281
+ mode: 420
282
+ });
283
+ }
284
+ await nft({
285
+ ...args,
286
+ localBuildFiles,
287
+ files,
288
+ span: rolldownSpan ?? new Span({ name: "vc.builder.backends.nft" }),
289
+ ignoreNodeModules: true
290
+ });
291
+ if (!handler) throw new Error(`Unable to resolve build handler for entrypoint: ${args.entrypoint}`);
292
+ return {
293
+ files,
294
+ handler,
295
+ framework,
296
+ localBuildFiles
297
+ };
298
+ };
299
+
300
+ //#endregion
301
+ export { rolldown };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/backends",
3
- "version": "0.0.27",
3
+ "version": "0.0.28",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index.mjs",
6
6
  "homepage": "https://vercel.com/docs",
@@ -11,11 +11,9 @@
11
11
  "exports": {
12
12
  ".": "./dist/index.mjs",
13
13
  "./package.json": "./package.json",
14
- "./introspection/loaders/cjs": "./dist/introspection/loaders/cjs.cjs",
15
- "./introspection/loaders/esm": "./dist/introspection/loaders/esm.mjs",
16
- "./introspection/loaders/hooks": "./dist/introspection/loaders/hooks.mjs",
17
- "./introspection/loaders/rolldown-esm": "./dist/introspection/loaders/rolldown-esm.mjs",
18
- "./introspection/loaders/rolldown-hooks": "./dist/introspection/loaders/rolldown-hooks.mjs"
14
+ "./rolldown/esm": "./dist/rolldown/esm.mjs",
15
+ "./rolldown/hooks": "./dist/rolldown/hooks.mjs",
16
+ "./rolldown/cjs-hooks": "./dist/rolldown/cjs-hooks.cjs"
19
17
  },
20
18
  "repository": {
21
19
  "type": "git",
@@ -36,7 +34,7 @@
36
34
  "srvx": "0.8.9",
37
35
  "tsx": "4.21.0",
38
36
  "zod": "3.22.4",
39
- "@vercel/build-utils": "13.3.0"
37
+ "@vercel/build-utils": "13.3.1"
40
38
  },
41
39
  "peerDependencies": {
42
40
  "typescript": "^4.0.0 || ^5.0.0"