@vercel/rust 1.4.2 → 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/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 import_node_path4 = __toESM(require("path"));
42
- var import_build_utils7 = require("@vercel/build-utils");
43
- var import_execa4 = __toESM(require("execa"));
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 = import_node_path.default.relative(import_node_path.default.dirname(workspace.root), entryPath);
112
- const entry = bin.find((binEntry) => binEntry.path === relativePath);
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 import_build_utils2 = require("@vercel/build-utils");
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, import_build_utils2.debug)("Running `build.sh`");
138
- await (0, import_build_utils2.runShellScript)(buildScriptPath);
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, import_build_utils2.debug)(
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, import_build_utils2.glob)(pattern, workPath))
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, import_build_utils2.glob)(globMatcher, workPath);
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 import_build_utils5 = require("@vercel/build-utils");
836
+ var import_build_utils7 = require("@vercel/build-utils");
163
837
 
164
838
  // src/lib/dev-build.ts
165
- var import_node_path3 = __toESM(require("path"));
166
- var import_execa3 = __toESM(require("execa"));
167
- var import_build_utils3 = require("@vercel/build-utils");
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, import_build_utils3.debug)(`Building executable for development: ${entrypoint}`);
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: `${import_node_path3.default.join(HOME, ".cargo/bin")}${import_node_path3.default.delimiter}${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 = import_node_path3.default.join(workPath, entrypoint);
850
+ const entryPath = import_node_path4.default.join(workPath, entrypoint);
177
851
  const cargoWorkspace = await findCargoWorkspace({
178
852
  env: rustEnv,
179
- cwd: import_node_path3.default.dirname(entryPath)
853
+ cwd: import_node_path4.default.dirname(entryPath)
180
854
  });
181
855
  const binaryName = findBinaryName(cargoWorkspace, entryPath);
182
- (0, import_build_utils3.debug)(`Building binary "${binaryName}" in debug mode for dev server`);
856
+ (0, import_build_utils5.debug)(`Building binary "${binaryName}" in debug mode for dev server`);
183
857
  try {
184
- await (0, import_execa3.default)(
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, import_build_utils3.debug)(`Cargo build failed for ${binaryName}`);
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 = import_node_path3.default.join(
880
+ const executablePath = import_node_path4.default.join(
207
881
  targetDirectory,
208
882
  "debug",
209
883
  getExecutableName(binaryName)
210
884
  );
211
- (0, import_build_utils3.debug)(`Built executable at: ${executablePath}`);
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 import_build_utils4 = require("@vercel/build-utils");
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, import_build_utils4.debug)(`Dev server environment: ${Object.keys(devEnv).join(", ")}`);
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, import_build_utils5.debug)(`Error sending SIGTERM to Rust dev server on signal: ${err}`);
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, import_build_utils5.debug)(`Error sending SIGTERM to Rust dev server: ${err}`);
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, import_build_utils5.debug)(
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, import_build_utils5.debug)(`Error sending SIGKILL to Rust dev server: ${err}`);
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, import_build_utils5.debug)(`Starting Rust dev server: ${executablePath} (port=${port})`);
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, import_build_utils5.debug)(`Rust dev server process started with PID: ${child.pid}`);
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, import_build_utils5.debug)(`Rust dev server reported ready on port ${reportedPort}`);
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, import_build_utils5.debug)(`Rust dev server error: ${err}`);
1053
+ (0, import_build_utils7.debug)(`Rust dev server error: ${err}`);
380
1054
  });
381
1055
  child.on("exit", (code, signal2) => {
382
- (0, import_build_utils5.debug)(`Rust dev server exited with code ${code}, signal ${signal2}`);
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, import_build_utils5.debug)(`Rust dev server ready on port ${readyPort} (pid ${child.pid})`);
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, import_build_utils5.debug)(
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, import_build_utils5.debug)(`Failed to start Rust dev server: ${error}`);
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 import_build_utils6 = require("@vercel/build-utils");
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: import_build_utils6.MANIFEST_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, import_build_utils6.writeProjectManifest)(manifest, workPath, "rust");
1207
+ await (0, import_build_utils8.writeProjectManifest)(manifest, workPath, "rust");
526
1208
  } catch {
527
1209
  }
528
1210
  }
529
- var diagnostics = (0, import_build_utils6.createDiagnostics)("rust");
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, import_build_utils7.debug)("Creating file system");
544
- const downloadedFiles = await (0, import_build_utils7.download)(files, workPath, meta);
545
- const entryPath = downloadedFiles[entrypoint].fsPath;
546
- const HOME = process.platform === "win32" ? assertEnv("USERPROFILE") : assertEnv("HOME");
547
- const PATH = assertEnv("PATH");
548
- const rustEnv = {
549
- PATH: `${import_node_path4.default.join(HOME, ".cargo/bin")}${import_node_path4.default.delimiter}${PATH}`,
550
- RUSTFLAGS: [process.env.RUSTFLAGS].filter(Boolean).join(" ")
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: import_node_path4.default.dirname(entryPath)
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
- const buildTarget = cargoBuildConfiguration?.build.target ?? "";
567
- const targetTriple = architecture === "x86_64" ? "x86_64-unknown-linux-gnu" : "aarch64-unknown-linux-gnu";
568
- try {
569
- const args = crossCompilationEnabled ? ["zigbuild", "--target", targetTriple, "--bin", binaryName].concat(
570
- BUILDER_DEBUG ? ["--verbose"] : ["--quiet"],
571
- ["--release"]
572
- ) : ["build", "--bin", binaryName].concat(
573
- BUILDER_DEBUG ? ["--verbose"] : ["--quiet"],
574
- meta?.isDev ? [] : ["--release"]
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
- let { target_directory: targetDirectory } = cargoMetadata;
595
- if (crossCompilationEnabled) {
596
- targetDirectory = import_node_path4.default.join(targetDirectory, targetTriple);
597
- }
598
- targetDirectory = import_node_path4.default.join(targetDirectory, buildTarget);
599
- const bin = import_node_path4.default.join(
600
- targetDirectory,
601
- buildVariant,
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 import_build_utils7.FileFsRef({ mode: 493, fsPath: bin });
606
- const lambda = new import_build_utils7.Lambda({
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, import_execa4.default)("rustc", ["--version"], {
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, import_build_utils7.debug)("Failed to determine rustc version");
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, import_build_utils7.getReportedServiceType)(service) : void 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, import_build_utils7.debug)(`generating function for \`${entrypoint}\``);
1646
+ (0, import_build_utils11.debug)(`generating function for \`${entrypoint}\``);
1647
+ const routes = getVercelRuntimeRoutes(entrypoint, service);
644
1648
  return {
645
- output: lambda
1649
+ resultVersion: 3,
1650
+ result: { output: lambda, ...routes ? { routes } : {} }
646
1651
  };
647
1652
  }
648
1653
  var runtime = {
649
- version: 3,
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, import_build_utils7.debug)(`Caching \`${workPath}\``);
653
- const cacheFiles = await (0, import_build_utils7.glob)("target/**", workPath);
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, import_build_utils7.debug)(`Requested ${options.requestPath} for ${options.entrypoint}`);
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, import_build_utils7.debug)(
1686
+ (0, import_build_utils11.debug)(
668
1687
  `shouldServe: ${matches} (entrypointWithoutExt: ${entrypointWithoutExt})`
669
1688
  );
670
- return Promise.resolve(matches);
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,