diff --git a/apps/server/src/preview/ServerBrowser.test.ts b/apps/server/src/preview/ServerBrowser.test.ts index c8061833a80ec..a0b7526f513ed 100644 --- a/apps/server/src/preview/ServerBrowser.test.ts +++ b/apps/server/src/preview/ServerBrowser.test.ts @@ -1057,6 +1057,27 @@ it.live.each(["save failed", "oversized"])( ).pipe(Effect.provide(layer)), ); +it.live("a restarted server removes the previous run's downloads and keeps its profiles", () => + Effect.scoped( + Effect.gen(function* () { + const { stateDir } = yield* ServerConfig.ServerConfig; + const fs = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const previousTab = path.join(stateDir, "server-browser", "downloads", "previous-tab"); + const profile = path.join(stateDir, "server-browser", "profiles", "default"); + yield* fs.makeDirectory(previousTab, { recursive: true }); + yield* fs.makeDirectory(profile, { recursive: true }); + yield* fs.writeFileString(path.join(previousTab, "report.csv"), "a,b"); + yield* fs.writeFileString(path.join(profile, "Preferences"), "{}"); + + yield* Layer.build(ServerBrowser.layer); + + expect(yield* fs.exists(previousTab)).toBe(false); + expect(yield* fs.readFileString(path.join(profile, "Preferences"))).toBe("{}"); + }), + ).pipe(Effect.provide(dependencies)), +); + it.live("a page's file picker goes to the controller and takes its uploaded files", () => Effect.scoped( Effect.gen(function* () { diff --git a/apps/server/src/preview/ServerBrowser.ts b/apps/server/src/preview/ServerBrowser.ts index 93f6849bbb995..d4f05d7a35151 100644 --- a/apps/server/src/preview/ServerBrowser.ts +++ b/apps/server/src/preview/ServerBrowser.ts @@ -903,6 +903,12 @@ const make = Effect.gen(function* () { }; const downloadsRoot = NodePath.join(config.stateDir, "server-browser", "downloads"); + // Saved downloads are indexed in memory, so an earlier run's files can never be opened again. + yield* Effect.tryPromise(() => NodeFSP.rm(downloadsRoot, { recursive: true, force: true })).pipe( + Effect.catch((cause) => + Effect.logWarning("server preview could not clear earlier downloads", { cause }), + ), + ); // Tab ids are opaque server strings; hashing keeps them out of the path. const downloadDir = (tab: ServerTab) => NodePath.join(