// Todo: (RR7) Test, used AI to migrate this component from NextJS to Remix. import satori from 'satori'; import sharp from 'sharp'; import { P, match } from 'ts-pattern'; import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app'; import type { ShareHandlerAPIResponse } from '../api+/share'; import type { Route } from './+types/share.$slug.opengraph'; export const runtime = 'edge'; const CARD_OFFSET_TOP = 173; const CARD_OFFSET_LEFT = 307; const CARD_WIDTH = 590; const CARD_HEIGHT = 337; const IMAGE_SIZE = { width: 1200, height: 630, }; export const loader = async ({ params }: Route.LoaderArgs) => { const { slug } = params; const baseUrl = NEXT_PUBLIC_WEBAPP_URL(); const [interSemiBold, interRegular, caveatRegular] = await Promise.all([ fetch(new URL(`${baseUrl}/fonts/inter-semibold.ttf`, import.meta.url)).then(async (res) => res.arrayBuffer(), ), fetch(new URL(`${baseUrl}/fonts/inter-regular.ttf`, import.meta.url)).then(async (res) => res.arrayBuffer(), ), fetch(new URL(`${baseUrl}/fonts/caveat-regular.ttf`, import.meta.url)).then(async (res) => res.arrayBuffer(), ), ]); const recipientOrSender: ShareHandlerAPIResponse = await fetch( new URL(`/api/share?slug=${slug}`, baseUrl), ).then(async (res) => res.json()); if ('error' in recipientOrSender) { return Response.json({ error: 'Not found' }, { status: 404 }); } const isRecipient = 'Signature' in recipientOrSender; const signatureImage = match(recipientOrSender) .with({ signatures: P.array(P._) }, (recipient) => { return recipient.signatures?.[0]?.signatureImageAsBase64 || null; }) .otherwise((sender) => { return sender.signature || null; }); const signatureName = match(recipientOrSender) .with({ signatures: P.array(P._) }, (recipient) => { return recipient.name || recipient.email; }) .otherwise((sender) => { return sender.name || sender.email; }); // Generate SVG using Satori const svg = await satori(
og-share-frame {signatureImage ? (
signature
) : (

{signatureName}

)}

{isRecipient ? 'Document Signed!' : 'Document Sent!'}

, { width: IMAGE_SIZE.width, height: IMAGE_SIZE.height, fonts: [ { name: 'Caveat', data: caveatRegular, style: 'italic', }, { name: 'Inter', data: interRegular, weight: 400, }, { name: 'Inter', data: interSemiBold, weight: 600, }, ], }, ); // Convert SVG to PNG using sharp const pngBuffer = await sharp(Buffer.from(svg)).toFormat('png').toBuffer(); return new Response(pngBuffer, { headers: { 'Content-Type': 'image/png', 'Content-Length': pngBuffer.length.toString(), 'Cache-Control': 'public, max-age=31536000, immutable', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, OPTIONS', }, }); };