All files / src/lib uploads.ts

100% Statements 24/24
100% Branches 10/10
100% Functions 3/3
100% Lines 24/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 628x 8x 8x       8x           8x 8x   8x 8x     30x       3x 2x   1x                                 16x 16x 16x   21x   21x 5x 5x   16x 2x 2x   14x   16x    
export const MAX_UPLOAD_BYTES = 4_500_000;
const MAX_UPLOAD_LABEL = "4.5 MB";
export const MAX_UPLOAD_ERROR = `Image must be ${MAX_UPLOAD_LABEL} or smaller`;
 
/** Pool bulk-upload limits — the durable client-upload path (separate from the
 *  4.5MB serverless single-photo cap above). Mirrors the token endpoint. */
export const POOL_ALLOWED_CONTENT_TYPES = [
  "image/jpeg",
  "image/png",
  "image/gif",
  "image/webp",
] as const;
export const POOL_MAX_BYTES = 50_000_000;
const POOL_MAX_LABEL = "50 MB";
 
const HEIF_EXTENSIONS = /\.(heic|heif)$/i;
const HEIF_MIME_TYPES = new Set(["image/heic", "image/heif"]);
 
export function isHeifFile(file: Pick<File, "name" | "type">): boolean {
  return HEIF_MIME_TYPES.has(file.type.toLowerCase()) || HEIF_EXTENSIONS.test(file.name);
}
 
export function buildJpegFileName(name: string): string {
  if (name.includes(".")) {
    return name.replace(/\.[^.]+$/, ".jpg");
  }
  return `${name}.jpg`;
}
 
export interface SkippedFile {
  name: string;
  reason: string;
}
export interface PoolFilePartition {
  accepted: File[];
  skipped: SkippedFile[];
}
 
/** Pre-flight: split selected files into those the pool endpoint will accept
 *  vs. those to skip up front (with a gentle reason), so we never upload bytes
 *  that the token endpoint would reject. HEIC/HEIF is accepted — it is converted
 *  to JPEG before upload. */
export function partitionPoolFiles(files: File[]): PoolFilePartition {
  const accepted: File[] = [];
  const skipped: SkippedFile[] = [];
  for (const file of files) {
    const typeOk =
      isHeifFile(file) ||
      (POOL_ALLOWED_CONTENT_TYPES as readonly string[]).includes(file.type);
    if (!typeOk) {
      skipped.push({ name: file.name, reason: "This kind of photo isn't supported yet" });
      continue;
    }
    if (file.size > POOL_MAX_BYTES) {
      skipped.push({ name: file.name, reason: `This photo is over ${POOL_MAX_LABEL}` });
      continue;
    }
    accepted.push(file);
  }
  return { accepted, skipped };
}