Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't let opengraph image embeds go stale #2765

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions common/src/contract-seo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const getContractOGProps = (
creatorName,
outcomeType,
creatorAvatarUrl,
id,
} = contract

const topAnswer =
Expand Down Expand Up @@ -58,6 +59,7 @@ export const getContractOGProps = (
resolution,
topAnswer: topAnswer?.text,
bountyLeft: bountyLeft,
contractId: id,
}
}

Expand All @@ -73,6 +75,7 @@ export type OgCardProps = {
topAnswer?: string
bountyLeft?: string // number
points?: string // base64ified points
contractId?: string
}

export function getSeoDescription(contract: Contract) {
Expand Down
44 changes: 38 additions & 6 deletions web/pages/api/og/market.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { ImageResponseOptions } from '@vercel/og/dist/types'
import { NextRequest } from 'next/server'
import { OgMarket } from 'web/components/og/og-market'
import { classToTw } from 'web/components/og/utils'
import { OgCardProps } from 'common/contract-seo'
import { getContractOGProps, OgCardProps } from 'common/contract-seo'

export const config = { runtime: 'edge' }
export const getCardOptions = async () => {
export const getCardOptions = async (): Promise<ImageResponseOptions> => {
const [light, med] = await Promise.all([figtreeLightData, figtreeMediumData])

// https://vercel.com/docs/functions/og-image-generation/og-image-api
return {
width: 600,
height: 315,
Expand All @@ -24,6 +25,11 @@ export const getCardOptions = async () => {
style: 'normal',
},
],
headers: {
// max-age is in seconds. Vercel defaults to a very large value, but
// we want to show fresh data, so we override here.
'cache-control': 'public, no-transform, max-age=30',
},
}
}

Expand All @@ -36,16 +42,42 @@ const figtreeMediumData = fetch(FIGTREE_MED_URL).then((res) =>
res.arrayBuffer()
)

async function getFreshOgMarketProps(
contractId: string | undefined,
origin: string
): Promise<OgCardProps | undefined> {
if (contractId) {
try {
const resp = await fetch(`${origin}/api/v0/market/${contractId}`)
const contract = resp.ok && (await resp.json())

if (contract) {
return getContractOGProps(contract)
}
} catch (e) {
console.log(
`Failed to fetch contract ${contractId} when rendering OG image`,
e
)
}
}
return undefined
}

export default async function handler(req: NextRequest) {
try {
const { searchParams } = new URL(req.url)
const { searchParams, origin } = new URL(req.url)
const options = await getCardOptions()
const OgMarketProps = Object.fromEntries(
const ogMarketPropsFromParams = Object.fromEntries(
searchParams.entries()
) as OgCardProps
const image = OgMarket(OgMarketProps)
const { contractId } = ogMarketPropsFromParams

const ogMarketPropsFromDb = await getFreshOgMarketProps(contractId, origin)

const image = OgMarket(ogMarketPropsFromDb ?? ogMarketPropsFromParams)

return new ImageResponse(classToTw(image), options as ImageResponseOptions)
return new ImageResponse(classToTw(image), options)
} catch (e: any) {
console.log(`${e.message}`)
return new Response(`Failed to generate the image`, {
Expand Down
Loading