import { S3 } from '@aws-sdk/client-s3'; import { loadImage, createCanvas } from 'canvas'; import { awsConfig, awsParams } from '~/server/aws.ts'; import { newDate, sha256 } from '~/src/helpers.ts'; const s3 = new S3(awsConfig); 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, ...awsParams }); 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', ...awsParams, }); return `${process.env.NUXT_PUBLIC_CLOUDFRONT}/${key}`; } catch (e) { return null; } } };