/** * apps/worker — files pipeline: thumbnail step (TASK-0102 §5). * * Generates every planned artifact (images → 3 sizes, pdf → page 1, video → * first frame) via `generateThumbs` and writes them to the `thumbs` bucket. * * Idempotent by key (the plan is deterministic from the row; a re-run of a * READY file is a no-op upstream, so these PUTs are never re-executed with * different bytes). A generate failure is FATAL (corrupt_object — the * object's kind was identified by magic bytes, so it can't be fixed by a * retry) and lands in `metadata.pipeline.error` via the processor. */ import { generateThumbs } from "../generateThumbs.js"; import type { FilePipelineContext, ThumbsResult } from "../types.js"; export async function thumbnailsStep( ctx: FilePipelineContext, finalMime: string ): Promise { const { job } = ctx; const fileRow = await ctx.prisma.file.findUniqueOrThrow({ where: { id: job.fileId } }); const { artifacts, primaryKey } = await generateThumbs({ sourcePath: ctx.temp.path, mime: finalMime, workspaceId: fileRow.workspaceId, fileId: job.fileId, name: fileRow.name, ...(ctx.extracted.dimensions ? { sourceWidth: ctx.extracted.dimensions.width } : {}) }); for (const a of artifacts) { await ctx.s3Thumbs.putObject(a.key, a.body, a.mime); } return { primaryKey, keys: artifacts.map((a) => a.key) }; }