@vercel/rust 0.0.0-canary.0

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.
Files changed (2) hide show
  1. package/dist/index.js +428 -0
  2. package/package.json +45 -0
package/dist/index.js ADDED
@@ -0,0 +1,428 @@
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
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ build: () => build,
34
+ prepareCache: () => prepareCache,
35
+ shouldServe: () => shouldServe,
36
+ startDevServer: () => startDevServer2,
37
+ version: () => version
38
+ });
39
+ module.exports = __toCommonJS(src_exports);
40
+ var import_node_path4 = __toESM(require("path"));
41
+ var import_build_utils6 = require("@vercel/build-utils");
42
+ var import_execa4 = __toESM(require("execa"));
43
+
44
+ // src/lib/rust-toolchain.ts
45
+ var import_build_utils = require("@vercel/build-utils");
46
+ var import_execa = __toESM(require("execa"));
47
+ async function downloadRustToolchain() {
48
+ try {
49
+ await (0, import_execa.default)(
50
+ `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y`,
51
+ [],
52
+ { shell: true, stdio: "inherit" }
53
+ );
54
+ } catch (err) {
55
+ let message = "Unknown Error";
56
+ if (err instanceof Error) {
57
+ message = err.message;
58
+ }
59
+ throw new Error(`Installing Rust Toolchain via rustup failed: ${message}`);
60
+ }
61
+ }
62
+ var installRustToolchain = async () => {
63
+ try {
64
+ await (0, import_execa.default)(`rustup -V`, [], { shell: true, stdio: "ignore" });
65
+ (0, import_build_utils.debug)("Rust Toolchain is already installed, skipping download");
66
+ } catch (err) {
67
+ await downloadRustToolchain();
68
+ }
69
+ };
70
+
71
+ // src/lib/cargo.ts
72
+ var import_node_fs = __toESM(require("fs"));
73
+ var import_node_path = __toESM(require("path"));
74
+ var import_toml = __toESM(require("@iarna/toml"));
75
+ var import_execa2 = __toESM(require("execa"));
76
+ async function getCargoMetadata(options) {
77
+ const { stdout: cargoMetaData } = await (0, import_execa2.default)(
78
+ "cargo",
79
+ ["metadata", "--format-version", "1"],
80
+ options
81
+ );
82
+ return JSON.parse(cargoMetaData);
83
+ }
84
+ async function findCargoWorkspace(config) {
85
+ const { stdout: projectDescriptionStr } = await (0, import_execa2.default)(
86
+ "cargo",
87
+ ["locate-project"],
88
+ config
89
+ );
90
+ const projectDescription = JSON.parse(projectDescriptionStr);
91
+ return {
92
+ toml: await import_toml.default.parse.stream(import_node_fs.default.createReadStream(projectDescription.root)),
93
+ root: projectDescription.root
94
+ };
95
+ }
96
+ async function findCargoBuildConfiguration(workspace) {
97
+ const configPath = import_node_path.default.join(
98
+ import_node_path.default.dirname(workspace.root),
99
+ ".cargo/config.toml"
100
+ );
101
+ if (!import_node_fs.default.existsSync(configPath)) {
102
+ return null;
103
+ }
104
+ const config = await import_toml.default.parse.stream(import_node_fs.default.createReadStream(configPath));
105
+ return config;
106
+ }
107
+ function findBinaryName(workspace, entryPath) {
108
+ const { bin } = workspace.toml;
109
+ if (bin) {
110
+ const relativePath = import_node_path.default.relative(import_node_path.default.dirname(workspace.root), entryPath);
111
+ const entry = bin.find((binEntry) => binEntry.path === relativePath);
112
+ if (entry?.name) {
113
+ return entry.name;
114
+ }
115
+ }
116
+ return import_node_path.default.basename(entryPath, ".rs").replace("[", "_").replace("]", "_");
117
+ }
118
+
119
+ // src/lib/utils.ts
120
+ var import_node_fs2 = __toESM(require("fs"));
121
+ var import_node_path2 = __toESM(require("path"));
122
+ var import_build_utils2 = require("@vercel/build-utils");
123
+ function getExecutableName(binName) {
124
+ return process.platform === "win32" ? `${binName}.exe` : binName;
125
+ }
126
+ function assertEnv(name) {
127
+ if (!process.env[name]) {
128
+ throw new Error(`Missing ENV variable process.env.${name}`);
129
+ }
130
+ return process.env[name];
131
+ }
132
+ async function runUserScripts(dir) {
133
+ const buildScriptPath = import_node_path2.default.join(dir, "build.sh");
134
+ const buildScriptExists = import_node_fs2.default.existsSync(buildScriptPath);
135
+ if (buildScriptExists) {
136
+ (0, import_build_utils2.debug)("Running `build.sh`");
137
+ await (0, import_build_utils2.runShellScript)(buildScriptPath);
138
+ }
139
+ }
140
+ async function gatherExtraFiles(globMatcher, workPath) {
141
+ if (!globMatcher)
142
+ return {};
143
+ (0, import_build_utils2.debug)(
144
+ `Gathering extra files for glob \`${JSON.stringify(
145
+ globMatcher
146
+ )}\` in ${workPath}`
147
+ );
148
+ if (Array.isArray(globMatcher)) {
149
+ const allMatches = await Promise.all(
150
+ globMatcher.map((pattern) => (0, import_build_utils2.glob)(pattern, workPath))
151
+ );
152
+ return allMatches.reduce((acc, matches) => ({ ...acc, ...matches }), {});
153
+ }
154
+ return (0, import_build_utils2.glob)(globMatcher, workPath);
155
+ }
156
+
157
+ // src/lib/start-dev-server.ts
158
+ var import_child_process = require("child_process");
159
+ var import_events = require("events");
160
+ var import_build_utils5 = require("@vercel/build-utils");
161
+
162
+ // src/lib/dev-build.ts
163
+ var import_node_path3 = __toESM(require("path"));
164
+ var import_execa3 = __toESM(require("execa"));
165
+ var import_build_utils3 = require("@vercel/build-utils");
166
+ async function buildExecutableForDev(workPath, entrypoint) {
167
+ (0, import_build_utils3.debug)(`Building executable for development: ${entrypoint}`);
168
+ const HOME = process.platform === "win32" ? assertEnv("USERPROFILE") : assertEnv("HOME");
169
+ const PATH = assertEnv("PATH");
170
+ const rustEnv = {
171
+ PATH: `${import_node_path3.default.join(HOME, ".cargo/bin")}${import_node_path3.default.delimiter}${PATH}`,
172
+ RUSTFLAGS: [process.env.RUSTFLAGS].filter(Boolean).join(" ")
173
+ };
174
+ const entryPath = import_node_path3.default.join(workPath, entrypoint);
175
+ const cargoWorkspace = await findCargoWorkspace({
176
+ env: rustEnv,
177
+ cwd: import_node_path3.default.dirname(entryPath)
178
+ });
179
+ const binaryName = findBinaryName(cargoWorkspace, entryPath);
180
+ (0, import_build_utils3.debug)(`Building binary "${binaryName}" in debug mode for dev server`);
181
+ try {
182
+ await (0, import_execa3.default)(
183
+ "cargo",
184
+ [
185
+ "build",
186
+ "--bin",
187
+ binaryName,
188
+ "--message-format=json-diagnostic-rendered-ansi"
189
+ ],
190
+ {
191
+ cwd: workPath,
192
+ env: rustEnv,
193
+ stdio: "pipe"
194
+ }
195
+ );
196
+ } catch (err) {
197
+ (0, import_build_utils3.debug)(`Cargo build failed for ${binaryName}`);
198
+ throw new Error(`Failed to build Rust binary for development: ${err}`);
199
+ }
200
+ const { target_directory: targetDirectory } = await getCargoMetadata({
201
+ cwd: workPath,
202
+ env: rustEnv
203
+ });
204
+ const executablePath = import_node_path3.default.join(
205
+ targetDirectory,
206
+ "debug",
207
+ getExecutableName(binaryName)
208
+ );
209
+ (0, import_build_utils3.debug)(`Built executable at: ${executablePath}`);
210
+ return executablePath;
211
+ }
212
+
213
+ // src/lib/dev-server.ts
214
+ var import_build_utils4 = require("@vercel/build-utils");
215
+ function createDevServerEnv(baseEnv, meta = {}) {
216
+ const devEnv = {
217
+ // Base environment
218
+ ...Object.fromEntries(
219
+ Object.entries(baseEnv).filter(([, value]) => value !== void 0)
220
+ ),
221
+ // Development-specific variables
222
+ VERCEL_DEV: "1",
223
+ RUST_LOG: process.env.RUST_LOG || "info",
224
+ // Runtime environment from meta
225
+ ...meta.env || {}
226
+ };
227
+ Object.keys(devEnv).forEach((key) => {
228
+ if (devEnv[key] === void 0) {
229
+ delete devEnv[key];
230
+ }
231
+ });
232
+ (0, import_build_utils4.debug)(`Dev server environment: ${Object.keys(devEnv).join(", ")}`);
233
+ return devEnv;
234
+ }
235
+
236
+ // src/lib/start-dev-server.ts
237
+ var startDevServer = async (opts) => {
238
+ const { entrypoint, workPath, meta = {} } = opts;
239
+ try {
240
+ await installRustToolchain();
241
+ const executablePath = await buildExecutableForDev(workPath, entrypoint);
242
+ (0, import_build_utils5.debug)(`Starting Rust dev server: ${executablePath}`);
243
+ const devEnv = createDevServerEnv(process.env, meta);
244
+ const child = (0, import_child_process.spawn)(executablePath, [], {
245
+ cwd: workPath,
246
+ env: devEnv,
247
+ stdio: ["pipe", "pipe", "pipe"]
248
+ });
249
+ if (!child.pid) {
250
+ throw new Error("Failed to start dev server process");
251
+ }
252
+ (0, import_build_utils5.debug)(`Dev server process started with PID: ${child.pid}`);
253
+ let buffer = "";
254
+ let portEmitted = false;
255
+ child.stdout?.on("data", (data) => {
256
+ const output = data.toString();
257
+ buffer += output;
258
+ if (!portEmitted && buffer.includes("Dev server listening:")) {
259
+ const portMatch = buffer.match(/Dev server listening: (\d+)/);
260
+ if (portMatch) {
261
+ const port = parseInt(portMatch[1], 10);
262
+ (0, import_build_utils5.debug)(
263
+ `Rust dev server detected port ${port}, emitting message event`
264
+ );
265
+ child.emit("message", { port }, null);
266
+ portEmitted = true;
267
+ }
268
+ buffer = "";
269
+ }
270
+ console.log(output);
271
+ });
272
+ child.stderr?.on("data", (data) => {
273
+ console.error(data.toString());
274
+ });
275
+ child.on("error", (err) => {
276
+ (0, import_build_utils5.debug)(`Dev server error: ${err}`);
277
+ });
278
+ child.on("exit", (code, signal) => {
279
+ (0, import_build_utils5.debug)(`Dev server exited with code ${code}, signal ${signal}`);
280
+ });
281
+ const onMessage = (0, import_events.once)(child, "message");
282
+ const onExit = (0, import_events.once)(child, "close");
283
+ const result = await Promise.race([
284
+ onMessage.then((args) => {
285
+ const [messageData] = args;
286
+ return { state: "message", value: messageData };
287
+ }),
288
+ onExit.then((args) => {
289
+ const [code, signal] = args;
290
+ return { state: "exit", value: [code, signal] };
291
+ })
292
+ ]);
293
+ if (result.state === "message") {
294
+ const { port } = result.value;
295
+ (0, import_build_utils5.debug)(`Rust dev server ready on port ${port}`);
296
+ if (!child.pid) {
297
+ throw new Error("Child process has no PID");
298
+ }
299
+ const shutdown = async () => {
300
+ try {
301
+ process.kill(child.pid, "SIGTERM");
302
+ } catch (err) {
303
+ (0, import_build_utils5.debug)(`Error terminating Rust dev server: ${err}`);
304
+ }
305
+ };
306
+ return { port, pid: child.pid, shutdown };
307
+ } else {
308
+ const [exitCode, signal] = result.value;
309
+ const reason = signal ? `"${signal}" signal` : `exit code ${exitCode}`;
310
+ throw new Error(`Rust dev server failed with ${reason}`);
311
+ }
312
+ } catch (error) {
313
+ (0, import_build_utils5.debug)(`Failed to start dev server: ${error}`);
314
+ return null;
315
+ }
316
+ };
317
+
318
+ // src/index.ts
319
+ async function buildHandler(options) {
320
+ const BUILDER_DEBUG = Boolean(process.env.VERCEL_BUILDER_DEBUG ?? false);
321
+ const isVercelBuild = Boolean(process.env.VERCEL_BUILD_IMAGE ?? false);
322
+ const { files, entrypoint, workPath, config, meta } = options;
323
+ const crossCompilationEnabled = !isVercelBuild && !meta?.isDev;
324
+ await installRustToolchain();
325
+ (0, import_build_utils6.debug)("Creating file system");
326
+ const downloadedFiles = await (0, import_build_utils6.download)(files, workPath, meta);
327
+ const entryPath = downloadedFiles[entrypoint].fsPath;
328
+ const HOME = process.platform === "win32" ? assertEnv("USERPROFILE") : assertEnv("HOME");
329
+ const PATH = assertEnv("PATH");
330
+ const rustEnv = {
331
+ PATH: `${import_node_path4.default.join(HOME, ".cargo/bin")}${import_node_path4.default.delimiter}${PATH}`,
332
+ RUSTFLAGS: [process.env.RUSTFLAGS].filter(Boolean).join(" ")
333
+ };
334
+ const cargoWorkspace = await findCargoWorkspace({
335
+ env: rustEnv,
336
+ cwd: import_node_path4.default.dirname(entryPath)
337
+ });
338
+ const binaryName = findBinaryName(cargoWorkspace, entryPath);
339
+ const cargoBuildConfiguration = await findCargoBuildConfiguration(cargoWorkspace);
340
+ const buildVariant = BUILDER_DEBUG || meta?.isDev ? "debug" : "release";
341
+ const buildTarget = cargoBuildConfiguration?.build.target ?? "";
342
+ await runUserScripts(workPath);
343
+ const extraFiles = await gatherExtraFiles(config.includeFiles, workPath);
344
+ (0, import_build_utils6.debug)(`Running \`cargo build\` for \`${binaryName}\``);
345
+ try {
346
+ const args = crossCompilationEnabled ? [
347
+ "zigbuild",
348
+ "--target",
349
+ "x86_64-unknown-linux-gnu",
350
+ "--bin",
351
+ binaryName
352
+ ].concat(BUILDER_DEBUG ? ["--verbose"] : ["--quiet"], ["--release"]) : ["build", "--bin", binaryName].concat(
353
+ BUILDER_DEBUG ? ["--verbose"] : ["--quiet"],
354
+ meta?.isDev ? [] : ["--release"]
355
+ );
356
+ await (0, import_execa4.default)("cargo", args, {
357
+ cwd: workPath,
358
+ env: rustEnv
359
+ });
360
+ } catch (err) {
361
+ (0, import_build_utils6.debug)(`Running \`cargo build\` for \`${binaryName}\` failed`);
362
+ throw err;
363
+ }
364
+ (0, import_build_utils6.debug)(`Building \`${binaryName}\` for \`${process.platform}\` completed`);
365
+ let { target_directory: targetDirectory } = await getCargoMetadata({
366
+ cwd: workPath,
367
+ env: rustEnv
368
+ });
369
+ if (crossCompilationEnabled) {
370
+ targetDirectory = import_node_path4.default.join(targetDirectory, "x86_64-unknown-linux-gnu");
371
+ }
372
+ targetDirectory = import_node_path4.default.join(targetDirectory, buildTarget);
373
+ const bin = import_node_path4.default.join(
374
+ targetDirectory,
375
+ buildVariant,
376
+ getExecutableName(binaryName)
377
+ );
378
+ const lambdaOptions = await (0, import_build_utils6.getLambdaOptionsFromFunction)({
379
+ sourceFile: entrypoint,
380
+ config
381
+ });
382
+ const handler = getExecutableName("executable");
383
+ const executableFile = new import_build_utils6.FileFsRef({ mode: 493, fsPath: bin });
384
+ const lambda = new import_build_utils6.Lambda({
385
+ files: {
386
+ ...extraFiles,
387
+ [handler]: executableFile
388
+ },
389
+ handler,
390
+ runtime: "executable",
391
+ supportsResponseStreaming: true,
392
+ ...lambdaOptions
393
+ });
394
+ lambda.zipBuffer = await lambda.createZip();
395
+ (0, import_build_utils6.debug)(`generating function for \`${entrypoint}\``);
396
+ return {
397
+ output: lambda
398
+ };
399
+ }
400
+ var runtime = {
401
+ version: 3,
402
+ build: buildHandler,
403
+ prepareCache: async ({ workPath }) => {
404
+ (0, import_build_utils6.debug)(`Caching \`${workPath}\``);
405
+ const cacheFiles = await (0, import_build_utils6.glob)("target/**", workPath);
406
+ for (const f of Object.keys(cacheFiles)) {
407
+ const accept = /(?:^|\/)target\/release\/\.fingerprint\//.test(f) || /(?:^|\/)target\/release\/build\//.test(f) || /(?:^|\/)target\/release\/deps\//.test(f) || /(?:^|\/)target\/debug\/\.fingerprint\//.test(f) || /(?:^|\/)target\/debug\/build\//.test(f) || /(?:^|\/)target\/debug\/deps\//.test(f);
408
+ if (!accept) {
409
+ delete cacheFiles[f];
410
+ }
411
+ }
412
+ return cacheFiles;
413
+ },
414
+ startDevServer,
415
+ shouldServe: async (options) => {
416
+ (0, import_build_utils6.debug)(`Requested ${options.requestPath} for ${options.entrypoint}`);
417
+ return Promise.resolve(options.requestPath === options.entrypoint);
418
+ }
419
+ };
420
+ var { version, build, prepareCache, startDevServer: startDevServer2, shouldServe } = runtime;
421
+ // Annotate the CommonJS export names for ESM import in node:
422
+ 0 && (module.exports = {
423
+ build,
424
+ prepareCache,
425
+ shouldServe,
426
+ startDevServer,
427
+ version
428
+ });
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@vercel/rust",
3
+ "version": "0.0.0-canary.0",
4
+ "license": "Apache-2.0",
5
+ "main": "./dist/index",
6
+ "homepage": "https://vercel.com/docs/runtimes#official-runtimes/rust",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/vercel/vercel.git",
10
+ "directory": "packages/rust"
11
+ },
12
+ "scripts": {
13
+ "build": "node ../../utils/build-builder.mjs",
14
+ "test": "jest --reporters=default --reporters=jest-junit --env node --verbose --runInBand --bail",
15
+ "test-e2e": "pnpm test",
16
+ "type-check": "tsc --noEmit"
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "dependencies": {
22
+ "@iarna/toml": "^2.2.5",
23
+ "lodash": "^4.17.21",
24
+ "execa": "5"
25
+ },
26
+ "devDependencies": {
27
+ "typescript": "^4.9.4",
28
+ "@types/jest": "^29.4.0",
29
+ "@types/lodash": "^4.14.191",
30
+ "@types/ms": "^0.7.31",
31
+ "@types/node": "^18.11.18",
32
+ "@types/node-fetch": "^2.6.2",
33
+ "@vercel/build-utils": "13.1.0",
34
+ "@vercel/routing-utils": "5.2.2",
35
+ "@vercel/style-guide": "^4.0.2",
36
+ "eslint": "^8.35.0",
37
+ "husky": "^8.0.3",
38
+ "jest": "^29.5.0",
39
+ "ms": "^2.1.3",
40
+ "node-fetch": "2.6.0",
41
+ "prettier": "^2.8.4",
42
+ "rimraf": "^4.1.1",
43
+ "ts-jest": "^29.0.5"
44
+ }
45
+ }