fix: QA sweep fixes across migration, security, lint, and e2e tests

- fix(db): migration 0012 column order mismatch causing NOT NULL
  constraint failure on existing databases; use explicit column
  mapping instead of SELECT *
- fix(db): disable FK checks during migrations to allow SQLite
  table-recreation pattern (DROP + RENAME)
- fix(security): filter cookie_secret and instance_id from settings
  API response for non-admin users
- fix(lint): resolve all 7 API lint warnings (noParameterAssign,
  noImplicitAnyLet) in compose, image-enhancement, and workspace
- fix(docs): correct permission count from 16 to 14 in CLAUDE.md
- fix(e2e): resolve 44 Playwright test failures across 8 spec files
  including locator specificity, compress mode defaults, format count,
  restore-photo UI drift, stitch image count, GIF animated fixtures,
  submit button timing, and processing timeouts
This commit is contained in:
SnapOtter
2026-05-15 22:41:22 +08:00
parent 3b181dd1ac
commit 51bc2d5732
15 changed files with 248 additions and 244 deletions
+8 -7
View File
@@ -13,23 +13,24 @@ import { decodeHeic } from "../../lib/heic-converter.js";
import { decompressSvgz, sanitizeSvg } from "../../lib/svg-sanitize.js";
import { createWorkspace } from "../../lib/workspace.js";
async function decodeBuffer(buffer: Buffer, filename: string): Promise<Buffer> {
const validation = await validateImageBuffer(buffer, filename);
async function decodeBuffer(inputBuffer: Buffer, filename: string): Promise<Buffer> {
const validation = await validateImageBuffer(inputBuffer, filename);
if (!validation.valid) {
throw new Error(`Invalid image: ${validation.reason}`);
}
let decoded = inputBuffer;
if (validation.format === "heif") {
buffer = await decodeHeic(buffer);
decoded = await decodeHeic(decoded);
} else if (needsCliDecode(validation.format)) {
const ext = filename.split(".").pop()?.toLowerCase();
buffer = await decodeToSharpCompat(buffer, validation.format, ext);
decoded = await decodeToSharpCompat(decoded, validation.format, ext);
} else if (validation.format === "svg") {
buffer = decompressSvgz(buffer);
buffer = sanitizeSvg(buffer);
decoded = decompressSvgz(decoded);
decoded = sanitizeSvg(decoded);
}
return autoOrient(buffer);
return autoOrient(decoded);
}
const settingsSchema = z.object({
@@ -34,13 +34,14 @@ const settingsSchema = z.object({
type EnhancementSettings = z.infer<typeof settingsSchema>;
async function processImageEnhancement(
inputBuffer: Buffer,
rawBuffer: Buffer,
settings: EnhancementSettings,
filename: string,
) {
const outputFormat = await resolveOutputFormat(inputBuffer, filename);
const outputFormat = await resolveOutputFormat(rawBuffer, filename);
// HDR/EXR decodes can produce 16-bit buffers; CLAHE requires 8-bit (VIPS_FORMAT_UCHAR)
let inputBuffer = rawBuffer;
const inputMeta = await sharp(inputBuffer).metadata();
if (inputMeta.depth && inputMeta.depth !== "uchar") {
inputBuffer = await sharp(inputBuffer).toColourspace("srgb").png().toBuffer();