@mandujs/core 0.9.13 → 0.9.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mandujs/core",
3
- "version": "0.9.13",
3
+ "version": "0.9.15",
4
4
  "description": "Mandu Framework Core - Spec, Generator, Guard, Runtime",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -2,8 +2,10 @@ import type { RoutesManifest, RouteSpec } from "../spec/schema";
2
2
  import { generateApiHandler, generatePageComponent, generateSlotLogic } from "./templates";
3
3
  import { generateContractTypeGlue, generateContractTemplate, generateContractTypesIndex } from "./contract-glue";
4
4
  import { computeHash } from "../spec/lock";
5
+ import { getWatcher } from "../watcher/watcher";
5
6
  import path from "path";
6
7
  import fs from "fs/promises";
8
+ import fsSync from "fs";
7
9
 
8
10
  async function fileExists(filePath: string): Promise<boolean> {
9
11
  try {
@@ -135,6 +137,10 @@ export async function generateRoutes(
135
137
  warnings: [],
136
138
  };
137
139
 
140
+ // Suppress watcher during generation to avoid false positives
141
+ const watcher = getWatcher();
142
+ watcher?.suppress();
143
+
138
144
  const serverRoutesDir = path.join(rootDir, "apps/server/generated/routes");
139
145
  const webRoutesDir = path.join(rootDir, "apps/web/generated/routes");
140
146
  const typesDir = path.join(rootDir, "apps/server/generated/types");
@@ -338,5 +344,14 @@ export async function generateRoutes(
338
344
  const mapPath = path.join(mapDir, "generated.map.json");
339
345
  await Bun.write(mapPath, JSON.stringify(generatedMap, null, 2));
340
346
 
347
+ // Resume watcher after generation
348
+ watcher?.resume();
349
+ // Cross-process timestamp: watcher skips warnings if generate finished recently
350
+ const stampDir = path.join(rootDir, ".mandu");
351
+ if (!fsSync.existsSync(stampDir)) {
352
+ fsSync.mkdirSync(stampDir, { recursive: true });
353
+ }
354
+ fsSync.writeFileSync(path.join(stampDir, "generate.stamp"), Date.now().toString());
355
+
341
356
  return result;
342
357
  }
@@ -67,6 +67,7 @@ export class FileWatcher {
67
67
  private logFile: string | null = null;
68
68
  private logStream: fs.WriteStream | null = null;
69
69
  private tailProcess: ChildProcess | null = null;
70
+ private _suppressed: boolean = false;
70
71
 
71
72
  constructor(config: WatcherConfig) {
72
73
  this.config = {
@@ -229,6 +230,20 @@ export class FileWatcher {
229
230
  this.recentWarnings = [];
230
231
  }
231
232
 
233
+ /**
234
+ * Suppress warnings (e.g. during generate)
235
+ */
236
+ suppress(): void {
237
+ this._suppressed = true;
238
+ }
239
+
240
+ /**
241
+ * Resume warnings after suppression
242
+ */
243
+ resume(): void {
244
+ this._suppressed = false;
245
+ }
246
+
232
247
  /**
233
248
  * Open a new terminal window tailing the log file
234
249
  */
@@ -266,8 +281,24 @@ export class FileWatcher {
266
281
  event: "create" | "modify" | "delete",
267
282
  filePath: string
268
283
  ): Promise<void> {
284
+ if (this._suppressed) return;
285
+
269
286
  const { rootDir } = this.config;
270
287
 
288
+ // Cross-process: skip if generate finished within last 2 seconds
289
+ // Walk up from the changed file to find nearest .mandu/generate.stamp
290
+ let stampDir = path.dirname(filePath);
291
+ while (stampDir !== path.dirname(stampDir)) {
292
+ const stampFile = path.join(stampDir, ".mandu", "generate.stamp");
293
+ try {
294
+ const stamp = parseInt(fs.readFileSync(stampFile, "utf-8"), 10);
295
+ if (Date.now() - stamp < 2000) return;
296
+ break;
297
+ } catch {}
298
+ stampDir = path.dirname(stampDir);
299
+ }
300
+
301
+
271
302
  // Validate file against rules
272
303
  try {
273
304
  const warnings = await validateFile(filePath, event, rootDir);