- Split llmModerationClient.ts (2170 lines) into 5 focused sub-modules - Split aiAnalyzer.ts (1282 lines) into 4 modular pipelines - Split messages.db.ts (826 lines) into 5 domain-specific modules - Moved shared schema to @bete/shared, eliminated backend duplication - Added createChildLogger to all voice-recording and AI moderation modules - Extracted tryCommandThenFallback, normalizeMediaState, DEFAULT_VOICE_STATUS - Created shared pagination.ts utility, eliminated 5+ cursor-pagination duplications - Created shared messageMapper.ts for row mapping - Standardized backend error handling with asyncHandler - Added frontend createLogger utility and useAsyncAction hook - Added structured logging to frontend hooks, socket, and API client Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
77 lines
1.6 KiB
TypeScript
77 lines
1.6 KiB
TypeScript
import { createChildLogger } from "@bete/shared/logger";
|
|
|
|
const log = createChildLogger("imageMimeSniffer");
|
|
|
|
/**
|
|
* Sniff the first bytes of a buffer to determine if it is a supported image
|
|
* format. Returns the canonical MIME type string on success, or null if the
|
|
* bytes are not a recognizable image.
|
|
*/
|
|
export function sniffImageMimeType(buf: Buffer): string | null {
|
|
if (buf.length < 12) return null;
|
|
|
|
if (buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff) {
|
|
return "image/jpeg";
|
|
}
|
|
|
|
if (
|
|
buf[0] === 0x89 &&
|
|
buf[1] === 0x50 &&
|
|
buf[2] === 0x4e &&
|
|
buf[3] === 0x47 &&
|
|
buf[4] === 0x0d &&
|
|
buf[5] === 0x0a &&
|
|
buf[6] === 0x1a &&
|
|
buf[7] === 0x0a
|
|
) {
|
|
return "image/png";
|
|
}
|
|
|
|
if (
|
|
buf[0] === 0x47 &&
|
|
buf[1] === 0x49 &&
|
|
buf[2] === 0x46 &&
|
|
buf[3] === 0x38
|
|
) {
|
|
return "image/gif";
|
|
}
|
|
|
|
if (
|
|
buf[0] === 0x52 &&
|
|
buf[1] === 0x49 &&
|
|
buf[2] === 0x46 &&
|
|
buf[3] === 0x46 &&
|
|
buf[8] === 0x57 &&
|
|
buf[9] === 0x45 &&
|
|
buf[10] === 0x42 &&
|
|
buf[11] === 0x50
|
|
) {
|
|
return "image/webp";
|
|
}
|
|
|
|
if (
|
|
buf.length >= 12 &&
|
|
buf[4] === 0x66 &&
|
|
buf[5] === 0x74 &&
|
|
buf[6] === 0x79 &&
|
|
buf[7] === 0x70
|
|
) {
|
|
const brand = buf.subarray(8, 12).toString("ascii");
|
|
if (brand.startsWith("avif") || brand.startsWith("avis")) {
|
|
return "image/avif";
|
|
}
|
|
if (
|
|
brand.startsWith("mif1") ||
|
|
brand.startsWith("heic") ||
|
|
brand.startsWith("heis")
|
|
) {
|
|
return "image/heic";
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// Keep log referenced so TS does not tree-shake the logger init
|
|
log.debug("imageMimeSniffer loaded");
|