@vercel/rust 1.4.1 → 1.5.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.
- package/bin/proxy-linux-amd64 +0 -0
- package/bin/proxy-linux-arm64 +0 -0
- package/dist/index.js +1124 -103
- package/package.json +11 -10
package/dist/index.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,10 +30,374 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
33
|
+
// ../../internals/ipc-proxy/dist/dev-proxy.js
|
|
34
|
+
var require_dev_proxy = __commonJS({
|
|
35
|
+
"../../internals/ipc-proxy/dist/dev-proxy.js"(exports, module2) {
|
|
36
|
+
"use strict";
|
|
37
|
+
var __defProp2 = Object.defineProperty;
|
|
38
|
+
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
39
|
+
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
40
|
+
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
41
|
+
var __export2 = (target, all) => {
|
|
42
|
+
for (var name in all)
|
|
43
|
+
__defProp2(target, name, { get: all[name], enumerable: true });
|
|
44
|
+
};
|
|
45
|
+
var __copyProps2 = (to, from, except, desc) => {
|
|
46
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
47
|
+
for (let key of __getOwnPropNames2(from))
|
|
48
|
+
if (!__hasOwnProp2.call(to, key) && key !== except)
|
|
49
|
+
__defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
|
|
50
|
+
}
|
|
51
|
+
return to;
|
|
52
|
+
};
|
|
53
|
+
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
54
|
+
var dev_proxy_exports = {};
|
|
55
|
+
__export2(dev_proxy_exports, {
|
|
56
|
+
createDevProxyServer: () => createDevProxyServer,
|
|
57
|
+
findFreePort: () => findFreePort,
|
|
58
|
+
normalizeServiceRoutePrefix: () => normalizeServiceRoutePrefix,
|
|
59
|
+
resolveServiceRoutePrefix: () => resolveServiceRoutePrefix,
|
|
60
|
+
rewriteRequestUrl: () => rewriteRequestUrl,
|
|
61
|
+
sanitizeHeaders: () => sanitizeHeaders,
|
|
62
|
+
startDevProxy: () => startDevProxy2,
|
|
63
|
+
stripServiceRoutePrefix: () => stripServiceRoutePrefix,
|
|
64
|
+
waitForPort: () => waitForPort
|
|
65
|
+
});
|
|
66
|
+
module2.exports = __toCommonJS2(dev_proxy_exports);
|
|
67
|
+
var import_node_http = require("http");
|
|
68
|
+
var import_node_net = require("net");
|
|
69
|
+
var PING_PATH = "/_vercel/ping";
|
|
70
|
+
var INTERNAL_HEADER_PREFIX = "x-vercel-internal-";
|
|
71
|
+
var LOCALHOST = "127.0.0.1";
|
|
72
|
+
var DEFAULT_READINESS_TIMEOUT = 5 * 6e4;
|
|
73
|
+
var READINESS_POLL_INTERVAL = 100;
|
|
74
|
+
var READINESS_DIAL_TIMEOUT = 1e3;
|
|
75
|
+
function normalizeServiceRoutePrefix(rawPrefix) {
|
|
76
|
+
if (!rawPrefix)
|
|
77
|
+
return "";
|
|
78
|
+
let prefix = rawPrefix.trim();
|
|
79
|
+
if (!prefix)
|
|
80
|
+
return "";
|
|
81
|
+
if (!prefix.startsWith("/")) {
|
|
82
|
+
prefix = `/${prefix}`;
|
|
83
|
+
}
|
|
84
|
+
if (prefix !== "/") {
|
|
85
|
+
prefix = prefix.replace(/\/+$/, "");
|
|
86
|
+
if (!prefix)
|
|
87
|
+
prefix = "/";
|
|
88
|
+
}
|
|
89
|
+
return prefix === "/" ? "" : prefix;
|
|
90
|
+
}
|
|
91
|
+
function resolveServiceRoutePrefix(env = process.env) {
|
|
92
|
+
const strip = (env.VERCEL_SERVICE_ROUTE_PREFIX_STRIP ?? "").trim().toLowerCase();
|
|
93
|
+
if (strip !== "1" && strip !== "true")
|
|
94
|
+
return "";
|
|
95
|
+
return normalizeServiceRoutePrefix(env.VERCEL_SERVICE_ROUTE_PREFIX);
|
|
96
|
+
}
|
|
97
|
+
function stripServiceRoutePrefix(pathValue, prefix) {
|
|
98
|
+
if (pathValue === "*")
|
|
99
|
+
return pathValue;
|
|
100
|
+
let normalized = pathValue;
|
|
101
|
+
if (!normalized) {
|
|
102
|
+
normalized = "/";
|
|
103
|
+
} else if (!normalized.startsWith("/")) {
|
|
104
|
+
normalized = `/${normalized}`;
|
|
105
|
+
}
|
|
106
|
+
if (!prefix)
|
|
107
|
+
return normalized;
|
|
108
|
+
if (normalized === prefix)
|
|
109
|
+
return "/";
|
|
110
|
+
if (normalized.startsWith(`${prefix}/`)) {
|
|
111
|
+
return normalized.slice(prefix.length) || "/";
|
|
112
|
+
}
|
|
113
|
+
return normalized;
|
|
114
|
+
}
|
|
115
|
+
function splitUrl(url) {
|
|
116
|
+
const queryIndex = url.indexOf("?");
|
|
117
|
+
if (queryIndex === -1)
|
|
118
|
+
return { pathname: url, search: "" };
|
|
119
|
+
return { pathname: url.slice(0, queryIndex), search: url.slice(queryIndex) };
|
|
120
|
+
}
|
|
121
|
+
function rewriteRequestUrl(url, prefix) {
|
|
122
|
+
const { pathname, search } = splitUrl(url || "/");
|
|
123
|
+
return `${stripServiceRoutePrefix(pathname, prefix)}${search}`;
|
|
124
|
+
}
|
|
125
|
+
function sanitizeHeaders(headers) {
|
|
126
|
+
const sanitized = {};
|
|
127
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
128
|
+
if (key.toLowerCase().startsWith(INTERNAL_HEADER_PREFIX))
|
|
129
|
+
continue;
|
|
130
|
+
sanitized[key] = value;
|
|
131
|
+
}
|
|
132
|
+
const forwardedHost = headers["x-forwarded-host"];
|
|
133
|
+
const host = Array.isArray(forwardedHost) ? forwardedHost[0] : forwardedHost;
|
|
134
|
+
if (host) {
|
|
135
|
+
sanitized.host = host;
|
|
136
|
+
}
|
|
137
|
+
return sanitized;
|
|
138
|
+
}
|
|
139
|
+
function findFreePort() {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const server = (0, import_node_net.createServer)();
|
|
142
|
+
server.unref();
|
|
143
|
+
server.once("error", reject);
|
|
144
|
+
server.listen(0, LOCALHOST, () => {
|
|
145
|
+
const address = server.address();
|
|
146
|
+
if (!address || typeof address === "string") {
|
|
147
|
+
server.close(() => reject(new Error("Failed to allocate a free port")));
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const { port } = address;
|
|
151
|
+
server.close(() => resolve(port));
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function isPortReachable(port) {
|
|
156
|
+
return new Promise((resolve) => {
|
|
157
|
+
const socket = (0, import_node_net.createConnection)({ port, host: LOCALHOST });
|
|
158
|
+
const done = (reachable) => {
|
|
159
|
+
socket.removeAllListeners();
|
|
160
|
+
socket.destroy();
|
|
161
|
+
resolve(reachable);
|
|
162
|
+
};
|
|
163
|
+
socket.setTimeout(READINESS_DIAL_TIMEOUT);
|
|
164
|
+
socket.once("connect", () => done(true));
|
|
165
|
+
socket.once("timeout", () => done(false));
|
|
166
|
+
socket.once("error", () => done(false));
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function sleep(ms) {
|
|
170
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
171
|
+
}
|
|
172
|
+
async function waitForPort(port, child, timeout, label = "Dev server") {
|
|
173
|
+
let exited;
|
|
174
|
+
let spawnError;
|
|
175
|
+
const onExit = (code, signal) => {
|
|
176
|
+
exited = { code, signal };
|
|
177
|
+
};
|
|
178
|
+
const onError = (err) => {
|
|
179
|
+
spawnError = err;
|
|
180
|
+
};
|
|
181
|
+
child.once("exit", onExit);
|
|
182
|
+
child.once("error", onError);
|
|
183
|
+
try {
|
|
184
|
+
const start = Date.now();
|
|
185
|
+
while (Date.now() - start < timeout) {
|
|
186
|
+
if (spawnError)
|
|
187
|
+
throw spawnError;
|
|
188
|
+
if (exited) {
|
|
189
|
+
throw new Error(
|
|
190
|
+
`${label} exited before it started listening (code: ${exited.code}, signal: ${exited.signal})`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
if (await isPortReachable(port))
|
|
194
|
+
return;
|
|
195
|
+
await sleep(READINESS_POLL_INTERVAL);
|
|
196
|
+
}
|
|
197
|
+
throw new Error(`${label} did not start listening within ${timeout}ms`);
|
|
198
|
+
} finally {
|
|
199
|
+
child.removeListener("exit", onExit);
|
|
200
|
+
child.removeListener("error", onError);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function createDevProxyServer(options) {
|
|
204
|
+
const { targetPort } = options;
|
|
205
|
+
const routePrefix = normalizeServiceRoutePrefix(options.routePrefix);
|
|
206
|
+
const server = (0, import_node_http.createServer)((req, res) => {
|
|
207
|
+
const { pathname } = splitUrl(req.url || "/");
|
|
208
|
+
if (pathname === PING_PATH) {
|
|
209
|
+
res.writeHead(200, { "content-type": "text/plain" });
|
|
210
|
+
res.end("OK");
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const proxyReq = (0, import_node_http.request)(
|
|
214
|
+
{
|
|
215
|
+
host: LOCALHOST,
|
|
216
|
+
port: targetPort,
|
|
217
|
+
method: req.method,
|
|
218
|
+
path: rewriteRequestUrl(req.url || "/", routePrefix),
|
|
219
|
+
headers: sanitizeHeaders(req.headers)
|
|
220
|
+
},
|
|
221
|
+
(proxyRes) => {
|
|
222
|
+
res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
|
|
223
|
+
proxyRes.pipe(res);
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
proxyReq.once("error", (err) => {
|
|
227
|
+
if (!res.headersSent) {
|
|
228
|
+
res.writeHead(502, { "content-type": "text/plain" });
|
|
229
|
+
}
|
|
230
|
+
res.end(`Dev proxy error: ${err.message}`);
|
|
231
|
+
});
|
|
232
|
+
res.once("close", () => {
|
|
233
|
+
if (!res.writableFinished)
|
|
234
|
+
proxyReq.destroy();
|
|
235
|
+
});
|
|
236
|
+
req.pipe(proxyReq);
|
|
237
|
+
});
|
|
238
|
+
server.on("upgrade", (req, clientSocket, head) => {
|
|
239
|
+
const headers = sanitizeHeaders(req.headers);
|
|
240
|
+
const path8 = rewriteRequestUrl(req.url || "/", routePrefix);
|
|
241
|
+
const upstream = (0, import_node_net.createConnection)(
|
|
242
|
+
{ host: LOCALHOST, port: targetPort },
|
|
243
|
+
() => {
|
|
244
|
+
const lines = [`${req.method} ${path8} HTTP/${req.httpVersion}`];
|
|
245
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
246
|
+
if (Array.isArray(value)) {
|
|
247
|
+
for (const entry of value)
|
|
248
|
+
lines.push(`${key}: ${entry}`);
|
|
249
|
+
} else if (value !== void 0) {
|
|
250
|
+
lines.push(`${key}: ${value}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
upstream.write(`${lines.join("\r\n")}\r
|
|
254
|
+
\r
|
|
255
|
+
`);
|
|
256
|
+
if (head?.length)
|
|
257
|
+
upstream.write(new Uint8Array(head));
|
|
258
|
+
upstream.pipe(clientSocket);
|
|
259
|
+
clientSocket.pipe(upstream);
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
const destroy = () => {
|
|
263
|
+
upstream.destroy();
|
|
264
|
+
clientSocket.destroy();
|
|
265
|
+
};
|
|
266
|
+
upstream.once("error", destroy);
|
|
267
|
+
clientSocket.once("error", destroy);
|
|
268
|
+
});
|
|
269
|
+
return server;
|
|
270
|
+
}
|
|
271
|
+
async function startDevProxy2(options) {
|
|
272
|
+
const {
|
|
273
|
+
spawnServer,
|
|
274
|
+
env = process.env,
|
|
275
|
+
readinessTimeout = DEFAULT_READINESS_TIMEOUT,
|
|
276
|
+
label = "Dev server"
|
|
277
|
+
} = options;
|
|
278
|
+
const internalPort = await findFreePort();
|
|
279
|
+
const child = spawnServer(internalPort);
|
|
280
|
+
let server;
|
|
281
|
+
const close = async () => {
|
|
282
|
+
if (server) {
|
|
283
|
+
await new Promise((resolve) => {
|
|
284
|
+
server?.close(() => resolve());
|
|
285
|
+
server?.closeAllConnections?.();
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
289
|
+
child.kill("SIGTERM");
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
try {
|
|
293
|
+
await waitForPort(internalPort, child, readinessTimeout, label);
|
|
294
|
+
server = createDevProxyServer({
|
|
295
|
+
targetPort: internalPort,
|
|
296
|
+
routePrefix: resolveServiceRoutePrefix(env)
|
|
297
|
+
});
|
|
298
|
+
const listenPort = options.port ?? await findFreePort();
|
|
299
|
+
await new Promise((resolve, reject) => {
|
|
300
|
+
server?.once("error", reject);
|
|
301
|
+
server?.listen(listenPort, () => resolve());
|
|
302
|
+
});
|
|
303
|
+
if (!child.pid) {
|
|
304
|
+
throw new Error(`${label} started without a PID`);
|
|
305
|
+
}
|
|
306
|
+
return { port: listenPort, pid: child.pid, child, close };
|
|
307
|
+
} catch (err) {
|
|
308
|
+
await close();
|
|
309
|
+
throw err;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// ../../internals/ipc-proxy/dist/index.js
|
|
316
|
+
var require_dist = __commonJS({
|
|
317
|
+
"../../internals/ipc-proxy/dist/index.js"(exports, module2) {
|
|
318
|
+
"use strict";
|
|
319
|
+
var __defProp2 = Object.defineProperty;
|
|
320
|
+
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
321
|
+
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
322
|
+
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
323
|
+
var __export2 = (target, all) => {
|
|
324
|
+
for (var name in all)
|
|
325
|
+
__defProp2(target, name, { get: all[name], enumerable: true });
|
|
326
|
+
};
|
|
327
|
+
var __copyProps2 = (to, from, except, desc) => {
|
|
328
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
329
|
+
for (let key of __getOwnPropNames2(from))
|
|
330
|
+
if (!__hasOwnProp2.call(to, key) && key !== except)
|
|
331
|
+
__defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
|
|
332
|
+
}
|
|
333
|
+
return to;
|
|
334
|
+
};
|
|
335
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps2(target, mod, "default"), secondTarget && __copyProps2(secondTarget, mod, "default"));
|
|
336
|
+
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
337
|
+
var src_exports2 = {};
|
|
338
|
+
__export2(src_exports2, {
|
|
339
|
+
createStandaloneLambda: () => createStandaloneLambda2,
|
|
340
|
+
getBootstrapDir: () => getBootstrapDir,
|
|
341
|
+
getProxyBinaryPath: () => getProxyBinaryPath
|
|
342
|
+
});
|
|
343
|
+
module2.exports = __toCommonJS2(src_exports2);
|
|
344
|
+
var import_node_path8 = require("path");
|
|
345
|
+
var import_node_fs4 = require("fs");
|
|
346
|
+
var import_promises2 = require("fs/promises");
|
|
347
|
+
var import_build_utils12 = require("@vercel/build-utils");
|
|
348
|
+
__reExport(src_exports2, require_dev_proxy(), module2.exports);
|
|
349
|
+
function proxyBinaryName(architecture) {
|
|
350
|
+
return architecture === "arm64" ? "proxy-linux-arm64" : "proxy-linux-amd64";
|
|
351
|
+
}
|
|
352
|
+
function getProxyBinaryPath(architecture) {
|
|
353
|
+
const binPath = (0, import_node_path8.join)(__dirname, "..", "bin", proxyBinaryName(architecture));
|
|
354
|
+
if (!(0, import_node_fs4.existsSync)(binPath)) {
|
|
355
|
+
throw new Error(
|
|
356
|
+
`IPC proxy binary not found for architecture "${architecture}" at ${binPath}. Ensure @vercel-internals/ipc-proxy has been built and its prebuilt binaries copied alongside the consumer's dist output.`
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
return binPath;
|
|
360
|
+
}
|
|
361
|
+
function getBootstrapDir() {
|
|
362
|
+
return (0, import_node_path8.join)(__dirname, "..", "bootstrap");
|
|
363
|
+
}
|
|
364
|
+
async function createStandaloneLambda2(options) {
|
|
365
|
+
const {
|
|
366
|
+
userServerPath,
|
|
367
|
+
architecture,
|
|
368
|
+
lambdaOptions,
|
|
369
|
+
includedFiles,
|
|
370
|
+
runtimeLanguage,
|
|
371
|
+
supportsResponseStreaming = true
|
|
372
|
+
} = options;
|
|
373
|
+
const proxyPath = getProxyBinaryPath(architecture);
|
|
374
|
+
const [proxyData, userServerData] = await Promise.all([
|
|
375
|
+
(0, import_promises2.readFile)(proxyPath),
|
|
376
|
+
(0, import_promises2.readFile)(userServerPath)
|
|
377
|
+
]);
|
|
378
|
+
return new import_build_utils12.Lambda({
|
|
379
|
+
...lambdaOptions,
|
|
380
|
+
files: {
|
|
381
|
+
...includedFiles,
|
|
382
|
+
executable: new import_build_utils12.FileBlob({ mode: 493, data: proxyData }),
|
|
383
|
+
"user-server": new import_build_utils12.FileBlob({ mode: 493, data: userServerData })
|
|
384
|
+
},
|
|
385
|
+
handler: "executable",
|
|
386
|
+
runtime: "executable",
|
|
387
|
+
supportsResponseStreaming,
|
|
388
|
+
architecture,
|
|
389
|
+
runtimeLanguage
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
|
|
30
395
|
// src/index.ts
|
|
31
396
|
var src_exports = {};
|
|
32
397
|
__export(src_exports, {
|
|
33
398
|
build: () => build,
|
|
399
|
+
detectEntrypoint: () => detectEntrypoint,
|
|
400
|
+
detectRustEntrypoint: () => detectRustEntrypoint,
|
|
34
401
|
diagnostics: () => diagnostics,
|
|
35
402
|
prepareCache: () => prepareCache,
|
|
36
403
|
shouldServe: () => shouldServe,
|
|
@@ -38,9 +405,9 @@ __export(src_exports, {
|
|
|
38
405
|
version: () => version
|
|
39
406
|
});
|
|
40
407
|
module.exports = __toCommonJS(src_exports);
|
|
41
|
-
var
|
|
42
|
-
var
|
|
43
|
-
var
|
|
408
|
+
var import_node_path7 = __toESM(require("path"));
|
|
409
|
+
var import_build_utils11 = require("@vercel/build-utils");
|
|
410
|
+
var import_execa5 = __toESM(require("execa"));
|
|
44
411
|
|
|
45
412
|
// src/lib/rust-toolchain.ts
|
|
46
413
|
var import_build_utils = require("@vercel/build-utils");
|
|
@@ -75,6 +442,7 @@ var import_node_fs = require("fs");
|
|
|
75
442
|
var import_node_path = __toESM(require("path"));
|
|
76
443
|
var import_smol_toml = require("smol-toml");
|
|
77
444
|
var import_execa2 = __toESM(require("execa"));
|
|
445
|
+
var import_build_utils2 = require("@vercel/build-utils");
|
|
78
446
|
async function getCargoMetadata(options, filterPlatform) {
|
|
79
447
|
const args = ["metadata", "--format-version", "1"];
|
|
80
448
|
if (filterPlatform)
|
|
@@ -105,11 +473,208 @@ async function findCargoBuildConfiguration(workspace) {
|
|
|
105
473
|
const config = (0, import_smol_toml.parse)(await (0, import_promises.readFile)(configPath, "utf8"));
|
|
106
474
|
return config;
|
|
107
475
|
}
|
|
476
|
+
var VERCEL_RUNTIME_CRATE = "vercel_runtime";
|
|
477
|
+
var CARGO_MANIFEST = "Cargo.toml";
|
|
478
|
+
function normalizeCrateName(name) {
|
|
479
|
+
return name.trim().toLowerCase().replace(/-/g, "_");
|
|
480
|
+
}
|
|
481
|
+
function declaresVercelRuntime(deps) {
|
|
482
|
+
if (!deps)
|
|
483
|
+
return false;
|
|
484
|
+
for (const [name, spec] of Object.entries(deps)) {
|
|
485
|
+
if (spec && typeof spec === "object" && spec.optional === true) {
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
if (normalizeCrateName(name) === VERCEL_RUNTIME_CRATE)
|
|
489
|
+
return true;
|
|
490
|
+
if (spec && typeof spec === "object" && typeof spec.package === "string" && normalizeCrateName(spec.package) === VERCEL_RUNTIME_CRATE) {
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
function tomlDeclaresVercelRuntime(toml) {
|
|
497
|
+
return declaresVercelRuntime(toml.dependencies);
|
|
498
|
+
}
|
|
499
|
+
async function readCargoToml(manifestPath) {
|
|
500
|
+
try {
|
|
501
|
+
return (0, import_smol_toml.parse)(await (0, import_promises.readFile)(manifestPath, "utf8"));
|
|
502
|
+
} catch (err) {
|
|
503
|
+
(0, import_build_utils2.debug)(`Failed to parse ${manifestPath}: ${err}`);
|
|
504
|
+
}
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
507
|
+
async function hasVercelRuntimeDependency(workPath, entrypoint) {
|
|
508
|
+
const root = import_node_path.default.resolve(workPath);
|
|
509
|
+
const entryPath = import_node_path.default.resolve(workPath, entrypoint);
|
|
510
|
+
let dir = import_node_path.default.dirname(entryPath);
|
|
511
|
+
for (; ; ) {
|
|
512
|
+
const manifestPath = import_node_path.default.join(dir, CARGO_MANIFEST);
|
|
513
|
+
if ((0, import_node_fs.existsSync)(manifestPath)) {
|
|
514
|
+
const toml = await readCargoToml(manifestPath);
|
|
515
|
+
if (toml?.package) {
|
|
516
|
+
const declaresRuntime = tomlDeclaresVercelRuntime(toml);
|
|
517
|
+
if (declaresRuntime) {
|
|
518
|
+
(0, import_build_utils2.debug)(`Found \`${VERCEL_RUNTIME_CRATE}\` in ${manifestPath}`);
|
|
519
|
+
}
|
|
520
|
+
return declaresRuntime;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (dir === root)
|
|
524
|
+
break;
|
|
525
|
+
const parent = import_node_path.default.dirname(dir);
|
|
526
|
+
if (parent === dir)
|
|
527
|
+
break;
|
|
528
|
+
dir = parent;
|
|
529
|
+
}
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
function findDefaultPackage(metadata) {
|
|
533
|
+
const defaultMembers = metadata.workspace_default_members;
|
|
534
|
+
if (defaultMembers?.length === 1) {
|
|
535
|
+
const member = metadata.packages.find((p) => p.id === defaultMembers[0]);
|
|
536
|
+
if (member)
|
|
537
|
+
return member;
|
|
538
|
+
}
|
|
539
|
+
const root = metadata.packages.find((p) => p.id === metadata.resolve?.root);
|
|
540
|
+
if (root)
|
|
541
|
+
return root;
|
|
542
|
+
if (metadata.workspace_root) {
|
|
543
|
+
const manifestPath = import_node_path.default.join(metadata.workspace_root, "Cargo.toml");
|
|
544
|
+
const atRoot = metadata.packages.find(
|
|
545
|
+
(p) => import_node_path.default.resolve(p.manifest_path) === import_node_path.default.resolve(manifestPath)
|
|
546
|
+
);
|
|
547
|
+
if (atRoot)
|
|
548
|
+
return atRoot;
|
|
549
|
+
}
|
|
550
|
+
return metadata.packages.length === 1 ? metadata.packages[0] : void 0;
|
|
551
|
+
}
|
|
552
|
+
function collectBinTargets(metadata) {
|
|
553
|
+
const workspaceIds = new Set(metadata.workspace_members ?? []);
|
|
554
|
+
const defaultPackage = findDefaultPackage(metadata);
|
|
555
|
+
const members = metadata.packages.filter(
|
|
556
|
+
(pkg) => workspaceIds.size === 0 || workspaceIds.has(pkg.id)
|
|
557
|
+
);
|
|
558
|
+
return members.flatMap(
|
|
559
|
+
(pkg) => (pkg.targets ?? []).filter((target) => target.kind.includes("bin")).map((target) => ({
|
|
560
|
+
name: target.name,
|
|
561
|
+
packageId: pkg.id,
|
|
562
|
+
packageName: pkg.name,
|
|
563
|
+
srcPath: target.src_path,
|
|
564
|
+
isDefaultPackage: pkg.id === defaultPackage?.id
|
|
565
|
+
}))
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
function looksLikeBinName(value) {
|
|
569
|
+
return Boolean(value) && !value.includes("/") && !value.includes("\\") && !value.includes(".");
|
|
570
|
+
}
|
|
571
|
+
function realPath(value) {
|
|
572
|
+
try {
|
|
573
|
+
return import_node_fs.realpathSync.native(import_node_path.default.resolve(value));
|
|
574
|
+
} catch {
|
|
575
|
+
return import_node_path.default.resolve(value);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
function describeCandidates(targets) {
|
|
579
|
+
const packages = new Set(targets.map((target) => target.packageName));
|
|
580
|
+
return targets.map(
|
|
581
|
+
(target) => packages.size > 1 ? `${target.packageName}:${target.name}` : target.name
|
|
582
|
+
).join(", ");
|
|
583
|
+
}
|
|
584
|
+
function resolveStandaloneBinary(metadata, entrypoint, workPath) {
|
|
585
|
+
const binTargets = collectBinTargets(metadata);
|
|
586
|
+
if (binTargets.length === 0) {
|
|
587
|
+
throw new Error(
|
|
588
|
+
"No binary target found in this Cargo project. Add a `src/main.rs` or a `[[bin]]` target to your `Cargo.toml`."
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
if (entrypoint) {
|
|
592
|
+
if (!looksLikeBinName(entrypoint)) {
|
|
593
|
+
const entryPath = import_node_path.default.resolve(workPath, entrypoint);
|
|
594
|
+
const resolvedEntry = realPath(entryPath);
|
|
595
|
+
const bySrcPath = binTargets.filter(
|
|
596
|
+
(target) => realPath(target.srcPath) === resolvedEntry
|
|
597
|
+
);
|
|
598
|
+
if (bySrcPath.length === 1)
|
|
599
|
+
return bySrcPath[0];
|
|
600
|
+
if (bySrcPath.length > 1) {
|
|
601
|
+
throw new Error(
|
|
602
|
+
`The entrypoint \`${entrypoint}\` matches multiple binary targets (${describeCandidates(bySrcPath)}). Give the targets unique source paths.`
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
if ((0, import_node_fs.existsSync)(entryPath)) {
|
|
606
|
+
throw new Error(
|
|
607
|
+
`The entrypoint \`${entrypoint}\` exists but is not a Cargo binary target. Point it at a binary target declared by this project (${describeCandidates(binTargets)}).`
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
} else {
|
|
611
|
+
const byName = binTargets.filter((target) => target.name === entrypoint);
|
|
612
|
+
if (byName.length === 1)
|
|
613
|
+
return byName[0];
|
|
614
|
+
if (byName.length > 1) {
|
|
615
|
+
throw new Error(
|
|
616
|
+
`The binary name \`${entrypoint}\` is ambiguous (${describeCandidates(byName)}). Set the entrypoint to the binary's source path.`
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
throw new Error(
|
|
620
|
+
`No Cargo binary target named \`${entrypoint}\` was found. Available targets: ${describeCandidates(binTargets)}.`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
const defaultTargets = binTargets.filter((target) => target.isDefaultPackage);
|
|
625
|
+
const candidates = defaultTargets.length > 0 ? defaultTargets : binTargets;
|
|
626
|
+
const defaultPackage = findDefaultPackage(metadata);
|
|
627
|
+
if (defaultPackage?.default_run) {
|
|
628
|
+
const byDefaultRun = candidates.find(
|
|
629
|
+
(target) => target.name === defaultPackage.default_run
|
|
630
|
+
);
|
|
631
|
+
if (byDefaultRun)
|
|
632
|
+
return byDefaultRun;
|
|
633
|
+
}
|
|
634
|
+
if (candidates.length === 1) {
|
|
635
|
+
return candidates[0];
|
|
636
|
+
}
|
|
637
|
+
throw new Error(
|
|
638
|
+
`Unable to determine which binary to deploy. This Cargo project declares multiple binary targets (${describeCandidates(candidates)}). Set the entrypoint to the binary you want to deploy \u2014 either its source path (e.g. \`src/bin/server.rs\`) or its name (e.g. \`server\`) \u2014 or set \`default-run\` in your \`Cargo.toml\`.`
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
function resolvedPackageUsesVercelRuntime(metadata, binary) {
|
|
642
|
+
const owner = metadata.packages.find(
|
|
643
|
+
(pkg) => pkg.id === binary.packageId || pkg.name === binary.packageName && pkg.targets.some(
|
|
644
|
+
(target) => realPath(target.src_path) === realPath(binary.srcPath)
|
|
645
|
+
)
|
|
646
|
+
);
|
|
647
|
+
if (!owner)
|
|
648
|
+
return false;
|
|
649
|
+
const node = metadata.resolve.nodes.find(
|
|
650
|
+
(candidate) => candidate.id === owner.id
|
|
651
|
+
);
|
|
652
|
+
if (!node)
|
|
653
|
+
return false;
|
|
654
|
+
return node.deps.some((dep) => {
|
|
655
|
+
const resolved = metadata.packages.find((pkg) => pkg.id === dep.pkg);
|
|
656
|
+
return resolved !== void 0 && normalizeCrateName(resolved.name) === VERCEL_RUNTIME_CRATE && dep.dep_kinds.some((kind) => kind.kind === null);
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
function assertStandaloneBinary(metadata, binary, workPath) {
|
|
660
|
+
if (!resolvedPackageUsesVercelRuntime(metadata, binary))
|
|
661
|
+
return;
|
|
662
|
+
const srcPath = (0, import_build_utils2.normalizePath)(
|
|
663
|
+
import_node_path.default.relative(realPath(workPath), realPath(binary.srcPath))
|
|
664
|
+
);
|
|
665
|
+
throw new Error(
|
|
666
|
+
`The package \`${binary.packageName}\` depends on \`${VERCEL_RUNTIME_CRATE}\`, so its binary \`${binary.name}\` cannot be deployed as a standalone server. Set the entrypoint to the binary's source file (\`${srcPath}\`) to keep the \`${VERCEL_RUNTIME_CRATE}\` output.`
|
|
667
|
+
);
|
|
668
|
+
}
|
|
108
669
|
function findBinaryName(workspace, entryPath) {
|
|
109
670
|
const { bin } = workspace.toml;
|
|
110
671
|
if (bin) {
|
|
111
|
-
const relativePath =
|
|
112
|
-
|
|
672
|
+
const relativePath = (0, import_build_utils2.normalizePath)(
|
|
673
|
+
import_node_path.default.relative(import_node_path.default.dirname(workspace.root), entryPath)
|
|
674
|
+
);
|
|
675
|
+
const entry = bin.find(
|
|
676
|
+
(binEntry) => binEntry.path && (0, import_build_utils2.normalizePath)(binEntry.path) === relativePath
|
|
677
|
+
);
|
|
113
678
|
if (entry?.name) {
|
|
114
679
|
return entry.name;
|
|
115
680
|
}
|
|
@@ -120,7 +685,49 @@ function findBinaryName(workspace, entryPath) {
|
|
|
120
685
|
// src/lib/utils.ts
|
|
121
686
|
var import_node_fs2 = __toESM(require("fs"));
|
|
122
687
|
var import_node_path2 = __toESM(require("path"));
|
|
123
|
-
var
|
|
688
|
+
var import_build_utils3 = require("@vercel/build-utils");
|
|
689
|
+
var CARGO_MANIFEST2 = "Cargo.toml";
|
|
690
|
+
function cargoManifestDirs(files) {
|
|
691
|
+
return Object.keys(files).filter(
|
|
692
|
+
(filePath) => filePath === CARGO_MANIFEST2 || filePath.endsWith(`/${CARGO_MANIFEST2}`)
|
|
693
|
+
).map((filePath) => filePath.slice(0, -CARGO_MANIFEST2.length));
|
|
694
|
+
}
|
|
695
|
+
function excludeCargoTargetDir(files, env = process.env, workPath) {
|
|
696
|
+
const rawTargetDir = env.CARGO_TARGET_DIR || "target";
|
|
697
|
+
const prefixes = [];
|
|
698
|
+
if (import_node_path2.default.isAbsolute(rawTargetDir)) {
|
|
699
|
+
if (workPath) {
|
|
700
|
+
const relative = import_node_path2.default.relative(
|
|
701
|
+
import_node_path2.default.resolve(workPath),
|
|
702
|
+
import_node_path2.default.resolve(rawTargetDir)
|
|
703
|
+
);
|
|
704
|
+
if (relative && !relative.startsWith("..")) {
|
|
705
|
+
prefixes.push(`${relative.split(import_node_path2.default.sep).join("/")}/`);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
} else {
|
|
709
|
+
const targetDir = rawTargetDir.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
710
|
+
prefixes.push(`${targetDir}/`);
|
|
711
|
+
for (const dir of cargoManifestDirs(files)) {
|
|
712
|
+
prefixes.push(`${dir}${targetDir}/`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
const filtered = {};
|
|
716
|
+
let excluded = 0;
|
|
717
|
+
for (const [filePath, file] of Object.entries(files)) {
|
|
718
|
+
if (prefixes.some((prefix) => filePath.startsWith(prefix))) {
|
|
719
|
+
excluded++;
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
filtered[filePath] = file;
|
|
723
|
+
}
|
|
724
|
+
if (excluded > 0) {
|
|
725
|
+
(0, import_build_utils3.debug)(
|
|
726
|
+
`Excluded ${excluded} file(s) under \`${rawTargetDir}\` from the build`
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
return filtered;
|
|
730
|
+
}
|
|
124
731
|
function getExecutableName(binName) {
|
|
125
732
|
return process.platform === "win32" ? `${binName}.exe` : binName;
|
|
126
733
|
}
|
|
@@ -134,54 +741,121 @@ async function runUserScripts(dir) {
|
|
|
134
741
|
const buildScriptPath = import_node_path2.default.join(dir, "build.sh");
|
|
135
742
|
const buildScriptExists = import_node_fs2.default.existsSync(buildScriptPath);
|
|
136
743
|
if (buildScriptExists) {
|
|
137
|
-
(0,
|
|
138
|
-
await (0,
|
|
744
|
+
(0, import_build_utils3.debug)("Running `build.sh`");
|
|
745
|
+
await (0, import_build_utils3.runShellScript)(buildScriptPath);
|
|
139
746
|
}
|
|
140
747
|
}
|
|
141
748
|
async function gatherExtraFiles(globMatcher, workPath) {
|
|
142
749
|
if (!globMatcher)
|
|
143
750
|
return {};
|
|
144
|
-
(0,
|
|
751
|
+
(0, import_build_utils3.debug)(
|
|
145
752
|
`Gathering extra files for glob \`${JSON.stringify(
|
|
146
753
|
globMatcher
|
|
147
754
|
)}\` in ${workPath}`
|
|
148
755
|
);
|
|
149
756
|
if (Array.isArray(globMatcher)) {
|
|
150
757
|
const allMatches = await Promise.all(
|
|
151
|
-
globMatcher.map((pattern) => (0,
|
|
758
|
+
globMatcher.map((pattern) => (0, import_build_utils3.glob)(pattern, workPath))
|
|
152
759
|
);
|
|
153
760
|
return allMatches.reduce((acc, matches) => ({ ...acc, ...matches }), {});
|
|
154
761
|
}
|
|
155
|
-
return (0,
|
|
762
|
+
return (0, import_build_utils3.glob)(globMatcher, workPath);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// src/lib/compile.ts
|
|
766
|
+
var import_node_path3 = __toESM(require("path"));
|
|
767
|
+
var import_execa3 = __toESM(require("execa"));
|
|
768
|
+
var import_build_utils4 = require("@vercel/build-utils");
|
|
769
|
+
function createRustEnv() {
|
|
770
|
+
const HOME = process.platform === "win32" ? assertEnv("USERPROFILE") : assertEnv("HOME");
|
|
771
|
+
const PATH = assertEnv("PATH");
|
|
772
|
+
return {
|
|
773
|
+
PATH: `${import_node_path3.default.join(HOME, ".cargo/bin")}${import_node_path3.default.delimiter}${PATH}`,
|
|
774
|
+
RUSTFLAGS: [process.env.RUSTFLAGS].filter(Boolean).join(" ")
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
async function compileCargoBinary({
|
|
778
|
+
workPath,
|
|
779
|
+
rustEnv,
|
|
780
|
+
binaryName,
|
|
781
|
+
packageName,
|
|
782
|
+
crossCompilation,
|
|
783
|
+
targetTriple,
|
|
784
|
+
release,
|
|
785
|
+
verbose
|
|
786
|
+
}) {
|
|
787
|
+
const args = crossCompilation ? ["zigbuild", "--target", targetTriple] : ["build"];
|
|
788
|
+
if (packageName) {
|
|
789
|
+
args.push("-p", packageName);
|
|
790
|
+
}
|
|
791
|
+
args.push("--bin", binaryName);
|
|
792
|
+
args.push(verbose ? "--verbose" : "--quiet");
|
|
793
|
+
if (release) {
|
|
794
|
+
args.push("--release");
|
|
795
|
+
}
|
|
796
|
+
(0, import_build_utils4.debug)(`Running \`cargo ${args.join(" ")}\``);
|
|
797
|
+
try {
|
|
798
|
+
await (0, import_execa3.default)("cargo", args, { cwd: workPath, env: rustEnv });
|
|
799
|
+
} catch (err) {
|
|
800
|
+
(0, import_build_utils4.debug)(`Running \`cargo build\` for \`${binaryName}\` failed`);
|
|
801
|
+
throw err;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
function resolveCompiledBinaryPath({
|
|
805
|
+
targetDirectory,
|
|
806
|
+
crossCompilation,
|
|
807
|
+
targetTriple,
|
|
808
|
+
buildTarget = "",
|
|
809
|
+
variant,
|
|
810
|
+
binaryName
|
|
811
|
+
}) {
|
|
812
|
+
let dir = targetDirectory;
|
|
813
|
+
if (crossCompilation) {
|
|
814
|
+
dir = import_node_path3.default.join(dir, targetTriple);
|
|
815
|
+
}
|
|
816
|
+
dir = import_node_path3.default.join(dir, buildTarget);
|
|
817
|
+
return import_node_path3.default.join(dir, variant, getExecutableName(binaryName));
|
|
818
|
+
}
|
|
819
|
+
function getTargetTriple(architecture) {
|
|
820
|
+
return architecture === "arm64" ? "aarch64-unknown-linux-gnu" : "x86_64-unknown-linux-gnu";
|
|
821
|
+
}
|
|
822
|
+
async function getRustHostTargetTriple(rustEnv) {
|
|
823
|
+
try {
|
|
824
|
+
const { stdout } = await (0, import_execa3.default)("rustc", ["-vV"], { env: rustEnv });
|
|
825
|
+
return /^host:\s+(.+)$/m.exec(stdout)?.[1];
|
|
826
|
+
} catch (err) {
|
|
827
|
+
(0, import_build_utils4.debug)(`Failed to determine the Rust host target: ${err}`);
|
|
828
|
+
return void 0;
|
|
829
|
+
}
|
|
156
830
|
}
|
|
157
831
|
|
|
158
832
|
// src/lib/start-dev-server.ts
|
|
159
833
|
var import_child_process = require("child_process");
|
|
160
834
|
var import_events = require("events");
|
|
161
835
|
var import_get_port = __toESM(require("get-port"));
|
|
162
|
-
var
|
|
836
|
+
var import_build_utils7 = require("@vercel/build-utils");
|
|
163
837
|
|
|
164
838
|
// src/lib/dev-build.ts
|
|
165
|
-
var
|
|
166
|
-
var
|
|
167
|
-
var
|
|
839
|
+
var import_node_path4 = __toESM(require("path"));
|
|
840
|
+
var import_execa4 = __toESM(require("execa"));
|
|
841
|
+
var import_build_utils5 = require("@vercel/build-utils");
|
|
168
842
|
async function buildExecutableForDev(workPath, entrypoint) {
|
|
169
|
-
(0,
|
|
843
|
+
(0, import_build_utils5.debug)(`Building executable for development: ${entrypoint}`);
|
|
170
844
|
const HOME = process.platform === "win32" ? assertEnv("USERPROFILE") : assertEnv("HOME");
|
|
171
845
|
const PATH = assertEnv("PATH");
|
|
172
846
|
const rustEnv = {
|
|
173
|
-
PATH: `${
|
|
847
|
+
PATH: `${import_node_path4.default.join(HOME, ".cargo/bin")}${import_node_path4.default.delimiter}${PATH}`,
|
|
174
848
|
RUSTFLAGS: [process.env.RUSTFLAGS].filter(Boolean).join(" ")
|
|
175
849
|
};
|
|
176
|
-
const entryPath =
|
|
850
|
+
const entryPath = import_node_path4.default.join(workPath, entrypoint);
|
|
177
851
|
const cargoWorkspace = await findCargoWorkspace({
|
|
178
852
|
env: rustEnv,
|
|
179
|
-
cwd:
|
|
853
|
+
cwd: import_node_path4.default.dirname(entryPath)
|
|
180
854
|
});
|
|
181
855
|
const binaryName = findBinaryName(cargoWorkspace, entryPath);
|
|
182
|
-
(0,
|
|
856
|
+
(0, import_build_utils5.debug)(`Building binary "${binaryName}" in debug mode for dev server`);
|
|
183
857
|
try {
|
|
184
|
-
await (0,
|
|
858
|
+
await (0, import_execa4.default)(
|
|
185
859
|
"cargo",
|
|
186
860
|
[
|
|
187
861
|
"build",
|
|
@@ -196,24 +870,24 @@ async function buildExecutableForDev(workPath, entrypoint) {
|
|
|
196
870
|
}
|
|
197
871
|
);
|
|
198
872
|
} catch (err) {
|
|
199
|
-
(0,
|
|
873
|
+
(0, import_build_utils5.debug)(`Cargo build failed for ${binaryName}`);
|
|
200
874
|
throw new Error(`Failed to build Rust binary for development: ${err}`);
|
|
201
875
|
}
|
|
202
876
|
const { target_directory: targetDirectory } = await getCargoMetadata({
|
|
203
877
|
cwd: workPath,
|
|
204
878
|
env: rustEnv
|
|
205
879
|
});
|
|
206
|
-
const executablePath =
|
|
880
|
+
const executablePath = import_node_path4.default.join(
|
|
207
881
|
targetDirectory,
|
|
208
882
|
"debug",
|
|
209
883
|
getExecutableName(binaryName)
|
|
210
884
|
);
|
|
211
|
-
(0,
|
|
885
|
+
(0, import_build_utils5.debug)(`Built executable at: ${executablePath}`);
|
|
212
886
|
return executablePath;
|
|
213
887
|
}
|
|
214
888
|
|
|
215
889
|
// src/lib/dev-server.ts
|
|
216
|
-
var
|
|
890
|
+
var import_build_utils6 = require("@vercel/build-utils");
|
|
217
891
|
function createDevServerEnv(baseEnv, meta = {}, port) {
|
|
218
892
|
const devEnv = {
|
|
219
893
|
// Base environment
|
|
@@ -234,7 +908,7 @@ function createDevServerEnv(baseEnv, meta = {}, port) {
|
|
|
234
908
|
delete devEnv[key];
|
|
235
909
|
}
|
|
236
910
|
});
|
|
237
|
-
(0,
|
|
911
|
+
(0, import_build_utils6.debug)(`Dev server environment: ${Object.keys(devEnv).join(", ")}`);
|
|
238
912
|
return devEnv;
|
|
239
913
|
}
|
|
240
914
|
|
|
@@ -253,7 +927,7 @@ function installGlobalCleanupHandlers() {
|
|
|
253
927
|
try {
|
|
254
928
|
child.kill("SIGTERM");
|
|
255
929
|
} catch (err) {
|
|
256
|
-
(0,
|
|
930
|
+
(0, import_build_utils7.debug)(`Error sending SIGTERM to Rust dev server on signal: ${err}`);
|
|
257
931
|
}
|
|
258
932
|
}
|
|
259
933
|
};
|
|
@@ -308,18 +982,18 @@ function terminate(child) {
|
|
|
308
982
|
try {
|
|
309
983
|
child.kill("SIGTERM");
|
|
310
984
|
} catch (err) {
|
|
311
|
-
(0,
|
|
985
|
+
(0, import_build_utils7.debug)(`Error sending SIGTERM to Rust dev server: ${err}`);
|
|
312
986
|
done();
|
|
313
987
|
return;
|
|
314
988
|
}
|
|
315
989
|
timer = setTimeout(() => {
|
|
316
|
-
(0,
|
|
990
|
+
(0, import_build_utils7.debug)(
|
|
317
991
|
`Rust dev server did not exit within ${SHUTDOWN_TIMEOUT}ms, sending SIGKILL`
|
|
318
992
|
);
|
|
319
993
|
try {
|
|
320
994
|
child.kill("SIGKILL");
|
|
321
995
|
} catch (err) {
|
|
322
|
-
(0,
|
|
996
|
+
(0, import_build_utils7.debug)(`Error sending SIGKILL to Rust dev server: ${err}`);
|
|
323
997
|
}
|
|
324
998
|
}, SHUTDOWN_TIMEOUT);
|
|
325
999
|
timer.unref?.();
|
|
@@ -332,7 +1006,7 @@ var startDevServer = async (opts) => {
|
|
|
332
1006
|
const executablePath = await buildExecutableForDev(workPath, entrypoint);
|
|
333
1007
|
const requestedPort = typeof meta.port === "number" ? meta.port : meta.env?.VERCEL_DEV_PORT ? Number(meta.env.VERCEL_DEV_PORT) : void 0;
|
|
334
1008
|
const port = typeof requestedPort === "number" && Number.isInteger(requestedPort) ? requestedPort : await (0, import_get_port.default)();
|
|
335
|
-
(0,
|
|
1009
|
+
(0, import_build_utils7.debug)(`Starting Rust dev server: ${executablePath} (port=${port})`);
|
|
336
1010
|
const devEnv = createDevServerEnv(process.env, meta, port);
|
|
337
1011
|
const child = (0, import_child_process.spawn)(executablePath, [], {
|
|
338
1012
|
cwd: workPath,
|
|
@@ -343,7 +1017,7 @@ var startDevServer = async (opts) => {
|
|
|
343
1017
|
throw new Error("Failed to start Rust dev server process");
|
|
344
1018
|
}
|
|
345
1019
|
trackDevServer(child);
|
|
346
|
-
(0,
|
|
1020
|
+
(0, import_build_utils7.debug)(`Rust dev server process started with PID: ${child.pid}`);
|
|
347
1021
|
let buffer = "";
|
|
348
1022
|
let portEmitted = false;
|
|
349
1023
|
let stderrTail = "";
|
|
@@ -355,7 +1029,7 @@ var startDevServer = async (opts) => {
|
|
|
355
1029
|
if (match) {
|
|
356
1030
|
portEmitted = true;
|
|
357
1031
|
const reportedPort = parseInt(match[1], 10);
|
|
358
|
-
(0,
|
|
1032
|
+
(0, import_build_utils7.debug)(`Rust dev server reported ready on port ${reportedPort}`);
|
|
359
1033
|
child.emit("message", { port: reportedPort }, null);
|
|
360
1034
|
buffer = "";
|
|
361
1035
|
}
|
|
@@ -376,10 +1050,10 @@ var startDevServer = async (opts) => {
|
|
|
376
1050
|
}
|
|
377
1051
|
});
|
|
378
1052
|
child.on("error", (err) => {
|
|
379
|
-
(0,
|
|
1053
|
+
(0, import_build_utils7.debug)(`Rust dev server error: ${err}`);
|
|
380
1054
|
});
|
|
381
1055
|
child.on("exit", (code, signal2) => {
|
|
382
|
-
(0,
|
|
1056
|
+
(0, import_build_utils7.debug)(`Rust dev server exited with code ${code}, signal ${signal2}`);
|
|
383
1057
|
});
|
|
384
1058
|
const onMessage = (0, import_events.once)(child, "message");
|
|
385
1059
|
const onExit = (0, import_events.once)(child, "close");
|
|
@@ -395,7 +1069,7 @@ var startDevServer = async (opts) => {
|
|
|
395
1069
|
]);
|
|
396
1070
|
if (result.state === "message") {
|
|
397
1071
|
const readyPort = typeof result.value?.port === "number" ? result.value.port : port;
|
|
398
|
-
(0,
|
|
1072
|
+
(0, import_build_utils7.debug)(`Rust dev server ready on port ${readyPort} (pid ${child.pid})`);
|
|
399
1073
|
if (!child.pid) {
|
|
400
1074
|
throw new Error("Child process has no PID");
|
|
401
1075
|
}
|
|
@@ -414,13 +1088,13 @@ var startDevServer = async (opts) => {
|
|
|
414
1088
|
`Rust dev server failed to bind port ${port} ("address already in use"). A previous dev server instance may not have shut down yet. Please retry, or ensure no other process is using that port.`
|
|
415
1089
|
);
|
|
416
1090
|
}
|
|
417
|
-
(0,
|
|
1091
|
+
(0, import_build_utils7.debug)(
|
|
418
1092
|
`Rust dev server exited before becoming ready (${reason}). Falling back to build-and-invoke mode.` + (stderr ? ` stderr:
|
|
419
1093
|
${stderr}` : "")
|
|
420
1094
|
);
|
|
421
1095
|
return null;
|
|
422
1096
|
} catch (error) {
|
|
423
|
-
(0,
|
|
1097
|
+
(0, import_build_utils7.debug)(`Failed to start Rust dev server: ${error}`);
|
|
424
1098
|
if (error instanceof RustDevServerError) {
|
|
425
1099
|
throw error;
|
|
426
1100
|
}
|
|
@@ -428,8 +1102,14 @@ ${stderr}` : "")
|
|
|
428
1102
|
}
|
|
429
1103
|
};
|
|
430
1104
|
|
|
1105
|
+
// src/standalone-server.ts
|
|
1106
|
+
var import_node_path5 = __toESM(require("path"));
|
|
1107
|
+
var import_node_child_process = require("child_process");
|
|
1108
|
+
var import_build_utils9 = require("@vercel/build-utils");
|
|
1109
|
+
var import_ipc_proxy = __toESM(require_dist());
|
|
1110
|
+
|
|
431
1111
|
// src/diagnostics.ts
|
|
432
|
-
var
|
|
1112
|
+
var import_build_utils8 = require("@vercel/build-utils");
|
|
433
1113
|
function parseSource(source) {
|
|
434
1114
|
if (!source)
|
|
435
1115
|
return { include: false };
|
|
@@ -463,6 +1143,8 @@ async function generateProjectManifest({
|
|
|
463
1143
|
const { packages, resolve } = cargoMetadata;
|
|
464
1144
|
const pkgById = new Map(packages.map((p) => [p.id, p]));
|
|
465
1145
|
const rootId = resolve.root;
|
|
1146
|
+
if (!rootId)
|
|
1147
|
+
return;
|
|
466
1148
|
const rootNode = resolve.nodes.find((n) => n.id === rootId);
|
|
467
1149
|
if (!rootNode)
|
|
468
1150
|
return;
|
|
@@ -512,7 +1194,7 @@ async function generateProjectManifest({
|
|
|
512
1194
|
transitiveEntries.push(entry);
|
|
513
1195
|
}
|
|
514
1196
|
const manifest = {
|
|
515
|
-
version:
|
|
1197
|
+
version: import_build_utils8.MANIFEST_VERSION,
|
|
516
1198
|
runtime: "rust",
|
|
517
1199
|
...framework ? { framework } : {},
|
|
518
1200
|
...serviceType ? { serviceType } : {},
|
|
@@ -522,11 +1204,332 @@ async function generateProjectManifest({
|
|
|
522
1204
|
...transitiveEntries.sort((a, b) => a.name.localeCompare(b.name))
|
|
523
1205
|
]
|
|
524
1206
|
};
|
|
525
|
-
await (0,
|
|
1207
|
+
await (0, import_build_utils8.writeProjectManifest)(manifest, workPath, "rust");
|
|
526
1208
|
} catch {
|
|
527
1209
|
}
|
|
528
1210
|
}
|
|
529
|
-
var diagnostics = (0,
|
|
1211
|
+
var diagnostics = (0, import_build_utils8.createDiagnostics)("rust");
|
|
1212
|
+
|
|
1213
|
+
// src/standalone-server.ts
|
|
1214
|
+
var STANDALONE_LAMBDA_PATH = "rust";
|
|
1215
|
+
function ownsRouteTable(service) {
|
|
1216
|
+
return !(service?.name && service.type);
|
|
1217
|
+
}
|
|
1218
|
+
function getStandaloneServerRoutes(service) {
|
|
1219
|
+
if (!ownsRouteTable(service)) {
|
|
1220
|
+
return void 0;
|
|
1221
|
+
}
|
|
1222
|
+
return [
|
|
1223
|
+
{ handle: "filesystem" },
|
|
1224
|
+
{
|
|
1225
|
+
src: "/(.*)",
|
|
1226
|
+
dest: `/${STANDALONE_LAMBDA_PATH}`,
|
|
1227
|
+
transforms: [
|
|
1228
|
+
{
|
|
1229
|
+
type: "request.path",
|
|
1230
|
+
op: "set",
|
|
1231
|
+
args: "/$1"
|
|
1232
|
+
}
|
|
1233
|
+
]
|
|
1234
|
+
}
|
|
1235
|
+
];
|
|
1236
|
+
}
|
|
1237
|
+
function getVercelRuntimeRoutes(entrypoint, service) {
|
|
1238
|
+
if (isApiHandlerBuild(entrypoint) || !ownsRouteTable(service)) {
|
|
1239
|
+
return void 0;
|
|
1240
|
+
}
|
|
1241
|
+
return [
|
|
1242
|
+
{ handle: "filesystem" },
|
|
1243
|
+
{ src: "/(.*)", dest: `/${entrypoint.replace(/\.rs$/, "")}` }
|
|
1244
|
+
];
|
|
1245
|
+
}
|
|
1246
|
+
function isApiHandlerBuild(entrypoint) {
|
|
1247
|
+
return entrypoint.startsWith("api/");
|
|
1248
|
+
}
|
|
1249
|
+
var STANDALONE_MODE_CACHE = /* @__PURE__ */ new Map();
|
|
1250
|
+
var RESOLVED_STANDALONE_MODE_CACHE = /* @__PURE__ */ new Map();
|
|
1251
|
+
var RESOLVED_STANDALONE_MODE_HINTS = /* @__PURE__ */ new Map();
|
|
1252
|
+
function useStandaloneMode(workPath, entrypoint) {
|
|
1253
|
+
if (isApiHandlerBuild(entrypoint))
|
|
1254
|
+
return Promise.resolve(false);
|
|
1255
|
+
const key = `${workPath}::${entrypoint}`;
|
|
1256
|
+
const resolved = RESOLVED_STANDALONE_MODE_HINTS.get(key);
|
|
1257
|
+
if (resolved)
|
|
1258
|
+
return resolved;
|
|
1259
|
+
let result = STANDALONE_MODE_CACHE.get(key);
|
|
1260
|
+
if (!result) {
|
|
1261
|
+
result = hasVercelRuntimeDependency(workPath, entrypoint).then(
|
|
1262
|
+
(hasCrate) => !hasCrate
|
|
1263
|
+
);
|
|
1264
|
+
STANDALONE_MODE_CACHE.set(key, result);
|
|
1265
|
+
}
|
|
1266
|
+
return result;
|
|
1267
|
+
}
|
|
1268
|
+
function resolveStandaloneMode(workPath, entrypoint, rustEnv, filterPlatform) {
|
|
1269
|
+
if (isApiHandlerBuild(entrypoint))
|
|
1270
|
+
return Promise.resolve(false);
|
|
1271
|
+
const modeKey = `${workPath}::${entrypoint}`;
|
|
1272
|
+
const cacheKey = `${modeKey}::${filterPlatform ?? "host"}`;
|
|
1273
|
+
let result = RESOLVED_STANDALONE_MODE_CACHE.get(cacheKey);
|
|
1274
|
+
if (!result) {
|
|
1275
|
+
result = (async () => {
|
|
1276
|
+
const metadata = await getCargoMetadata(
|
|
1277
|
+
{ cwd: workPath, env: rustEnv },
|
|
1278
|
+
filterPlatform
|
|
1279
|
+
);
|
|
1280
|
+
const binary = resolveStandaloneBinary(metadata, entrypoint, workPath);
|
|
1281
|
+
return !resolvedPackageUsesVercelRuntime(metadata, binary);
|
|
1282
|
+
})();
|
|
1283
|
+
RESOLVED_STANDALONE_MODE_CACHE.set(cacheKey, result);
|
|
1284
|
+
}
|
|
1285
|
+
RESOLVED_STANDALONE_MODE_HINTS.set(modeKey, result);
|
|
1286
|
+
return result;
|
|
1287
|
+
}
|
|
1288
|
+
async function buildStandaloneServer(options, { rustEnv, crossCompilation, verbose }) {
|
|
1289
|
+
const { entrypoint, workPath, config, service } = options;
|
|
1290
|
+
(0, import_build_utils9.debug)(`Building standalone Rust server: ${entrypoint}`);
|
|
1291
|
+
const lambdaOptions = await (0, import_build_utils9.getLambdaOptionsFromFunction)({
|
|
1292
|
+
sourceFile: entrypoint,
|
|
1293
|
+
config
|
|
1294
|
+
});
|
|
1295
|
+
const architecture = lambdaOptions?.architecture || "x86_64";
|
|
1296
|
+
const targetTriple = getTargetTriple(architecture);
|
|
1297
|
+
const metadataTarget = options.meta?.isDev ? await getRustHostTargetTriple(rustEnv) : targetTriple;
|
|
1298
|
+
const cargoMetadata = await getCargoMetadata(
|
|
1299
|
+
{ cwd: workPath, env: rustEnv },
|
|
1300
|
+
metadataTarget
|
|
1301
|
+
);
|
|
1302
|
+
const binary = resolveStandaloneBinary(cargoMetadata, entrypoint, workPath);
|
|
1303
|
+
assertStandaloneBinary(cargoMetadata, binary, workPath);
|
|
1304
|
+
const cargoWorkspace = await findCargoWorkspace({
|
|
1305
|
+
env: rustEnv,
|
|
1306
|
+
cwd: import_node_path5.default.dirname(binary.srcPath)
|
|
1307
|
+
});
|
|
1308
|
+
const cargoBuildConfiguration = await findCargoBuildConfiguration(cargoWorkspace);
|
|
1309
|
+
await runUserScripts(workPath);
|
|
1310
|
+
await compileCargoBinary({
|
|
1311
|
+
workPath,
|
|
1312
|
+
rustEnv,
|
|
1313
|
+
binaryName: binary.name,
|
|
1314
|
+
packageName: binary.packageName,
|
|
1315
|
+
crossCompilation,
|
|
1316
|
+
targetTriple,
|
|
1317
|
+
release: true,
|
|
1318
|
+
verbose
|
|
1319
|
+
});
|
|
1320
|
+
const userServerPath = resolveCompiledBinaryPath({
|
|
1321
|
+
targetDirectory: cargoMetadata.target_directory,
|
|
1322
|
+
crossCompilation,
|
|
1323
|
+
targetTriple,
|
|
1324
|
+
buildTarget: cargoBuildConfiguration?.build.target,
|
|
1325
|
+
variant: "release",
|
|
1326
|
+
binaryName: binary.name
|
|
1327
|
+
});
|
|
1328
|
+
(0, import_build_utils9.debug)(`Compiled standalone Rust server at ${userServerPath}`);
|
|
1329
|
+
const includedFiles = await gatherExtraFiles(config.includeFiles, workPath);
|
|
1330
|
+
const lambda = await (0, import_ipc_proxy.createStandaloneLambda)({
|
|
1331
|
+
userServerPath,
|
|
1332
|
+
architecture,
|
|
1333
|
+
lambdaOptions,
|
|
1334
|
+
includedFiles,
|
|
1335
|
+
runtimeLanguage: "rust"
|
|
1336
|
+
});
|
|
1337
|
+
lambda.zipBuffer = await lambda.createZip();
|
|
1338
|
+
await generateProjectManifest({
|
|
1339
|
+
workPath,
|
|
1340
|
+
cargoMetadata,
|
|
1341
|
+
framework: config?.framework ?? void 0,
|
|
1342
|
+
serviceType: service ? (0, import_build_utils9.getReportedServiceType)(service) : void 0
|
|
1343
|
+
});
|
|
1344
|
+
if (!ownsRouteTable(service)) {
|
|
1345
|
+
return { resultVersion: 3, result: { output: lambda } };
|
|
1346
|
+
}
|
|
1347
|
+
return {
|
|
1348
|
+
resultVersion: 2,
|
|
1349
|
+
result: {
|
|
1350
|
+
output: { [STANDALONE_LAMBDA_PATH]: lambda },
|
|
1351
|
+
routes: getStandaloneServerRoutes(service)
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
var PERSISTENT_SERVERS = /* @__PURE__ */ new Map();
|
|
1356
|
+
var PENDING_STARTS = /* @__PURE__ */ new Map();
|
|
1357
|
+
function snapshotFiles(files) {
|
|
1358
|
+
return new Map(Object.entries(files));
|
|
1359
|
+
}
|
|
1360
|
+
function filesAreUnchanged(snapshot, files) {
|
|
1361
|
+
const entries = Object.entries(files);
|
|
1362
|
+
return snapshot.size === entries.length && entries.every(([filePath, file]) => snapshot.get(filePath) === file);
|
|
1363
|
+
}
|
|
1364
|
+
var cleanupHandlersInstalled2 = false;
|
|
1365
|
+
function installGlobalCleanupHandlers2() {
|
|
1366
|
+
if (cleanupHandlersInstalled2)
|
|
1367
|
+
return;
|
|
1368
|
+
cleanupHandlersInstalled2 = true;
|
|
1369
|
+
const killAll = () => {
|
|
1370
|
+
for (const [key, server] of PERSISTENT_SERVERS.entries()) {
|
|
1371
|
+
PERSISTENT_SERVERS.delete(key);
|
|
1372
|
+
try {
|
|
1373
|
+
server.handle.child.kill("SIGKILL");
|
|
1374
|
+
} catch (err) {
|
|
1375
|
+
(0, import_build_utils9.debug)(`Error killing standalone Rust dev server: ${err}`);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
};
|
|
1379
|
+
process.on("SIGINT", killAll);
|
|
1380
|
+
process.on("SIGTERM", killAll);
|
|
1381
|
+
process.on("exit", killAll);
|
|
1382
|
+
}
|
|
1383
|
+
function toDevServerResult(serverKey, handle) {
|
|
1384
|
+
return {
|
|
1385
|
+
port: handle.port,
|
|
1386
|
+
pid: handle.pid,
|
|
1387
|
+
persistent: true,
|
|
1388
|
+
shutdown: async () => {
|
|
1389
|
+
if (PERSISTENT_SERVERS.get(serverKey)?.handle === handle) {
|
|
1390
|
+
PERSISTENT_SERVERS.delete(serverKey);
|
|
1391
|
+
}
|
|
1392
|
+
await handle.close();
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
async function startStandaloneDevServer(opts) {
|
|
1397
|
+
const { entrypoint, workPath, meta = {} } = opts;
|
|
1398
|
+
const serverKey = `${workPath}::${entrypoint}`;
|
|
1399
|
+
const existing = PERSISTENT_SERVERS.get(serverKey);
|
|
1400
|
+
if (existing && filesAreUnchanged(existing.files, opts.files)) {
|
|
1401
|
+
return toDevServerResult(serverKey, existing.handle);
|
|
1402
|
+
}
|
|
1403
|
+
const pending = PENDING_STARTS.get(serverKey);
|
|
1404
|
+
if (pending) {
|
|
1405
|
+
await pending;
|
|
1406
|
+
return startStandaloneDevServer(opts);
|
|
1407
|
+
}
|
|
1408
|
+
const startPromise = (async () => {
|
|
1409
|
+
if (existing) {
|
|
1410
|
+
PERSISTENT_SERVERS.delete(serverKey);
|
|
1411
|
+
await existing.handle.close();
|
|
1412
|
+
}
|
|
1413
|
+
await installRustToolchain();
|
|
1414
|
+
const rustEnv = createRustEnv();
|
|
1415
|
+
const hostTarget = await getRustHostTargetTriple(rustEnv);
|
|
1416
|
+
const cargoMetadata = await getCargoMetadata(
|
|
1417
|
+
{ cwd: workPath, env: rustEnv },
|
|
1418
|
+
hostTarget
|
|
1419
|
+
);
|
|
1420
|
+
const binary = resolveStandaloneBinary(cargoMetadata, entrypoint, workPath);
|
|
1421
|
+
assertStandaloneBinary(cargoMetadata, binary, workPath);
|
|
1422
|
+
const cargoWorkspace = await findCargoWorkspace({
|
|
1423
|
+
env: rustEnv,
|
|
1424
|
+
cwd: import_node_path5.default.dirname(binary.srcPath)
|
|
1425
|
+
});
|
|
1426
|
+
const cargoBuildConfiguration = await findCargoBuildConfiguration(cargoWorkspace);
|
|
1427
|
+
await compileCargoBinary({
|
|
1428
|
+
workPath,
|
|
1429
|
+
rustEnv,
|
|
1430
|
+
binaryName: binary.name,
|
|
1431
|
+
packageName: binary.packageName,
|
|
1432
|
+
crossCompilation: false,
|
|
1433
|
+
targetTriple: getTargetTriple("x86_64"),
|
|
1434
|
+
release: false,
|
|
1435
|
+
verbose: Boolean(process.env.VERCEL_BUILDER_DEBUG ?? false)
|
|
1436
|
+
});
|
|
1437
|
+
const executablePath = resolveCompiledBinaryPath({
|
|
1438
|
+
targetDirectory: cargoMetadata.target_directory,
|
|
1439
|
+
crossCompilation: false,
|
|
1440
|
+
targetTriple: getTargetTriple("x86_64"),
|
|
1441
|
+
buildTarget: cargoBuildConfiguration?.build.target,
|
|
1442
|
+
variant: "debug",
|
|
1443
|
+
binaryName: binary.name
|
|
1444
|
+
});
|
|
1445
|
+
const env = (0, import_build_utils9.cloneEnv)(process.env, meta.env);
|
|
1446
|
+
(0, import_build_utils9.debug)(`Starting standalone Rust dev server: ${executablePath}`);
|
|
1447
|
+
const handle = await (0, import_ipc_proxy.startDevProxy)({
|
|
1448
|
+
port: typeof meta.port === "number" ? meta.port : void 0,
|
|
1449
|
+
env,
|
|
1450
|
+
label: "Standalone Rust dev server",
|
|
1451
|
+
spawnServer: (internalPort) => {
|
|
1452
|
+
const child = (0, import_node_child_process.spawn)(executablePath, [], {
|
|
1453
|
+
cwd: workPath,
|
|
1454
|
+
env: (0, import_build_utils9.cloneEnv)(env, { PORT: String(internalPort) }),
|
|
1455
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1456
|
+
});
|
|
1457
|
+
const forward = (stream, onData, fallback) => {
|
|
1458
|
+
stream?.on("data", (data) => {
|
|
1459
|
+
const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
1460
|
+
if (onData) {
|
|
1461
|
+
onData(chunk);
|
|
1462
|
+
} else {
|
|
1463
|
+
fallback.write(
|
|
1464
|
+
new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength)
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1467
|
+
});
|
|
1468
|
+
};
|
|
1469
|
+
forward(child.stdout, opts.onStdout, process.stdout);
|
|
1470
|
+
forward(child.stderr, opts.onStderr, process.stderr);
|
|
1471
|
+
return child;
|
|
1472
|
+
}
|
|
1473
|
+
});
|
|
1474
|
+
const server = { handle, files: snapshotFiles(opts.files) };
|
|
1475
|
+
PERSISTENT_SERVERS.set(serverKey, server);
|
|
1476
|
+
handle.child.once("exit", () => {
|
|
1477
|
+
if (PERSISTENT_SERVERS.get(serverKey)?.handle === handle) {
|
|
1478
|
+
PERSISTENT_SERVERS.delete(serverKey);
|
|
1479
|
+
}
|
|
1480
|
+
handle.close().catch((err) => {
|
|
1481
|
+
(0, import_build_utils9.debug)(`Error closing standalone Rust dev proxy: ${err}`);
|
|
1482
|
+
});
|
|
1483
|
+
});
|
|
1484
|
+
installGlobalCleanupHandlers2();
|
|
1485
|
+
return server;
|
|
1486
|
+
})();
|
|
1487
|
+
PENDING_STARTS.set(serverKey, startPromise);
|
|
1488
|
+
try {
|
|
1489
|
+
const server = await startPromise;
|
|
1490
|
+
return toDevServerResult(serverKey, server.handle);
|
|
1491
|
+
} finally {
|
|
1492
|
+
if (PENDING_STARTS.get(serverKey) === startPromise) {
|
|
1493
|
+
PENDING_STARTS.delete(serverKey);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
// src/entrypoint.ts
|
|
1499
|
+
var import_node_path6 = __toESM(require("path"));
|
|
1500
|
+
var import_node_fs3 = require("fs");
|
|
1501
|
+
var import_build_utils10 = require("@vercel/build-utils");
|
|
1502
|
+
async function detectRustEntrypoint(workPath, configuredEntrypoint) {
|
|
1503
|
+
if (configuredEntrypoint?.endsWith(".rs") && (0, import_node_fs3.existsSync)(import_node_path6.default.join(workPath, configuredEntrypoint))) {
|
|
1504
|
+
(0, import_build_utils10.debug)(`Using configured Rust entrypoint: ${configuredEntrypoint}`);
|
|
1505
|
+
return configuredEntrypoint;
|
|
1506
|
+
}
|
|
1507
|
+
try {
|
|
1508
|
+
const metadata = await getCargoMetadata({
|
|
1509
|
+
cwd: workPath,
|
|
1510
|
+
env: createRustEnv()
|
|
1511
|
+
});
|
|
1512
|
+
const binary = resolveStandaloneBinary(
|
|
1513
|
+
metadata,
|
|
1514
|
+
configuredEntrypoint,
|
|
1515
|
+
workPath
|
|
1516
|
+
);
|
|
1517
|
+
const relative = (0, import_build_utils10.normalizePath)(
|
|
1518
|
+
import_node_path6.default.relative(realPath(workPath), realPath(binary.srcPath))
|
|
1519
|
+
);
|
|
1520
|
+
(0, import_build_utils10.debug)(`Detected Rust entrypoint: ${relative} (bin "${binary.name}")`);
|
|
1521
|
+
return relative;
|
|
1522
|
+
} catch (err) {
|
|
1523
|
+
(0, import_build_utils10.debug)(`Failed to detect Rust entrypoint: ${err}`);
|
|
1524
|
+
return null;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
var detectEntrypoint = async ({ workPath }) => {
|
|
1528
|
+
const file = await detectRustEntrypoint(workPath);
|
|
1529
|
+
if (!file)
|
|
1530
|
+
return null;
|
|
1531
|
+
return { kind: "file", entrypoint: file };
|
|
1532
|
+
};
|
|
530
1533
|
|
|
531
1534
|
// src/index.ts
|
|
532
1535
|
async function buildHandler(options) {
|
|
@@ -540,70 +1543,70 @@ async function buildHandler(options) {
|
|
|
540
1543
|
);
|
|
541
1544
|
}
|
|
542
1545
|
await installRustToolchain();
|
|
543
|
-
(0,
|
|
544
|
-
const downloadedFiles = await (0,
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
1546
|
+
(0, import_build_utils11.debug)("Creating file system");
|
|
1547
|
+
const downloadedFiles = await (0, import_build_utils11.download)(
|
|
1548
|
+
excludeCargoTargetDir(files, process.env, workPath),
|
|
1549
|
+
workPath,
|
|
1550
|
+
meta
|
|
1551
|
+
);
|
|
1552
|
+
const rustEnv = createRustEnv();
|
|
1553
|
+
const lambdaOptions = await (0, import_build_utils11.getLambdaOptionsFromFunction)({
|
|
1554
|
+
sourceFile: entrypoint,
|
|
1555
|
+
config
|
|
1556
|
+
});
|
|
1557
|
+
const architecture = lambdaOptions?.architecture || "x86_64";
|
|
1558
|
+
const targetTriple = getTargetTriple(architecture);
|
|
1559
|
+
const modeTarget = meta?.isDev ? await getRustHostTargetTriple(rustEnv) : targetTriple;
|
|
1560
|
+
if (await resolveStandaloneMode(workPath, entrypoint, rustEnv, modeTarget)) {
|
|
1561
|
+
return buildStandaloneServer(options, {
|
|
1562
|
+
rustEnv,
|
|
1563
|
+
crossCompilation: crossCompilationEnabled,
|
|
1564
|
+
verbose: BUILDER_DEBUG
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
const downloadedEntry = downloadedFiles[entrypoint];
|
|
1568
|
+
if (!downloadedEntry) {
|
|
1569
|
+
throw new Error(
|
|
1570
|
+
`Entrypoint "${entrypoint}" was not found. Make sure the file exists, or set the entrypoint to the Rust source file you want to deploy.`
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
const entryPath = downloadedEntry.fsPath;
|
|
552
1574
|
const cargoWorkspace = await findCargoWorkspace({
|
|
553
1575
|
env: rustEnv,
|
|
554
|
-
cwd:
|
|
1576
|
+
cwd: import_node_path7.default.dirname(entryPath)
|
|
555
1577
|
});
|
|
556
1578
|
const binaryName = findBinaryName(cargoWorkspace, entryPath);
|
|
557
1579
|
const cargoBuildConfiguration = await findCargoBuildConfiguration(cargoWorkspace);
|
|
558
1580
|
await runUserScripts(workPath);
|
|
559
1581
|
const extraFiles = await gatherExtraFiles(config.includeFiles, workPath);
|
|
560
|
-
const lambdaOptions = await (0, import_build_utils7.getLambdaOptionsFromFunction)({
|
|
561
|
-
sourceFile: entrypoint,
|
|
562
|
-
config
|
|
563
|
-
});
|
|
564
|
-
const architecture = lambdaOptions?.architecture || "x86_64";
|
|
565
1582
|
const buildVariant = meta?.isDev ? "debug" : "release";
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
(0, import_build_utils7.debug)(
|
|
577
|
-
`Running \`cargo build\` for \`${binaryName}\` (\`${architecture}\`)`
|
|
578
|
-
);
|
|
579
|
-
await (0, import_execa4.default)("cargo", args, {
|
|
580
|
-
cwd: workPath,
|
|
581
|
-
env: rustEnv
|
|
582
|
-
});
|
|
583
|
-
} catch (err) {
|
|
584
|
-
(0, import_build_utils7.debug)(`Running \`cargo build\` for \`${binaryName}\` failed`);
|
|
585
|
-
throw err;
|
|
586
|
-
}
|
|
587
|
-
(0, import_build_utils7.debug)(
|
|
1583
|
+
await compileCargoBinary({
|
|
1584
|
+
workPath,
|
|
1585
|
+
rustEnv,
|
|
1586
|
+
binaryName,
|
|
1587
|
+
crossCompilation: crossCompilationEnabled,
|
|
1588
|
+
targetTriple,
|
|
1589
|
+
release: crossCompilationEnabled || !meta?.isDev,
|
|
1590
|
+
verbose: BUILDER_DEBUG
|
|
1591
|
+
});
|
|
1592
|
+
(0, import_build_utils11.debug)(
|
|
588
1593
|
`Building \`${binaryName}\` for \`${process.platform}\` (\`${architecture}\`) completed`
|
|
589
1594
|
);
|
|
590
1595
|
const cargoMetadata = await getCargoMetadata(
|
|
591
1596
|
{ cwd: workPath, env: rustEnv },
|
|
592
1597
|
targetTriple
|
|
593
1598
|
);
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
getExecutableName(binaryName)
|
|
603
|
-
);
|
|
1599
|
+
const bin = resolveCompiledBinaryPath({
|
|
1600
|
+
targetDirectory: cargoMetadata.target_directory,
|
|
1601
|
+
crossCompilation: crossCompilationEnabled,
|
|
1602
|
+
targetTriple,
|
|
1603
|
+
buildTarget: cargoBuildConfiguration?.build.target,
|
|
1604
|
+
variant: buildVariant,
|
|
1605
|
+
binaryName
|
|
1606
|
+
});
|
|
604
1607
|
const handler = getExecutableName("executable");
|
|
605
|
-
const executableFile = new
|
|
606
|
-
const lambda = new
|
|
1608
|
+
const executableFile = new import_build_utils11.FileFsRef({ mode: 493, fsPath: bin });
|
|
1609
|
+
const lambda = new import_build_utils11.Lambda({
|
|
607
1610
|
...lambdaOptions,
|
|
608
1611
|
files: {
|
|
609
1612
|
...extraFiles,
|
|
@@ -618,13 +1621,13 @@ async function buildHandler(options) {
|
|
|
618
1621
|
lambda.zipBuffer = await lambda.createZip();
|
|
619
1622
|
let resolvedRustVersion;
|
|
620
1623
|
try {
|
|
621
|
-
const { stdout: rustcOut } = await (0,
|
|
1624
|
+
const { stdout: rustcOut } = await (0, import_execa5.default)("rustc", ["--version"], {
|
|
622
1625
|
env: rustEnv,
|
|
623
1626
|
cwd: workPath
|
|
624
1627
|
});
|
|
625
1628
|
resolvedRustVersion = rustcOut.split(" ")[1];
|
|
626
1629
|
} catch {
|
|
627
|
-
(0,
|
|
1630
|
+
(0, import_build_utils11.debug)("Failed to determine rustc version");
|
|
628
1631
|
}
|
|
629
1632
|
const rootPkg = cargoMetadata.packages.find(
|
|
630
1633
|
(p) => p.id === cargoMetadata.resolve.root
|
|
@@ -634,23 +1637,27 @@ async function buildHandler(options) {
|
|
|
634
1637
|
workPath,
|
|
635
1638
|
cargoMetadata,
|
|
636
1639
|
framework: config?.framework ?? void 0,
|
|
637
|
-
serviceType: service ? (0,
|
|
1640
|
+
serviceType: service ? (0, import_build_utils11.getReportedServiceType)(service) : void 0,
|
|
638
1641
|
runtimeVersion: resolvedRustVersion ? {
|
|
639
1642
|
...requestedRustVersion ? { requested: requestedRustVersion } : {},
|
|
640
1643
|
resolved: resolvedRustVersion
|
|
641
1644
|
} : void 0
|
|
642
1645
|
});
|
|
643
|
-
(0,
|
|
1646
|
+
(0, import_build_utils11.debug)(`generating function for \`${entrypoint}\``);
|
|
1647
|
+
const routes = getVercelRuntimeRoutes(entrypoint, service);
|
|
644
1648
|
return {
|
|
645
|
-
|
|
1649
|
+
resultVersion: 3,
|
|
1650
|
+
result: { output: lambda, ...routes ? { routes } : {} }
|
|
646
1651
|
};
|
|
647
1652
|
}
|
|
648
1653
|
var runtime = {
|
|
649
|
-
|
|
1654
|
+
// Standalone builds need a named V2 output and their own route table. The
|
|
1655
|
+
// classic `vercel_runtime` path stays V3 so preset routing remains intact.
|
|
1656
|
+
version: -1,
|
|
650
1657
|
build: buildHandler,
|
|
651
1658
|
prepareCache: async ({ workPath }) => {
|
|
652
|
-
(0,
|
|
653
|
-
const cacheFiles = await (0,
|
|
1659
|
+
(0, import_build_utils11.debug)(`Caching \`${workPath}\``);
|
|
1660
|
+
const cacheFiles = await (0, import_build_utils11.glob)("target/**", workPath);
|
|
654
1661
|
for (const f of Object.keys(cacheFiles)) {
|
|
655
1662
|
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);
|
|
656
1663
|
if (!accept) {
|
|
@@ -659,21 +1666,35 @@ var runtime = {
|
|
|
659
1666
|
}
|
|
660
1667
|
return cacheFiles;
|
|
661
1668
|
},
|
|
662
|
-
startDevServer
|
|
1669
|
+
startDevServer: async (options) => {
|
|
1670
|
+
const { workPath, entrypoint } = options;
|
|
1671
|
+
await installRustToolchain();
|
|
1672
|
+
const rustEnv = createRustEnv();
|
|
1673
|
+
const hostTarget = await getRustHostTargetTriple(rustEnv);
|
|
1674
|
+
if (await resolveStandaloneMode(workPath, entrypoint, rustEnv, hostTarget)) {
|
|
1675
|
+
return startStandaloneDevServer(options);
|
|
1676
|
+
}
|
|
1677
|
+
return startDevServer(options);
|
|
1678
|
+
},
|
|
663
1679
|
shouldServe: async (options) => {
|
|
664
|
-
(0,
|
|
1680
|
+
(0, import_build_utils11.debug)(`Requested ${options.requestPath} for ${options.entrypoint}`);
|
|
1681
|
+
if (await useStandaloneMode(options.workPath, options.entrypoint)) {
|
|
1682
|
+
return true;
|
|
1683
|
+
}
|
|
665
1684
|
const entrypointWithoutExt = options.entrypoint.replace(/\.rs$/, "");
|
|
666
1685
|
const matches = options.requestPath === options.entrypoint || options.requestPath === entrypointWithoutExt;
|
|
667
|
-
(0,
|
|
1686
|
+
(0, import_build_utils11.debug)(
|
|
668
1687
|
`shouldServe: ${matches} (entrypointWithoutExt: ${entrypointWithoutExt})`
|
|
669
1688
|
);
|
|
670
|
-
return
|
|
1689
|
+
return matches;
|
|
671
1690
|
}
|
|
672
1691
|
};
|
|
673
1692
|
var { version, build, prepareCache, startDevServer: startDevServer2, shouldServe } = runtime;
|
|
674
1693
|
// Annotate the CommonJS export names for ESM import in node:
|
|
675
1694
|
0 && (module.exports = {
|
|
676
1695
|
build,
|
|
1696
|
+
detectEntrypoint,
|
|
1697
|
+
detectRustEntrypoint,
|
|
677
1698
|
diagnostics,
|
|
678
1699
|
prepareCache,
|
|
679
1700
|
shouldServe,
|