@open-mercato/cli 0.6.4-develop.3944.1.4100aa7fbe → 0.6.4-develop.3962.1.70f30e284c

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 CHANGED
@@ -322,6 +322,26 @@ function writeDevSplashRuntimeReady(reason) {
322
322
  activity: reason ? `Restart completed after ${reason}` : "App runtime is ready"
323
323
  });
324
324
  }
325
+ function resolveDevWarmupReadyTimeoutMs(environment = process.env) {
326
+ const parsed = Number.parseInt(environment.OM_DEV_WARMUP_READY_TIMEOUT_MS ?? "", 10);
327
+ if (Number.isFinite(parsed) && parsed >= 0) return parsed;
328
+ return 3e5;
329
+ }
330
+ async function waitForDevWarmupReadyFile(filePath, options = {}) {
331
+ const normalized = filePath?.trim();
332
+ if (!normalized) return "ready";
333
+ const timeoutMs = options.timeoutMs ?? resolveDevWarmupReadyTimeoutMs();
334
+ const startedAt = Date.now();
335
+ while (true) {
336
+ if (options.signal?.aborted) return "aborted";
337
+ try {
338
+ if (fs.existsSync(normalized)) return "ready";
339
+ } catch {
340
+ }
341
+ if (timeoutMs >= 0 && Date.now() - startedAt >= timeoutMs) return "timeout";
342
+ await new Promise((resolve) => setTimeout(resolve, 250));
343
+ }
344
+ }
325
345
  function waitForManagedProcessExit(proc, label) {
326
346
  return new Promise((resolve) => {
327
347
  proc.on("exit", (code, signal) => {
@@ -1551,55 +1571,65 @@ async function run(argv = process.argv) {
1551
1571
  const waitForDevRestart = () => new Promise((resolve) => {
1552
1572
  devRestartPromiseResolve = resolve;
1553
1573
  });
1554
- const startNextDev = (runtimeEnv) => new Promise((resolve) => {
1555
- writeDevSplashRuntimeStarting(
1556
- lastRestartReason ? `Restarting Next.js dev server. Reason: ${lastRestartReason}` : "Starting Next.js dev server"
1557
- );
1558
- const nextProcess = spawn("node", [nextBin, "dev", "--turbopack"], {
1559
- stdio: ["inherit", "pipe", "pipe"],
1560
- env: runtimeEnv,
1561
- cwd: appDir
1574
+ const startNextDev = (runtimeEnv) => {
1575
+ let readyResolve = () => void 0;
1576
+ const readyPromise = new Promise((resolve) => {
1577
+ readyResolve = resolve;
1562
1578
  });
1563
- processes.push(nextProcess);
1564
- let combinedOutput = "";
1565
- let reportedReady = false;
1566
- const appendOutput = (chunk) => {
1567
- combinedOutput += chunk;
1568
- if (combinedOutput.length > 32768) {
1569
- combinedOutput = combinedOutput.slice(-32768);
1570
- }
1571
- if (!reportedReady && /\bready in\b/i.test(chunk)) {
1572
- reportedReady = true;
1573
- writeDevSplashRuntimeReady(lastRestartReason ?? void 0);
1574
- lastRestartReason = null;
1575
- }
1576
- };
1577
- nextProcess.stdout?.on("data", (chunk) => {
1578
- const text = typeof chunk === "string" ? chunk : chunk.toString();
1579
- process.stdout.write(text);
1580
- appendOutput(text);
1581
- });
1582
- nextProcess.stderr?.on("data", (chunk) => {
1583
- const text = typeof chunk === "string" ? chunk : chunk.toString();
1584
- process.stderr.write(text);
1585
- appendOutput(text);
1586
- });
1587
- nextProcess.on("exit", async (code, signal) => {
1588
- if (!didRetryCorruptedTurbopackCache && isTurbopackCacheCorruption(combinedOutput)) {
1589
- didRetryCorruptedTurbopackCache = true;
1590
- lastRestartReason = "corrupted Turbopack dev cache";
1591
- writeDevSplashRuntimeRestarting(lastRestartReason);
1592
- console.log("[server] Detected corrupted Turbopack dev cache. Clearing .mercato/next/dev and restarting Next.js once...");
1593
- removeTurbopackDevCache(appDir);
1594
- return resolve(await startNextDev(runtimeEnv));
1595
- }
1596
- resolve({
1597
- label: "Next.js dev server",
1598
- code,
1599
- signal
1579
+ const exitPromise = new Promise((resolve) => {
1580
+ writeDevSplashRuntimeStarting(
1581
+ lastRestartReason ? `Restarting Next.js dev server. Reason: ${lastRestartReason}` : "Starting Next.js dev server"
1582
+ );
1583
+ const nextProcess = spawn("node", [nextBin, "dev", "--turbopack"], {
1584
+ stdio: ["inherit", "pipe", "pipe"],
1585
+ env: runtimeEnv,
1586
+ cwd: appDir
1587
+ });
1588
+ processes.push(nextProcess);
1589
+ let combinedOutput = "";
1590
+ let reportedReady = false;
1591
+ const appendOutput = (chunk) => {
1592
+ combinedOutput += chunk;
1593
+ if (combinedOutput.length > 32768) {
1594
+ combinedOutput = combinedOutput.slice(-32768);
1595
+ }
1596
+ if (!reportedReady && /\bready in\b/i.test(chunk)) {
1597
+ reportedReady = true;
1598
+ writeDevSplashRuntimeReady(lastRestartReason ?? void 0);
1599
+ lastRestartReason = null;
1600
+ readyResolve();
1601
+ }
1602
+ };
1603
+ nextProcess.stdout?.on("data", (chunk) => {
1604
+ const text = typeof chunk === "string" ? chunk : chunk.toString();
1605
+ process.stdout.write(text);
1606
+ appendOutput(text);
1607
+ });
1608
+ nextProcess.stderr?.on("data", (chunk) => {
1609
+ const text = typeof chunk === "string" ? chunk : chunk.toString();
1610
+ process.stderr.write(text);
1611
+ appendOutput(text);
1612
+ });
1613
+ nextProcess.on("exit", async (code, signal) => {
1614
+ if (!didRetryCorruptedTurbopackCache && isTurbopackCacheCorruption(combinedOutput)) {
1615
+ didRetryCorruptedTurbopackCache = true;
1616
+ lastRestartReason = "corrupted Turbopack dev cache";
1617
+ writeDevSplashRuntimeRestarting(lastRestartReason);
1618
+ console.log("[server] Detected corrupted Turbopack dev cache. Clearing .mercato/next/dev and restarting Next.js once...");
1619
+ removeTurbopackDevCache(appDir);
1620
+ const restarted = startNextDev(runtimeEnv);
1621
+ restarted.readyPromise.then(readyResolve);
1622
+ return resolve(await restarted.exitPromise);
1623
+ }
1624
+ resolve({
1625
+ label: "Next.js dev server",
1626
+ code,
1627
+ signal
1628
+ });
1600
1629
  });
1601
1630
  });
1602
- });
1631
+ return { exitPromise, readyPromise };
1632
+ };
1603
1633
  try {
1604
1634
  while (!stopping) {
1605
1635
  envReloader.reload();
@@ -1608,59 +1638,84 @@ async function run(argv = process.argv) {
1608
1638
  const autoSpawnSchedulerMode = resolveAutoSpawnSchedulerMode(process.env);
1609
1639
  const queueStrategy = process.env.QUEUE_STRATEGY || "local";
1610
1640
  const schedulerCommand = lookupModuleCommand(getCliModules(), "scheduler", "start");
1641
+ const nextRuntime = startNextDev(runtimeEnv);
1642
+ const restartPromise = waitForDevRestart();
1643
+ const backgroundStartAbort = new AbortController();
1644
+ const cancelBackgroundStart = () => backgroundStartAbort.abort();
1645
+ nextRuntime.exitPromise.finally(cancelBackgroundStart);
1646
+ restartPromise.then(cancelBackgroundStart);
1647
+ let backgroundExitResolve = () => void 0;
1648
+ const backgroundExitPromise = new Promise((resolve) => {
1649
+ backgroundExitResolve = resolve;
1650
+ });
1611
1651
  const managedExitPromises = [
1612
- startNextDev(runtimeEnv),
1613
- waitForDevRestart()
1652
+ nextRuntime.exitPromise,
1653
+ restartPromise,
1654
+ backgroundExitPromise
1614
1655
  ];
1615
- if (autoSpawnWorkersMode !== "off") {
1616
- const discoveredWorkers = getRegisteredCliWorkers();
1617
- const discoveredWorkerQueues = [...new Set(discoveredWorkers.map((worker) => worker.queue))];
1618
- if (discoveredWorkerQueues.length === 0) {
1619
- console.error("[server] AUTO_SPAWN_WORKERS is enabled, but no queues were discovered from CLI modules. Run `yarn generate` and verify `.mercato/generated/modules.cli.generated.ts` contains worker entries. Continuing without auto-spawned workers.");
1620
- } else if (autoSpawnWorkersMode === "lazy") {
1621
- console.log(`[server] Lazy worker auto-spawn enabled \u2014 workers will start on first job (${discoveredWorkerQueues.length} queue(s) watched).`);
1622
- activeLazySupervisor = startLazyWorkerSupervisor({
1623
- mercatoBin,
1624
- appDir,
1625
- runtimeEnv,
1626
- workers: discoveredWorkers,
1627
- pollMs: resolveLazyPollMs(process.env),
1628
- restartOnUnexpectedExit: resolveLazyRestart(process.env)
1629
- });
1630
- } else {
1631
- console.log("[server] Eager worker auto-spawn enabled - starting workers for all queues...");
1632
- const workerProcess = spawn("node", [mercatoBin, "queue", "worker", "--all"], {
1633
- stdio: "inherit",
1634
- env: runtimeEnv,
1635
- cwd: appDir
1636
- });
1637
- processes.push(workerProcess);
1638
- managedExitPromises.push(waitForManagedProcessExit(workerProcess, formatQueueWorkerLabel(discoveredWorkerQueues)));
1656
+ const startBackgroundServices = async () => {
1657
+ if (stopping || backgroundStartAbort.signal.aborted) return;
1658
+ const warmupReady = await waitForDevWarmupReadyFile(process.env.OM_DEV_WARMUP_READY_FILE, {
1659
+ timeoutMs: resolveDevWarmupReadyTimeoutMs(process.env),
1660
+ signal: backgroundStartAbort.signal
1661
+ });
1662
+ if (warmupReady === "aborted" || stopping || backgroundStartAbort.signal.aborted) return;
1663
+ if (warmupReady === "timeout") {
1664
+ console.warn("[server] Timed out waiting for dev warmup marker; starting background services anyway.");
1639
1665
  }
1640
- }
1641
- if (autoSpawnSchedulerMode !== "off" && queueStrategy === "local") {
1642
- if (schedulerCommand.status !== "ok") {
1643
- console.log(`[server] Skipping scheduler auto-start \u2014 ${describeMissingModuleCommand(schedulerCommand)}`);
1644
- } else if (autoSpawnSchedulerMode === "lazy") {
1645
- console.log("[server] Lazy scheduler auto-spawn enabled - scheduler will start when an enabled schedule exists.");
1646
- activeLazySchedulerSupervisor = startLazySchedulerSupervisor({
1647
- mercatoBin,
1648
- appDir,
1649
- runtimeEnv,
1650
- pollMs: resolveLazySchedulerPollMs(process.env),
1651
- restartOnUnexpectedExit: resolveLazySchedulerRestart(process.env)
1652
- });
1653
- } else {
1654
- console.log("[server] Eager scheduler auto-spawn enabled - starting scheduler polling engine...");
1655
- const schedulerProcess = spawn("node", [mercatoBin, "scheduler", "start"], {
1656
- stdio: "inherit",
1657
- env: runtimeEnv,
1658
- cwd: appDir
1659
- });
1660
- processes.push(schedulerProcess);
1661
- managedExitPromises.push(waitForManagedProcessExit(schedulerProcess, "Scheduler polling engine"));
1666
+ if (autoSpawnWorkersMode !== "off") {
1667
+ const discoveredWorkers = getRegisteredCliWorkers();
1668
+ const discoveredWorkerQueues = [...new Set(discoveredWorkers.map((worker) => worker.queue))];
1669
+ if (discoveredWorkerQueues.length === 0) {
1670
+ console.error("[server] AUTO_SPAWN_WORKERS is enabled, but no queues were discovered from CLI modules. Run `yarn generate` and verify `.mercato/generated/modules.cli.generated.ts` contains worker entries. Continuing without auto-spawned workers.");
1671
+ } else if (autoSpawnWorkersMode === "lazy") {
1672
+ console.log(`[server] Lazy worker auto-spawn enabled \u2014 workers will start on first job (${discoveredWorkerQueues.length} queue(s) watched).`);
1673
+ activeLazySupervisor = startLazyWorkerSupervisor({
1674
+ mercatoBin,
1675
+ appDir,
1676
+ runtimeEnv,
1677
+ workers: discoveredWorkers,
1678
+ pollMs: resolveLazyPollMs(process.env),
1679
+ restartOnUnexpectedExit: resolveLazyRestart(process.env)
1680
+ });
1681
+ } else {
1682
+ console.log("[server] Eager worker auto-spawn enabled - starting workers for all queues...");
1683
+ const workerProcess = spawn("node", [mercatoBin, "queue", "worker", "--all"], {
1684
+ stdio: "inherit",
1685
+ env: runtimeEnv,
1686
+ cwd: appDir
1687
+ });
1688
+ processes.push(workerProcess);
1689
+ waitForManagedProcessExit(workerProcess, formatQueueWorkerLabel(discoveredWorkerQueues)).then(backgroundExitResolve);
1690
+ }
1662
1691
  }
1663
- }
1692
+ if (autoSpawnSchedulerMode !== "off" && queueStrategy === "local") {
1693
+ if (schedulerCommand.status !== "ok") {
1694
+ console.log(`[server] Skipping scheduler auto-start \u2014 ${describeMissingModuleCommand(schedulerCommand)}`);
1695
+ } else if (autoSpawnSchedulerMode === "lazy") {
1696
+ console.log("[server] Lazy scheduler auto-spawn enabled - scheduler will start when an enabled schedule exists.");
1697
+ activeLazySchedulerSupervisor = startLazySchedulerSupervisor({
1698
+ mercatoBin,
1699
+ appDir,
1700
+ runtimeEnv,
1701
+ pollMs: resolveLazySchedulerPollMs(process.env),
1702
+ restartOnUnexpectedExit: resolveLazySchedulerRestart(process.env)
1703
+ });
1704
+ } else {
1705
+ console.log("[server] Eager scheduler auto-spawn enabled - starting scheduler polling engine...");
1706
+ const schedulerProcess = spawn("node", [mercatoBin, "scheduler", "start"], {
1707
+ stdio: "inherit",
1708
+ env: runtimeEnv,
1709
+ cwd: appDir
1710
+ });
1711
+ processes.push(schedulerProcess);
1712
+ waitForManagedProcessExit(schedulerProcess, "Scheduler polling engine").then(backgroundExitResolve);
1713
+ }
1714
+ }
1715
+ };
1716
+ nextRuntime.readyPromise.then(() => {
1717
+ void startBackgroundServices();
1718
+ });
1664
1719
  if (generateWatcherMode === "in-process") {
1665
1720
  console.log("[server] In-process generate watcher enabled \u2014 structural changes will regenerate without a sidecar process.");
1666
1721
  activeGenerateWatcher = startInProcessGenerateWatcher({