fix: QA sweep -- SSE crash, memory leaks, HEIC Docker decode, TGA detection, lint cleanup

- Fix SSE write-after-end crash in progress.ts (remove callback before ending stream)
- Fix blob URL memory leaks: revoke processedPreviewUrl and old HEIC preview URLs
- Add AbortController to batch fetch in use-tool-processor and use-pipeline-processor
- Fix TGA format misidentified as CUR (extension overrides magic bytes)
- Add libheif-plugin-libde265 to Docker for HEIC/HEIF decode support
- Remove unused imports and state (AppLayout, setSampledColor, useEffect)
- Fix non-null assertions in meme-text-renderer and meme-generator
- Fix confusing void type in meme-templates
- Remove unnecessary useEffect deps in adjustments-panel
- Fix Playwright strict mode violations in 5 E2E tests
This commit is contained in:
SnapOtter
2026-05-09 13:55:00 +08:00
parent 9f97c466b3
commit 7f131d99a6
19 changed files with 48 additions and 20 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ function serveStaticFile(
filename: string,
reply: FastifyReply,
cacheControl: string,
): FastifyReply | void {
): FastifyReply | undefined {
if (hasPathTraversal(filename)) {
return reply.status(400).send({ error: "Invalid filename" });
}
+8
View File
@@ -254,12 +254,20 @@ export async function registerProgressRoutes(app: FastifyInstance): Promise<void
listeners.set(jobId, new Set());
}
let ended = false;
const callback = (data: JobProgress | SingleFileProgress) => {
if (ended) return;
sendEvent(data);
if (
("status" in data && (data.status === "completed" || data.status === "failed")) ||
("phase" in data && (data.phase === "complete" || data.phase === "failed"))
) {
ended = true;
const subs = listeners.get(jobId);
if (subs) {
subs.delete(callback);
if (subs.size === 0) listeners.delete(jobId);
}
reply.raw.end();
}
};
+4 -1
View File
@@ -260,7 +260,10 @@ export function registerMemeGenerator(app: FastifyInstance) {
// ── Process ─────────────────────────────────────────────────────
try {
// Normalize the image for Sharp compatibility
imageBuffer = await autoOrient(await ensureSharpCompat(imageBuffer!));
if (!imageBuffer) {
return reply.status(400).send({ error: "No image provided" });
}
imageBuffer = await autoOrient(await ensureSharpCompat(imageBuffer));
const output = await processMeme(imageBuffer, settings, filename, templateTextBoxes);