import { loadImage, createCanvas } from 'canvas'; import { newDate, sha256 } from '#shared/helpers.ts'; import { s3, s3BucketParams } from '~~/server/cloudServices.ts'; const convertToPng = async (original: Buffer): Promise => { const image = await loadImage(original); const canvas = createCanvas(image.width, image.height); canvas.getContext('2d').drawImage(image, 0, 0); return canvas.toBuffer('image/png'); }; export default async (prefix: string, url: string, ttlDays: number | null = null): Promise => { if (!url) { return null; } const isSvg = url.toLowerCase().replace(/\?.*$/, '').endsWith('.svg') || url.startsWith('data:image/svg+xml'); const key = `${prefix}/${await sha256(url)}.${isSvg ? 'svg' : 'png'}`; try { const metadata = await s3.headObject({ Key: key, ...s3BucketParams }); if ( ttlDays !== null && metadata.LastModified! < new Date( newDate().setDate(newDate().getDate() - ttlDays), ) ) { throw 'force refresh'; } return `${process.env.NUXT_PUBLIC_CLOUDFRONT}/${key}`; } catch { try { const originalBuffer = Buffer.from(await (await fetch(url)).arrayBuffer()); await s3.putObject({ Key: key, Body: isSvg ? originalBuffer : await convertToPng(originalBuffer), ContentType: isSvg ? 'image/svg+xml' : 'image/png', ACL: 'public-read', ...s3BucketParams, }); return `${process.env.NUXT_PUBLIC_CLOUDFRONT}/${key}`; } catch (e) { return null; } } };