From b508b490581d9aa2b3e7df85d2b6ad2fcfb08b38 Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Wed, 12 Aug 2026 22:25:12 +0530 Subject: [PATCH] fix(dev): consolidate generated cache directories --- bun.lock | 4 ++-- packages/cli/package.json | 2 +- packages/cli/src/workspace.ts | 1 + packages/dev-server/package.json | 2 +- packages/dev-server/src/cache.ts | 19 +++++++++++++++++-- packages/dev-server/src/index.ts | 7 +++---- .../dev-server/test/authz-startserver.test.ts | 4 ++-- .../test/cache-ignore-config.test.ts | 2 +- 8 files changed, 28 insertions(+), 13 deletions(-) diff --git a/bun.lock b/bun.lock index 83363cf6..2f56b6b3 100644 --- a/bun.lock +++ b/bun.lock @@ -268,7 +268,7 @@ }, "packages/cli": { "name": "@wrnexus/cli", - "version": "0.8.30", + "version": "0.8.31", "bin": { "wrnexus": "src/index.ts", }, @@ -332,7 +332,7 @@ }, "packages/dev-server": { "name": "@wrnexus/dev-server", - "version": "0.8.28", + "version": "0.8.29", "dependencies": { "@wrnexus/authz": "workspace:*", "@wrnexus/cache": "workspace:*", diff --git a/packages/cli/package.json b/packages/cli/package.json index 2146f773..a7c91971 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/cli", - "version": "0.8.30", + "version": "0.8.31", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/cli/src/workspace.ts b/packages/cli/src/workspace.ts index 81f9a0be..6d6ae998 100644 --- a/packages/cli/src/workspace.ts +++ b/packages/cli/src/workspace.ts @@ -540,6 +540,7 @@ export async function runGateway(root: string, args: string[]): Promise { const hostname = hostArg?.split("=")[1] ?? environmentConfig.hostname; + // The published CLI bundle carries the matching gateway/cache lifecycle. const { startGateway } = await import("@wrnexus/dev-server"); await startGateway({ diff --git a/packages/dev-server/package.json b/packages/dev-server/package.json index a8ae1499..8c6b7d4b 100644 --- a/packages/dev-server/package.json +++ b/packages/dev-server/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/dev-server", - "version": "0.8.28", + "version": "0.8.29", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/dev-server/src/cache.ts b/packages/dev-server/src/cache.ts index 923c7fd0..5ab45af8 100644 --- a/packages/dev-server/src/cache.ts +++ b/packages/dev-server/src/cache.ts @@ -1,5 +1,5 @@ -import { existsSync, rmSync } from "node:fs"; -import { resolve } from "node:path"; +import { existsSync, readdirSync, rmSync } from "node:fs"; +import { join, resolve } from "node:path"; export interface ResetDevCacheOptions { rootDir?: string; @@ -7,6 +7,19 @@ export interface ResetDevCacheOptions { enabled?: boolean; } +function removeLegacyProcessCaches(rootDir: string): void { + if (!existsSync(rootDir)) return; + for (const entry of readdirSync(rootDir, { withFileTypes: true })) { + if (!entry.isDirectory() || !/^\.wrnexus-\d+$/.test(entry.name)) continue; + rmSync(join(rootDir, entry.name), { + recursive: true, + force: true, + maxRetries: 3, + retryDelay: 100, + }); + } +} + export function resetDevCache(options: ResetDevCacheOptions = {}): string { const rootDir = resolve(options.rootDir ?? process.cwd()); @@ -16,6 +29,8 @@ export function resetDevCache(options: ResetDevCacheOptions = {}): string { return cacheDir; } + removeLegacyProcessCaches(rootDir); + // Safety: never allow deleting the project root. if (cacheDir === rootDir) { throw new Error("Refusing to remove the project root as the WRNexus cache directory."); diff --git a/packages/dev-server/src/index.ts b/packages/dev-server/src/index.ts index 34333ad2..4c4223cc 100644 --- a/packages/dev-server/src/index.ts +++ b/packages/dev-server/src/index.ts @@ -288,10 +288,9 @@ export async function startServer(opts: ServeOptions): Promise { const pluginContributions = await pluginRunner.contributions(); const virtualModules = new Map(); - // A live dev server and a test process can share an app root. Keeping the - // generated artifacts in a process-specific directory prevents a test boot - // from deleting the running server's client modules. - const cacheDir = join(appRoot, `.wrnexus-${process.pid}`); + // Keep generated artifacts under the single framework state directory. + // Startup clears this cache and removes legacy PID-suffixed cache folders. + const cacheDir = join(appRoot, ".wrnexus", "cache"); const virtualDir = join(cacheDir, "virtual"); mkdirSync(virtualDir, { recursive: true }); for (const [index, module] of pluginContributions.virtualModules.entries()) { diff --git a/packages/dev-server/test/authz-startserver.test.ts b/packages/dev-server/test/authz-startserver.test.ts index b34b5ea5..44af167a 100644 --- a/packages/dev-server/test/authz-startserver.test.ts +++ b/packages/dev-server/test/authz-startserver.test.ts @@ -63,14 +63,14 @@ export default defineAuthz({ permissions: { "post:read": { title: "View posts" } try { expect(hasAuthzCatalog()).toBe(true); expect(getAuthzCatalog().permissions.has("post:read")).toBe(true); - const cacheDir = join(appDir, "..", `.wrnexus-${process.pid}`); + const cacheDir = join(appDir, "..", ".wrnexus", "cache"); mkdirSync(cacheDir, { recursive: true }); writeFileSync(join(cacheDir, "generated.js"), "generated", "utf8"); expect(existsSync(cacheDir)).toBe(true); } finally { server.stop(); } - expect(existsSync(join(appDir, "..", `.wrnexus-${process.pid}`))).toBe(false); + expect(existsSync(join(appDir, "..", ".wrnexus", "cache"))).toBe(false); }); test("an app with no app/authz declarations boots without throwing", async () => { diff --git a/packages/dev-server/test/cache-ignore-config.test.ts b/packages/dev-server/test/cache-ignore-config.test.ts index bbbc86ca..4b8b9d01 100644 --- a/packages/dev-server/test/cache-ignore-config.test.ts +++ b/packages/dev-server/test/cache-ignore-config.test.ts @@ -18,7 +18,7 @@ test("per-process dev caches are excluded from root and example project tools", const projects = ["basic-app", "inter-app-api-showcase"].map((name) => join(root, "examples", name), ); - const caches = projects.map((project) => join(project, ".wrnexus-123")); + const caches = projects.map((project) => join(project, ".wrnexus", "cache")); for (const project of projects) { const projectEslint = readFileSync(join(project, "eslint.config.js"), "utf8");