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 3 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
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"verify": "yarn --cwd=common verify:dir; yarn --cwd=web verify:dir; yarn --cwd=backend/functions verify:dir; yarn --cwd=backend/shared verify:dir",
"lint": "yarn --cwd=web lint-fix; eslint common --fix ; eslint backend/functions --fix ; eslint backend/api --fix ; eslint backend/shared --fix",
"_comment": "Place your admin json under /backend/functions/ to enable this:",
"dev:dev": "cross-env GOOGLE_APPLICATION_CREDENTIALS_DEV=./dev-mantic-markets-firebase-adminsdk.json ./dev.sh dev"
"dev:dev": "cross-env GOOGLE_APPLICATION_CREDENTIALS_DEV=./dev-mantic-markets-firebase-adminsdk.json ./dev.sh dev",
"postinstall": "patch-package"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, so when are we're supposed to run this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It runs automatically as part of the installation lifecycle, apparently: https://yarnpkg.com/advanced/lifecycle-scripts#postinstall

But moot point if we're going with the public API.

},
"dependencies": {},
"devDependencies": {
Expand All @@ -27,6 +28,8 @@
"eslint-plugin-lodash": "^7.4.0",
"eslint-plugin-unused-imports": "^2.0.0",
"nodemon": "2.0.20",
"patch-package": "8.0.0",
"postinstall-postinstall": "2.1.0",
"prettier": "2.8.4",
"ts-node": "10.9.1",
"tsc-alias": "1.8.2",
Expand Down
12 changes: 12 additions & 0 deletions patches/lodash+4.17.21.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/node_modules/lodash/_root.js b/node_modules/lodash/_root.js
index d2852be..aa44a86 100644
--- a/node_modules/lodash/_root.js
+++ b/node_modules/lodash/_root.js
@@ -4,6 +4,6 @@ var freeGlobal = require('./_freeGlobal');
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;

/** Used as a reference to the global object. */
-var root = freeGlobal || freeSelf || Function('return this')();
+var root = freeGlobal || freeSelf;

module.exports = root;
40 changes: 35 additions & 5 deletions web/pages/api/og/market.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ 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'
import { getContract } from 'common/supabase/contracts'
import { db } from 'web/lib/supabase/db'

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 +27,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 +44,38 @@ const figtreeMediumData = fetch(FIGTREE_MED_URL).then((res) =>
res.arrayBuffer()
)

async function getFreshOgMarketProps(
contractId: string | undefined
): Promise<OgCardProps | undefined> {
if (contractId) {
try {
const contract = await getContract(db, contractId)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It think it would be simpler to just use the public api to fetch the contract rather than use the internal api. That way we don't have to patch lodash, either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't aware of the public API, thanks for the pointer.

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 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)

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
Loading