Skip to content

Commit 04b9c58

Browse files
feat: switch OG images to vercel edge runtime + Satori
1 parent 07d84bd commit 04b9c58

File tree

9 files changed

+387
-420
lines changed

9 files changed

+387
-420
lines changed

lib/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { parsePageId } from 'notion-utils'
9-
import posthog from 'posthog-js'
9+
import type posthog from 'posthog-js'
1010
import { getEnv, getSiteConfig } from './get-config-value'
1111
import { NavigationLink } from './site-config'
1212
import {
@@ -131,6 +131,7 @@ export const apiBaseUrl = `/api`
131131

132132
export const api = {
133133
searchNotion: `${apiBaseUrl}/search-notion`,
134+
getNotionPageInfo: `${apiBaseUrl}/notion-page-info`,
134135
getSocialImage: `${apiBaseUrl}/social-image`
135136
}
136137

lib/fonts.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

lib/types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,13 @@ export interface PageUrlOverridesInverseMap {
6060
// (this overrides the built-in URL path generation for these pages)
6161
[pageId: string]: string
6262
}
63+
64+
export interface NotionPageInfo {
65+
pageId: string
66+
title: string
67+
image: string
68+
imageObjectPosition: string
69+
author: string
70+
authorImage: string
71+
detail: string
72+
}

package.json

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"@keyvhq/core": "^1.6.9",
3030
"@keyvhq/redis": "^1.6.10",
3131
"@react-icons/all-files": "^4.1.0",
32+
"@vercel/og": "^0.0.18",
3233
"classnames": "^2.3.1",
3334
"date-fns": "^2.28.0",
3435
"expiry-map": "^2.0.0",
@@ -37,7 +38,6 @@
3738
"isomorphic-unfetch": "^3.1.0",
3839
"lqip-modern": "^1.2.0",
3940
"next": "^12.3.1",
40-
"next-api-og-image": "^2.2.1",
4141
"notion-client": "^6.13.11",
4242
"notion-types": "^6.13.4",
4343
"notion-utils": "^6.13.4",
@@ -67,15 +67,7 @@
6767
"prettier": "^2.7.1",
6868
"typescript": "^4.8.4"
6969
},
70-
"resolutions": {
71-
"next-api-og-image/chrome-aws-lambda": "6.0.0",
72-
"next-api-og-image/puppeteer-core": "6.0.0"
73-
},
7470
"overrides": {
75-
"next-api-og-image": {
76-
"chrome-aws-lambda": "6.0.0",
77-
"puppeteer-core": "6.0.0"
78-
},
7971
"cacheable-request": {
8072
"keyv": "npm:@keyvhq/core@~1.6.6"
8173
}

pages/api/notion-page-info.tsx

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { NextApiRequest, NextApiResponse } from 'next'
2+
3+
import {
4+
getBlockTitle,
5+
getBlockIcon,
6+
getPageProperty,
7+
isUrl,
8+
parsePageId
9+
} from 'notion-utils'
10+
import { PageBlock } from 'notion-types'
11+
12+
import { notion } from 'lib/notion-api'
13+
import { mapImageUrl } from 'lib/map-image-url'
14+
import { NotionPageInfo } from 'lib/types'
15+
import * as libConfig from 'lib/config'
16+
17+
export default async (req: NextApiRequest, res: NextApiResponse) => {
18+
if (req.method !== 'POST') {
19+
return res.status(405).send({ error: 'method not allowed' })
20+
}
21+
22+
const pageId: string = parsePageId(req.body.pageId)
23+
if (!pageId) {
24+
throw new Error('Invalid notion page id')
25+
}
26+
27+
const recordMap = await notion.getPage(pageId)
28+
29+
const keys = Object.keys(recordMap?.block || {})
30+
const block = recordMap?.block?.[keys[0]]?.value
31+
32+
if (!block) {
33+
throw new Error('Invalid recordMap for page')
34+
}
35+
36+
const blockSpaceId = block.space_id
37+
38+
if (
39+
blockSpaceId &&
40+
libConfig.rootNotionSpaceId &&
41+
blockSpaceId !== libConfig.rootNotionSpaceId
42+
) {
43+
return res.status(400).send({
44+
error: `Notion page "${pageId}" belongs to a different workspace.`
45+
})
46+
}
47+
48+
const isBlogPost =
49+
block.type === 'page' && block.parent_table === 'collection'
50+
const title = getBlockTitle(block, recordMap) || libConfig.name
51+
const image = mapImageUrl(
52+
getPageProperty<string>('Social Image', block, recordMap) ||
53+
(block as PageBlock).format?.page_cover ||
54+
libConfig.defaultPageCover,
55+
block
56+
)
57+
58+
const imageCoverPosition =
59+
(block as PageBlock).format?.page_cover_position ??
60+
libConfig.defaultPageCoverPosition
61+
const imageObjectPosition = imageCoverPosition
62+
? `center ${(1 - imageCoverPosition) * 100}%`
63+
: null
64+
65+
const blockIcon = getBlockIcon(block, recordMap)
66+
const authorImage = mapImageUrl(
67+
blockIcon && isUrl(blockIcon) ? blockIcon : libConfig.defaultPageIcon,
68+
block
69+
)
70+
71+
const author =
72+
getPageProperty<string>('Author', block, recordMap) || libConfig.author
73+
74+
// const socialDescription =
75+
// getPageProperty<string>('Description', block, recordMap) ||
76+
// libConfig.description
77+
78+
// const lastUpdatedTime = getPageProperty<number>(
79+
// 'Last Updated',
80+
// block,
81+
// recordMap
82+
// )
83+
const publishedTime = getPageProperty<number>('Published', block, recordMap)
84+
const datePublished = publishedTime ? new Date(publishedTime) : undefined
85+
// const dateUpdated = lastUpdatedTime
86+
// ? new Date(lastUpdatedTime)
87+
// : publishedTime
88+
// ? new Date(publishedTime)
89+
// : undefined
90+
const date =
91+
isBlogPost && datePublished
92+
? `${datePublished.toLocaleString('en-US', {
93+
month: 'long'
94+
})} ${datePublished.getFullYear()}`
95+
: undefined
96+
const detail = date || author || libConfig.domain
97+
98+
const pageInfo: NotionPageInfo = {
99+
pageId,
100+
title,
101+
image,
102+
imageObjectPosition,
103+
author,
104+
authorImage,
105+
detail
106+
}
107+
108+
res.setHeader(
109+
'Cache-Control',
110+
'public, s-maxage=30, max-age=30, stale-while-revalidate=30'
111+
)
112+
res.status(200).json(pageInfo)
113+
}

0 commit comments

Comments
 (0)