@open-mercato/cli 0.5.1-develop.3032.01699048cb → 0.5.1-develop.3036.f02c281f23
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/mercato.js +85 -52
- package/dist/mercato.js.map +2 -2
- package/package.json +5 -5
- package/src/__tests__/mercato.test.ts +221 -57
- package/src/mercato.ts +107 -54
package/dist/mercato.js
CHANGED
|
@@ -248,6 +248,40 @@ function formatManagedProcessExitStatus(result) {
|
|
|
248
248
|
function createManagedProcessExitError(result) {
|
|
249
249
|
return new Error(`[server] ${result.label} exited unexpectedly with ${formatManagedProcessExitStatus(result)}.`);
|
|
250
250
|
}
|
|
251
|
+
function formatQueueWorkerLabel(queueNames) {
|
|
252
|
+
if (queueNames.length === 0) return "Queue worker";
|
|
253
|
+
const sorted = [...queueNames].sort((a, b) => a.localeCompare(b));
|
|
254
|
+
const preview = sorted.length > 4 ? `${sorted.slice(0, 4).join(", ")}, +${sorted.length - 4} more` : sorted.join(", ");
|
|
255
|
+
return `Queue worker (${preview})`;
|
|
256
|
+
}
|
|
257
|
+
function lookupModuleCommand(allModules, moduleName, commandName) {
|
|
258
|
+
const mod = allModules.find((entry) => entry.id === moduleName);
|
|
259
|
+
if (!mod) {
|
|
260
|
+
return { status: "missing-module" };
|
|
261
|
+
}
|
|
262
|
+
if (!mod.cli || mod.cli.length === 0) {
|
|
263
|
+
return { status: "missing-cli" };
|
|
264
|
+
}
|
|
265
|
+
const command = mod.cli.find((entry) => entry.command === commandName);
|
|
266
|
+
if (!command) {
|
|
267
|
+
return { status: "missing-command" };
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
status: "ok",
|
|
271
|
+
module: mod,
|
|
272
|
+
command
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function describeMissingModuleCommand(result) {
|
|
276
|
+
switch (result.status) {
|
|
277
|
+
case "missing-module":
|
|
278
|
+
return "module not enabled";
|
|
279
|
+
case "missing-cli":
|
|
280
|
+
return "module has no CLI commands";
|
|
281
|
+
case "missing-command":
|
|
282
|
+
return "command not found";
|
|
283
|
+
}
|
|
284
|
+
}
|
|
251
285
|
function ensureNextBuildIdInConfiguredDistDir(appDir) {
|
|
252
286
|
const configuredDistDir = path.join(appDir, ".mercato", "next");
|
|
253
287
|
const configuredBuildIdPath = path.join(configuredDistDir, "BUILD_ID");
|
|
@@ -304,36 +338,24 @@ async function handleDirectEjectCommand(args) {
|
|
|
304
338
|
return 0;
|
|
305
339
|
}
|
|
306
340
|
async function runModuleCommand(allModules, moduleName, commandName, args = [], options = {}) {
|
|
307
|
-
const
|
|
308
|
-
if (
|
|
309
|
-
if (options.optional) {
|
|
310
|
-
if (!options.silentOptional) {
|
|
311
|
-
console.log(`\u23ED\uFE0F Skipping "${moduleName}:${commandName}" \u2014 module not enabled`);
|
|
312
|
-
}
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
|
-
throw new Error(`Module not found: "${moduleName}"`);
|
|
316
|
-
}
|
|
317
|
-
if (!mod.cli || mod.cli.length === 0) {
|
|
341
|
+
const resolved = lookupModuleCommand(allModules, moduleName, commandName);
|
|
342
|
+
if (resolved.status !== "ok") {
|
|
318
343
|
if (options.optional) {
|
|
319
344
|
if (!options.silentOptional) {
|
|
320
|
-
console.log(`\u23ED\uFE0F Skipping "${moduleName}:${commandName}" \u2014
|
|
345
|
+
console.log(`\u23ED\uFE0F Skipping "${moduleName}:${commandName}" \u2014 ${describeMissingModuleCommand(resolved)}`);
|
|
321
346
|
}
|
|
322
347
|
return false;
|
|
323
348
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
return false;
|
|
349
|
+
switch (resolved.status) {
|
|
350
|
+
case "missing-module":
|
|
351
|
+
throw new Error(`Module not found: "${moduleName}"`);
|
|
352
|
+
case "missing-cli":
|
|
353
|
+
throw new Error(`Module "${moduleName}" has no CLI commands`);
|
|
354
|
+
case "missing-command":
|
|
355
|
+
throw new Error(`Command "${commandName}" not found in module "${moduleName}"`);
|
|
333
356
|
}
|
|
334
|
-
throw new Error(`Command "${commandName}" not found in module "${moduleName}"`);
|
|
335
357
|
}
|
|
336
|
-
await
|
|
358
|
+
await resolved.command.run(args);
|
|
337
359
|
return true;
|
|
338
360
|
}
|
|
339
361
|
async function runPostGenerateStructuralCachePurge(quiet) {
|
|
@@ -1355,8 +1377,8 @@ async function run(argv = process.argv) {
|
|
|
1355
1377
|
const autoSpawnWorkers = process.env.AUTO_SPAWN_WORKERS !== "false";
|
|
1356
1378
|
const autoSpawnScheduler = process.env.AUTO_SPAWN_SCHEDULER !== "false";
|
|
1357
1379
|
const queueStrategy = process.env.QUEUE_STRATEGY || "local";
|
|
1358
|
-
const runtimeEnv = buildServerProcessEnvironment(process.env);
|
|
1359
1380
|
let didRetryCorruptedTurbopackCache = false;
|
|
1381
|
+
const schedulerCommand = lookupModuleCommand(getCliModules(), "scheduler", "start");
|
|
1360
1382
|
function cleanup() {
|
|
1361
1383
|
console.log("[server] Shutting down...");
|
|
1362
1384
|
for (const proc of processes) {
|
|
@@ -1370,7 +1392,7 @@ async function run(argv = process.argv) {
|
|
|
1370
1392
|
await Promise.all(
|
|
1371
1393
|
processes.map(
|
|
1372
1394
|
(proc) => new Promise((resolve) => {
|
|
1373
|
-
if (proc.exitCode !== null) return resolve();
|
|
1395
|
+
if (proc.exitCode !== null || proc.signalCode !== null) return resolve();
|
|
1374
1396
|
proc.on("exit", () => resolve());
|
|
1375
1397
|
})
|
|
1376
1398
|
)
|
|
@@ -1392,7 +1414,7 @@ async function run(argv = process.argv) {
|
|
|
1392
1414
|
const startNextDev = () => new Promise((resolve) => {
|
|
1393
1415
|
const nextProcess = spawn("node", [nextBin, "dev", "--turbopack"], {
|
|
1394
1416
|
stdio: ["inherit", "pipe", "pipe"],
|
|
1395
|
-
env:
|
|
1417
|
+
env: process.env,
|
|
1396
1418
|
cwd: appDir
|
|
1397
1419
|
});
|
|
1398
1420
|
processes.push(nextProcess);
|
|
@@ -1437,22 +1459,26 @@ async function run(argv = process.argv) {
|
|
|
1437
1459
|
console.log("[server] Starting workers for all queues...");
|
|
1438
1460
|
const workerProcess = spawn("node", [mercatoBin, "queue", "worker", "--all"], {
|
|
1439
1461
|
stdio: "inherit",
|
|
1440
|
-
env:
|
|
1462
|
+
env: process.env,
|
|
1441
1463
|
cwd: appDir
|
|
1442
1464
|
});
|
|
1443
1465
|
processes.push(workerProcess);
|
|
1444
|
-
managedExitPromises.push(waitForManagedProcessExit(workerProcess,
|
|
1466
|
+
managedExitPromises.push(waitForManagedProcessExit(workerProcess, formatQueueWorkerLabel(discoveredWorkerQueues)));
|
|
1445
1467
|
}
|
|
1446
1468
|
}
|
|
1447
1469
|
if (autoSpawnScheduler && queueStrategy === "local") {
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1470
|
+
if (schedulerCommand.status !== "ok") {
|
|
1471
|
+
console.log(`[server] Skipping scheduler auto-start \u2014 ${describeMissingModuleCommand(schedulerCommand)}`);
|
|
1472
|
+
} else {
|
|
1473
|
+
console.log("[server] Starting scheduler polling engine...");
|
|
1474
|
+
const schedulerProcess = spawn("node", [mercatoBin, "scheduler", "start"], {
|
|
1475
|
+
stdio: "inherit",
|
|
1476
|
+
env: process.env,
|
|
1477
|
+
cwd: appDir
|
|
1478
|
+
});
|
|
1479
|
+
processes.push(schedulerProcess);
|
|
1480
|
+
managedExitPromises.push(waitForManagedProcessExit(schedulerProcess, "Scheduler polling engine"));
|
|
1481
|
+
}
|
|
1456
1482
|
}
|
|
1457
1483
|
const firstExit = await Promise.race(managedExitPromises);
|
|
1458
1484
|
await cleanupAndWait();
|
|
@@ -1474,13 +1500,14 @@ async function run(argv = process.argv) {
|
|
|
1474
1500
|
const autoSpawnScheduler = process.env.AUTO_SPAWN_SCHEDULER !== "false";
|
|
1475
1501
|
const queueStrategy = process.env.QUEUE_STRATEGY || "local";
|
|
1476
1502
|
const runtimeEnv = buildServerProcessEnvironment(process.env);
|
|
1503
|
+
const schedulerCommand = lookupModuleCommand(getCliModules(), "scheduler", "start");
|
|
1477
1504
|
const serverStartLock = acquireServerStartLock(appDir, {
|
|
1478
1505
|
port: runtimeEnv.PORT ?? process.env.PORT ?? null
|
|
1479
1506
|
});
|
|
1480
1507
|
function cleanup() {
|
|
1481
1508
|
console.log("[server] Shutting down...");
|
|
1482
1509
|
for (const proc of processes) {
|
|
1483
|
-
if (!proc.killed) {
|
|
1510
|
+
if (!proc.killed && proc.exitCode === null && proc.signalCode === null) {
|
|
1484
1511
|
proc.kill("SIGTERM");
|
|
1485
1512
|
}
|
|
1486
1513
|
}
|
|
@@ -1490,7 +1517,7 @@ async function run(argv = process.argv) {
|
|
|
1490
1517
|
await Promise.all(
|
|
1491
1518
|
processes.map(
|
|
1492
1519
|
(proc) => new Promise((resolve) => {
|
|
1493
|
-
if (proc.exitCode !== null) return resolve();
|
|
1520
|
+
if (proc.exitCode !== null || proc.signalCode !== null) return resolve();
|
|
1494
1521
|
proc.on("exit", () => resolve());
|
|
1495
1522
|
})
|
|
1496
1523
|
)
|
|
@@ -1509,6 +1536,9 @@ async function run(argv = process.argv) {
|
|
|
1509
1536
|
cwd: appDir
|
|
1510
1537
|
});
|
|
1511
1538
|
processes.push(nextProcess);
|
|
1539
|
+
const managedExitPromises = [
|
|
1540
|
+
waitForManagedProcessExit(nextProcess, "Next.js production server")
|
|
1541
|
+
];
|
|
1512
1542
|
if (autoSpawnWorkers) {
|
|
1513
1543
|
const discoveredWorkerQueues = [...new Set(getRegisteredCliWorkers().map((worker) => worker.queue))];
|
|
1514
1544
|
if (discoveredWorkerQueues.length === 0) {
|
|
@@ -1521,25 +1551,28 @@ async function run(argv = process.argv) {
|
|
|
1521
1551
|
cwd: appDir
|
|
1522
1552
|
});
|
|
1523
1553
|
processes.push(workerProcess);
|
|
1554
|
+
managedExitPromises.push(waitForManagedProcessExit(workerProcess, formatQueueWorkerLabel(discoveredWorkerQueues)));
|
|
1524
1555
|
}
|
|
1525
1556
|
}
|
|
1526
1557
|
if (autoSpawnScheduler && queueStrategy === "local") {
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1558
|
+
if (schedulerCommand.status !== "ok") {
|
|
1559
|
+
console.log(`[server] Skipping scheduler auto-start \u2014 ${describeMissingModuleCommand(schedulerCommand)}`);
|
|
1560
|
+
} else {
|
|
1561
|
+
console.log("[server] Starting scheduler polling engine...");
|
|
1562
|
+
const schedulerProcess = spawn("node", [mercatoBin, "scheduler", "start"], {
|
|
1563
|
+
stdio: "inherit",
|
|
1564
|
+
env: runtimeEnv,
|
|
1565
|
+
cwd: appDir
|
|
1566
|
+
});
|
|
1567
|
+
processes.push(schedulerProcess);
|
|
1568
|
+
managedExitPromises.push(waitForManagedProcessExit(schedulerProcess, "Scheduler polling engine"));
|
|
1569
|
+
}
|
|
1534
1570
|
}
|
|
1535
|
-
await Promise.race(
|
|
1536
|
-
processes.map(
|
|
1537
|
-
(proc) => new Promise((resolve) => {
|
|
1538
|
-
proc.on("exit", () => resolve());
|
|
1539
|
-
})
|
|
1540
|
-
)
|
|
1541
|
-
);
|
|
1571
|
+
const firstExit = await Promise.race(managedExitPromises);
|
|
1542
1572
|
await cleanupAndWait();
|
|
1573
|
+
if (!isExpectedManagedExitSignal(firstExit.signal)) {
|
|
1574
|
+
throw createManagedProcessExitError(firstExit);
|
|
1575
|
+
}
|
|
1543
1576
|
} finally {
|
|
1544
1577
|
serverStartLock.release();
|
|
1545
1578
|
}
|