From 4ca2ac31e0f4df753194b3d658d09f44e489c794 Mon Sep 17 00:00:00 2001 From: shrimbly Date: Sun, 29 Mar 2026 19:28:20 +1300 Subject: [PATCH] fix: cleanup-workflow filter, workflow load validation, media hydration guard - cleanup-workflow.js: Filter only embedded data: images from outputGallery instead of wiping entire array; preserve imageRef/video on output nodes - workflow/route.ts: Validate parsed.version is number, nodes/edges are arrays; sort candidates by mtime desc for deterministic file selection - mediaStorage.ts: Guard against undefined mediaData in loadMediaById before caching/returning Co-Authored-By: Claude Opus 4.6 --- scripts/cleanup-workflow.js | 13 ++++++------- src/app/api/workflow/route.ts | 18 +++++++++++++++++- src/utils/mediaStorage.ts | 6 +++++- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/scripts/cleanup-workflow.js b/scripts/cleanup-workflow.js index 8824d0ac..61ff63ef 100644 --- a/scripts/cleanup-workflow.js +++ b/scripts/cleanup-workflow.js @@ -26,12 +26,15 @@ workflow.nodes.forEach((node, index) => { const imageCount = node.data.images.filter(img => img && img.startsWith('data:')).length; if (imageCount > 0) { + const removedImages = node.data.images.filter(img => img && img.startsWith('data:')); + const removedSize = removedImages.reduce((sum, img) => sum + img.length, 0); + console.log(`\nNode ${index} (${node.id}):`); console.log(` Found ${imageCount} embedded images`); - console.log(` Size: ${(sizeBefore / 1024 / 1024).toFixed(2)} MB`); + console.log(` Size: ${(removedSize / 1024 / 1024).toFixed(2)} MB`); - node.data.images = []; - totalSizeBefore += sizeBefore; + node.data.images = node.data.images.filter(img => !(img && img.startsWith('data:'))); + totalSizeBefore += removedSize; cleaned = true; } } @@ -43,10 +46,6 @@ workflow.nodes.forEach((node, index) => { console.log(` Size: ${(sizeBefore / 1024 / 1024).toFixed(2)} MB`); node.data.image = null; - node.data.imageRef = undefined; - if (node.data.video) { - node.data.video = null; - } totalSizeBefore += sizeBefore; cleaned = true; } diff --git a/src/app/api/workflow/route.ts b/src/app/api/workflow/route.ts index 08d994e8..1bcf0b24 100644 --- a/src/app/api/workflow/route.ts +++ b/src/app/api/workflow/route.ts @@ -189,13 +189,29 @@ export async function GET(request: NextRequest) { const entries = await fs.readdir(directoryPath); const jsonFiles = entries.filter(f => f.endsWith(".json")); + // Gather candidates with mtime for deterministic selection (newest first) + const candidates: { jsonFile: string; filePath: string; mtime: number }[] = []; for (const jsonFile of jsonFiles) { try { const filePath = path.join(directoryPath, jsonFile); + const stat = await fs.stat(filePath); + candidates.push({ jsonFile, filePath, mtime: stat.mtimeMs }); + } catch { + continue; + } + } + candidates.sort((a, b) => b.mtime - a.mtime); + + for (const { jsonFile, filePath } of candidates) { + try { const content = await fs.readFile(filePath, "utf-8"); const parsed = JSON.parse(content); - if (parsed.version && parsed.nodes && parsed.edges) { + if ( + typeof parsed.version === "number" && + Array.isArray(parsed.nodes) && + Array.isArray(parsed.edges) + ) { const filename = path.basename(jsonFile, ".json"); logger.info('file.load', 'Workflow loaded from directory', { directoryPath, diff --git a/src/utils/mediaStorage.ts b/src/utils/mediaStorage.ts index 4099804d..9b7a81fa 100644 --- a/src/utils/mediaStorage.ts +++ b/src/utils/mediaStorage.ts @@ -1100,11 +1100,15 @@ async function loadMediaById( genResult = await response.json(); } - const mediaData = mediaType === "video" ? genResult.video : genResult.audio; if (!genResult.success) { console.log(`${mediaType} not found: ${mediaId}`); return ""; } + const mediaData = mediaType === "video" ? genResult.video : genResult.audio; + if (!mediaData) { + console.log(`${mediaType} not found or invalid payload: ${mediaId}`); + return ""; + } loadedMedia.set(mediaId, mediaData); return mediaData; }