aboutsummaryrefslogtreecommitdiffstats
path: root/lib/image-worker.ts
blob: d45927d1416b2382ab7a618530a9d70ac7aaaee4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Image conversion runs in THIS separate process, spawned per upload by
// lib/image.ts. It is the only place sharp/libvips is ever loaded. Reads the
// raw upload on stdin, writes the resized webp to stdout, exits 0. Any
// decoder bug (libheif/libwebp/libpng heap corruption, SIGSEGV, SIGILL) kills
// this process alone — the app keeps serving. 2026-09-26: a stream of corrupt
// HEIF uploads crash-looped the whole server when this ran in-process.
const sharp = require("sharp");

const MAX_PIXELS = 80_000_000;

const width = Number(process.argv[2]);
if (!Number.isInteger(width) || width <= 0 || width > 4096) {
  console.error("bad width");
  process.exit(2);
}

try {
  const input = Buffer.from(await new Response(Bun.stdin.stream()).arrayBuffer());
  const out = await sharp(input, { failOnError: true, limitInputPixels: MAX_PIXELS })
    .rotate()
    .resize(width)
    .webp()
    .toBuffer();
  await Bun.write(Bun.stdout, out);
  process.exit(0);
} catch (e) {
  console.error(e?.message || String(e));
  process.exit(2);
}