diff --git a/packages/og/src/generate.ts b/packages/og/src/generate.ts index 6c1a82d..57366a3 100644 --- a/packages/og/src/generate.ts +++ b/packages/og/src/generate.ts @@ -5,6 +5,8 @@ import satori from 'satori' import { Resvg } from '@resvg/resvg-js' +import { head, put } from '@vercel/blob' +import { createHash } from 'node:crypto' import { loadFonts, createSatoriFonts } from './fonts.js' import { generateNoiseDataUrl, generateCircleNoiseDataUrl } from './noise.js' import { getTemplate } from './templates/index.js' @@ -19,6 +21,24 @@ import type { export const OG_WIDTH = 1200 export const OG_HEIGHT = 630 +/** + * Generate a deterministic hash for the options to use as a blob key. + */ +function getOptionsHash(options: OgGenerateOptions): string { + const str = JSON.stringify({ + title: options.title, + description: options.description, + siteName: options.siteName, + image: options.image, + template: options.template || 'blog', + colors: options.colors, + noise: options.noise, + width: options.width || OG_WIDTH, + height: options.height || OG_HEIGHT, + }) + return createHash('sha256').update(str).digest('hex') +} + /** * Generate an OG image as PNG Buffer. */ @@ -38,6 +58,26 @@ export async function generateOgImage(options: OgGenerateOptions): Promise null) + if (existingBlob) { + const response = await fetch(blobUrl) + if (response.ok) { + const arrayBuffer = await response.arrayBuffer() + return Buffer.from(arrayBuffer) + } + } + } catch (e) { + console.error('Failed to check Vercel Blob:', e) + } + } + // Merge colours const colors: OgColorConfig = { ...defaultColors, @@ -110,8 +150,22 @@ export async function generateOgImage(options: OgGenerateOptions): Promise