@montytools/cli 0.2.6 → 0.2.7

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.
Files changed (2) hide show
  1. package/bin/monty.mjs +20 -3
  2. package/package.json +1 -1
package/bin/monty.mjs CHANGED
@@ -489,6 +489,7 @@ async function dev() {
489
489
  let hbTimer = null;
490
490
  let publishing = false;
491
491
  let ended = false;
492
+ const sessionId = `dev_${randomBytes(16).toString("hex")}`;
492
493
  const buildFile = join(appDir, ".monty", "build");
493
494
  const buildId = existsSync(buildFile) ? readFileSync(buildFile, "utf8").trim() : undefined;
494
495
  // The DEV schema channel: heartbeats carry the compiled schema, and edits
@@ -519,7 +520,7 @@ async function dev() {
519
520
  await fetch(`${host}/api/dev-session`, {
520
521
  method: "POST",
521
522
  headers: { authorization: `Bearer ${cfg.key}`, "content-type": "application/json" },
522
- body: JSON.stringify({ slug: meta.slug, end: true }),
523
+ body: JSON.stringify({ slug: meta.slug, sessionId, end: true }),
523
524
  signal: AbortSignal.timeout(timeoutMs),
524
525
  });
525
526
  } catch { /* best effort */ }
@@ -534,7 +535,17 @@ async function dev() {
534
535
  await clearDevSession();
535
536
  }
536
537
 
537
- async function heartbeat(originUrl) {
538
+ function stopSuperseded(fix) {
539
+ if (ended) return;
540
+ ended = true;
541
+ if (hbTimer) clearInterval(hbTimer);
542
+ try { tunnelChild?.kill(); } catch { /* already gone */ }
543
+ try { child.kill(); } catch { /* already gone */ }
544
+ console.log(`dev-session: superseded — ${fix}`);
545
+ setTimeout(() => process.exit(0), 50);
546
+ }
547
+
548
+ async function heartbeat(originUrl, { claim = false } = {}) {
538
549
  await refreshSchemaIfChanged();
539
550
  try {
540
551
  const r = await fetch(`${host}/api/dev-session`, {
@@ -543,6 +554,8 @@ async function dev() {
543
554
  body: JSON.stringify({
544
555
  slug: meta.slug,
545
556
  tunnelUrl: originUrl,
557
+ sessionId,
558
+ claim,
546
559
  name: currentMeta.name,
547
560
  icon: currentMeta.icon,
548
561
  buildId,
@@ -552,6 +565,10 @@ async function dev() {
552
565
  });
553
566
  const data = await r.json().catch(() => null);
554
567
  if (!r.ok) {
568
+ if (data?.code === "DEV_SESSION_SUPERSEDED") {
569
+ stopSuperseded(data.fix ?? "A newer `monty dev` session is active for this app.");
570
+ return false;
571
+ }
555
572
  console.log(`dev-session: ${data?.code ?? r.status}${data?.fix ? ` — ${data.fix}` : ""}`);
556
573
  return false;
557
574
  }
@@ -633,7 +650,7 @@ async function dev() {
633
650
  console.log("tunnel: unavailable — dev mode registered on localhost (visible on this machine's browser only)");
634
651
  }
635
652
  }
636
- const registered = await heartbeat(originUrl);
653
+ const registered = await heartbeat(originUrl, { claim: true });
637
654
  console.log(
638
655
  registered
639
656
  ? `studio: ${host}/studio/${meta.slug} — your app is live there while this runs; click Publish to ship`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@montytools/cli",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "monty": "./bin/monty.mjs"