@vercel/rust 1.3.0 → 1.4.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 +150 -38
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -158,6 +158,7 @@ async function gatherExtraFiles(globMatcher, workPath) {
|
|
|
158
158
|
// src/lib/start-dev-server.ts
|
|
159
159
|
var import_child_process = require("child_process");
|
|
160
160
|
var import_events = require("events");
|
|
161
|
+
var import_get_port = __toESM(require("get-port"));
|
|
161
162
|
var import_build_utils5 = require("@vercel/build-utils");
|
|
162
163
|
|
|
163
164
|
// src/lib/dev-build.ts
|
|
@@ -213,7 +214,7 @@ async function buildExecutableForDev(workPath, entrypoint) {
|
|
|
213
214
|
|
|
214
215
|
// src/lib/dev-server.ts
|
|
215
216
|
var import_build_utils4 = require("@vercel/build-utils");
|
|
216
|
-
function createDevServerEnv(baseEnv, meta = {}) {
|
|
217
|
+
function createDevServerEnv(baseEnv, meta = {}, port) {
|
|
217
218
|
const devEnv = {
|
|
218
219
|
// Base environment
|
|
219
220
|
...Object.fromEntries(
|
|
@@ -225,6 +226,9 @@ function createDevServerEnv(baseEnv, meta = {}) {
|
|
|
225
226
|
// Runtime environment from meta
|
|
226
227
|
...meta.env || {}
|
|
227
228
|
};
|
|
229
|
+
if (typeof port === "number" && Number.isInteger(port)) {
|
|
230
|
+
devEnv.VERCEL_DEV_PORT = String(port);
|
|
231
|
+
}
|
|
228
232
|
Object.keys(devEnv).forEach((key) => {
|
|
229
233
|
if (devEnv[key] === void 0) {
|
|
230
234
|
delete devEnv[key];
|
|
@@ -235,49 +239,147 @@ function createDevServerEnv(baseEnv, meta = {}) {
|
|
|
235
239
|
}
|
|
236
240
|
|
|
237
241
|
// src/lib/start-dev-server.ts
|
|
242
|
+
var SHUTDOWN_TIMEOUT = 35e3;
|
|
243
|
+
var ADDR_IN_USE_RE = /address (already )?in use|AddrInUse|EADDRINUSE/i;
|
|
244
|
+
var MAX_STDERR_CAPTURE = 8192;
|
|
245
|
+
var RUNNING_DEV_SERVERS = /* @__PURE__ */ new Set();
|
|
246
|
+
var cleanupHandlersInstalled = false;
|
|
247
|
+
function installGlobalCleanupHandlers() {
|
|
248
|
+
if (cleanupHandlersInstalled)
|
|
249
|
+
return;
|
|
250
|
+
cleanupHandlersInstalled = true;
|
|
251
|
+
const onSignal = () => {
|
|
252
|
+
for (const child of RUNNING_DEV_SERVERS) {
|
|
253
|
+
try {
|
|
254
|
+
child.kill("SIGTERM");
|
|
255
|
+
} catch (err) {
|
|
256
|
+
(0, import_build_utils5.debug)(`Error sending SIGTERM to Rust dev server on signal: ${err}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
process.on("SIGINT", onSignal);
|
|
261
|
+
process.on("SIGTERM", onSignal);
|
|
262
|
+
process.on("SIGHUP", onSignal);
|
|
263
|
+
process.on("exit", () => {
|
|
264
|
+
for (const child of RUNNING_DEV_SERVERS) {
|
|
265
|
+
if (child.pid) {
|
|
266
|
+
try {
|
|
267
|
+
process.kill(child.pid, "SIGKILL");
|
|
268
|
+
} catch {
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
RUNNING_DEV_SERVERS.clear();
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
function trackDevServer(child) {
|
|
276
|
+
installGlobalCleanupHandlers();
|
|
277
|
+
RUNNING_DEV_SERVERS.add(child);
|
|
278
|
+
const untrack = () => {
|
|
279
|
+
RUNNING_DEV_SERVERS.delete(child);
|
|
280
|
+
};
|
|
281
|
+
child.once("exit", untrack);
|
|
282
|
+
child.once("close", untrack);
|
|
283
|
+
}
|
|
284
|
+
var RustDevServerError = class extends Error {
|
|
285
|
+
constructor(message) {
|
|
286
|
+
super(message);
|
|
287
|
+
this.name = "RustDevServerError";
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
function terminate(child) {
|
|
291
|
+
return new Promise((resolve) => {
|
|
292
|
+
if (!child.pid || child.exitCode !== null || child.signalCode !== null) {
|
|
293
|
+
resolve();
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
let timer;
|
|
297
|
+
let settled = false;
|
|
298
|
+
const done = () => {
|
|
299
|
+
if (settled)
|
|
300
|
+
return;
|
|
301
|
+
settled = true;
|
|
302
|
+
if (timer)
|
|
303
|
+
clearTimeout(timer);
|
|
304
|
+
resolve();
|
|
305
|
+
};
|
|
306
|
+
child.once("exit", done);
|
|
307
|
+
child.once("close", done);
|
|
308
|
+
try {
|
|
309
|
+
child.kill("SIGTERM");
|
|
310
|
+
} catch (err) {
|
|
311
|
+
(0, import_build_utils5.debug)(`Error sending SIGTERM to Rust dev server: ${err}`);
|
|
312
|
+
done();
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
timer = setTimeout(() => {
|
|
316
|
+
(0, import_build_utils5.debug)(
|
|
317
|
+
`Rust dev server did not exit within ${SHUTDOWN_TIMEOUT}ms, sending SIGKILL`
|
|
318
|
+
);
|
|
319
|
+
try {
|
|
320
|
+
child.kill("SIGKILL");
|
|
321
|
+
} catch (err) {
|
|
322
|
+
(0, import_build_utils5.debug)(`Error sending SIGKILL to Rust dev server: ${err}`);
|
|
323
|
+
}
|
|
324
|
+
}, SHUTDOWN_TIMEOUT);
|
|
325
|
+
timer.unref?.();
|
|
326
|
+
});
|
|
327
|
+
}
|
|
238
328
|
var startDevServer = async (opts) => {
|
|
239
|
-
const { entrypoint, workPath, meta = {} } = opts;
|
|
329
|
+
const { entrypoint, workPath, meta = {}, onStdout, onStderr } = opts;
|
|
240
330
|
try {
|
|
241
331
|
await installRustToolchain();
|
|
242
332
|
const executablePath = await buildExecutableForDev(workPath, entrypoint);
|
|
243
|
-
|
|
244
|
-
const
|
|
333
|
+
const requestedPort = typeof meta.port === "number" ? meta.port : meta.env?.VERCEL_DEV_PORT ? Number(meta.env.VERCEL_DEV_PORT) : void 0;
|
|
334
|
+
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})`);
|
|
336
|
+
const devEnv = createDevServerEnv(process.env, meta, port);
|
|
245
337
|
const child = (0, import_child_process.spawn)(executablePath, [], {
|
|
246
338
|
cwd: workPath,
|
|
247
339
|
env: devEnv,
|
|
248
340
|
stdio: ["pipe", "pipe", "pipe"]
|
|
249
341
|
});
|
|
250
342
|
if (!child.pid) {
|
|
251
|
-
throw new Error("Failed to start dev server process");
|
|
343
|
+
throw new Error("Failed to start Rust dev server process");
|
|
252
344
|
}
|
|
253
|
-
(
|
|
345
|
+
trackDevServer(child);
|
|
346
|
+
(0, import_build_utils5.debug)(`Rust dev server process started with PID: ${child.pid}`);
|
|
254
347
|
let buffer = "";
|
|
255
348
|
let portEmitted = false;
|
|
349
|
+
let stderrTail = "";
|
|
256
350
|
child.stdout?.on("data", (data) => {
|
|
257
|
-
const
|
|
258
|
-
buffer +=
|
|
259
|
-
if (!portEmitted
|
|
260
|
-
const
|
|
261
|
-
if (
|
|
262
|
-
const port = parseInt(portMatch[1], 10);
|
|
263
|
-
(0, import_build_utils5.debug)(
|
|
264
|
-
`Rust dev server detected port ${port}, emitting message event`
|
|
265
|
-
);
|
|
266
|
-
child.emit("message", { port }, null);
|
|
351
|
+
const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
352
|
+
buffer += chunk.toString();
|
|
353
|
+
if (!portEmitted) {
|
|
354
|
+
const match = buffer.match(/Dev server listening:\s*(\d+)/);
|
|
355
|
+
if (match) {
|
|
267
356
|
portEmitted = true;
|
|
357
|
+
const reportedPort = parseInt(match[1], 10);
|
|
358
|
+
(0, import_build_utils5.debug)(`Rust dev server reported ready on port ${reportedPort}`);
|
|
359
|
+
child.emit("message", { port: reportedPort }, null);
|
|
360
|
+
buffer = "";
|
|
268
361
|
}
|
|
269
|
-
buffer = "";
|
|
270
362
|
}
|
|
271
|
-
|
|
363
|
+
if (onStdout) {
|
|
364
|
+
onStdout(chunk);
|
|
365
|
+
} else {
|
|
366
|
+
process.stdout.write(chunk.toString());
|
|
367
|
+
}
|
|
272
368
|
});
|
|
273
369
|
child.stderr?.on("data", (data) => {
|
|
274
|
-
|
|
370
|
+
const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
371
|
+
stderrTail = (stderrTail + chunk.toString()).slice(-MAX_STDERR_CAPTURE);
|
|
372
|
+
if (onStderr) {
|
|
373
|
+
onStderr(chunk);
|
|
374
|
+
} else {
|
|
375
|
+
process.stderr.write(chunk.toString());
|
|
376
|
+
}
|
|
275
377
|
});
|
|
276
378
|
child.on("error", (err) => {
|
|
277
|
-
(0, import_build_utils5.debug)(`
|
|
379
|
+
(0, import_build_utils5.debug)(`Rust dev server error: ${err}`);
|
|
278
380
|
});
|
|
279
|
-
child.on("exit", (code,
|
|
280
|
-
(0, import_build_utils5.debug)(`
|
|
381
|
+
child.on("exit", (code, signal2) => {
|
|
382
|
+
(0, import_build_utils5.debug)(`Rust dev server exited with code ${code}, signal ${signal2}`);
|
|
281
383
|
});
|
|
282
384
|
const onMessage = (0, import_events.once)(child, "message");
|
|
283
385
|
const onExit = (0, import_events.once)(child, "close");
|
|
@@ -287,31 +389,41 @@ var startDevServer = async (opts) => {
|
|
|
287
389
|
return { state: "message", value: messageData };
|
|
288
390
|
}),
|
|
289
391
|
onExit.then((args) => {
|
|
290
|
-
const [code,
|
|
291
|
-
return { state: "exit", value: [code,
|
|
392
|
+
const [code, signal2] = args;
|
|
393
|
+
return { state: "exit", value: [code, signal2] };
|
|
292
394
|
})
|
|
293
395
|
]);
|
|
294
396
|
if (result.state === "message") {
|
|
295
|
-
const
|
|
296
|
-
(0, import_build_utils5.debug)(`Rust dev server ready on port ${
|
|
397
|
+
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})`);
|
|
297
399
|
if (!child.pid) {
|
|
298
400
|
throw new Error("Child process has no PID");
|
|
299
401
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
}
|
|
402
|
+
return {
|
|
403
|
+
port: readyPort,
|
|
404
|
+
pid: child.pid,
|
|
405
|
+
// Wait for exit so the port is released before `vercel dev` continues.
|
|
406
|
+
shutdown: () => terminate(child)
|
|
306
407
|
};
|
|
307
|
-
return { port, pid: child.pid, shutdown };
|
|
308
|
-
} else {
|
|
309
|
-
const [exitCode, signal] = result.value;
|
|
310
|
-
const reason = signal ? `"${signal}" signal` : `exit code ${exitCode}`;
|
|
311
|
-
throw new Error(`Rust dev server failed with ${reason}`);
|
|
312
408
|
}
|
|
409
|
+
const [exitCode, signal] = result.value;
|
|
410
|
+
const reason = signal ? `"${signal}" signal` : `exit code ${exitCode}`;
|
|
411
|
+
const stderr = stderrTail.trim();
|
|
412
|
+
if (ADDR_IN_USE_RE.test(stderr)) {
|
|
413
|
+
throw new RustDevServerError(
|
|
414
|
+
`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
|
+
);
|
|
416
|
+
}
|
|
417
|
+
(0, import_build_utils5.debug)(
|
|
418
|
+
`Rust dev server exited before becoming ready (${reason}). Falling back to build-and-invoke mode.` + (stderr ? ` stderr:
|
|
419
|
+
${stderr}` : "")
|
|
420
|
+
);
|
|
421
|
+
return null;
|
|
313
422
|
} catch (error) {
|
|
314
|
-
(0, import_build_utils5.debug)(`Failed to start dev server: ${error}`);
|
|
423
|
+
(0, import_build_utils5.debug)(`Failed to start Rust dev server: ${error}`);
|
|
424
|
+
if (error instanceof RustDevServerError) {
|
|
425
|
+
throw error;
|
|
426
|
+
}
|
|
315
427
|
return null;
|
|
316
428
|
}
|
|
317
429
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/rust",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "./dist/index",
|
|
6
6
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/rust",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"smol-toml": "1.5.2",
|
|
17
|
-
"execa": "5"
|
|
17
|
+
"execa": "5",
|
|
18
|
+
"get-port": "5.1.1"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"@types/ms": "^0.7.31",
|
|
@@ -26,8 +27,8 @@
|
|
|
26
27
|
"prettier": "^2.8.4",
|
|
27
28
|
"rimraf": "^4.1.1",
|
|
28
29
|
"vitest": "2.0.3",
|
|
29
|
-
"@vercel/build-utils": "13.
|
|
30
|
-
"@vercel/routing-utils": "6.
|
|
30
|
+
"@vercel/build-utils": "13.32.2",
|
|
31
|
+
"@vercel/routing-utils": "6.4.0"
|
|
31
32
|
},
|
|
32
33
|
"scripts": {
|
|
33
34
|
"build": "node ../../utils/build-builder.mjs",
|