@montytools/cli 0.2.4 → 0.2.5

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 +39 -2
  2. package/package.json +1 -1
package/bin/monty.mjs CHANGED
@@ -489,6 +489,27 @@ async function dev() {
489
489
  let ended = false;
490
490
  const buildFile = join(appDir, ".monty", "build");
491
491
  const buildId = existsSync(buildFile) ? readFileSync(buildFile, "utf8").trim() : undefined;
492
+ // The DEV schema channel: heartbeats carry the compiled schema, and edits
493
+ // to monty.config.ts are re-compiled (softly) so schema changes reach the
494
+ // platform within one heartbeat. Publish owns the PROD schema.
495
+ let currentMeta = meta;
496
+ const configPath = join(appDir, "monty.config.ts");
497
+ let configMtime = statSync(configPath).mtimeMs;
498
+
499
+ async function refreshSchemaIfChanged() {
500
+ try {
501
+ const m = statSync(configPath).mtimeMs;
502
+ if (m === configMtime) return;
503
+ configMtime = m;
504
+ const fresh = await compileConfig(appDir, { soft: true });
505
+ if (fresh) {
506
+ currentMeta = fresh;
507
+ console.log(
508
+ `schema: monty.config.ts changed — dev schema updated (${Object.keys(fresh.schemaJson.tables).length} tables)`,
509
+ );
510
+ }
511
+ } catch { /* transient fs hiccup — next beat retries */ }
512
+ }
492
513
 
493
514
  async function endSession() {
494
515
  if (ended) return;
@@ -508,11 +529,19 @@ async function dev() {
508
529
  }
509
530
 
510
531
  async function heartbeat(originUrl) {
532
+ await refreshSchemaIfChanged();
511
533
  try {
512
534
  const r = await fetch(`${host}/api/dev-session`, {
513
535
  method: "POST",
514
536
  headers: { authorization: `Bearer ${cfg.key}`, "content-type": "application/json" },
515
- body: JSON.stringify({ slug: meta.slug, tunnelUrl: originUrl, name: meta.name, icon: meta.icon, buildId }),
537
+ body: JSON.stringify({
538
+ slug: meta.slug,
539
+ tunnelUrl: originUrl,
540
+ name: currentMeta.name,
541
+ icon: currentMeta.icon,
542
+ buildId,
543
+ schemaJson: currentMeta.schemaJson,
544
+ }),
516
545
  });
517
546
  const data = await r.json().catch(() => null);
518
547
  if (!r.ok) {
@@ -819,7 +848,7 @@ async function deploy() {
819
848
  console.log(`deployed: ${body.url} (version ${body.version})`);
820
849
  }
821
850
 
822
- async function compileConfig(appDir) {
851
+ async function compileConfig(appDir, { soft = false } = {}) {
823
852
  const { build } = await import("esbuild");
824
853
  const tmpDir = join(appDir, ".monty");
825
854
  mkdirSync(tmpDir, { recursive: true });
@@ -843,11 +872,19 @@ async function compileConfig(appDir) {
843
872
  });
844
873
  const result = spawnSync(process.execPath, [out], { encoding: "utf8" });
845
874
  if (result.status !== 0) {
875
+ if (soft) {
876
+ console.log("schema: monty.config.ts doesn't compile right now — keeping the last good schema");
877
+ return null;
878
+ }
846
879
  fail("CONFIG_COMPILE_FAILED", `monty.config.ts threw while loading:\n${result.stderr}\nFix the config (it must only call defineApp with zod tables).`);
847
880
  }
848
881
  return JSON.parse(result.stdout);
849
882
  } catch (e) {
850
883
  if (e?.errors) {
884
+ if (soft) {
885
+ console.log("schema: monty.config.ts doesn't compile right now — keeping the last good schema");
886
+ return null;
887
+ }
851
888
  fail("CONFIG_COMPILE_FAILED", `esbuild could not bundle monty.config.ts: ${e.errors[0]?.text ?? e.message}`);
852
889
  }
853
890
  throw e;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@montytools/cli",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "monty": "./bin/monty.mjs"