Browse Source

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 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 4 months ago
parent
commit
4ca2ac31e0
  1. 13
      scripts/cleanup-workflow.js
  2. 18
      src/app/api/workflow/route.ts
  3. 6
      src/utils/mediaStorage.ts

13
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;
}

18
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,

6
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;
}

Loading…
Cancel
Save