forked from transitive-bullshit/nextjs-notion-starter-kit
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy path[pageId].ts
129 lines (112 loc) · 3.48 KB
/
[pageId].ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { NextApiRequest, NextApiResponse } from 'next'
import chromium from 'chrome-aws-lambda'
import renderSocialImage from 'puppeteer-social-image-transitive-bs'
import { getBlockTitle, parsePageId } from 'notion-utils'
import { mapNotionImageUrl } from '../../lib/map-image-url'
// import { getPageDescription } from '../../lib/get-page-description'
import { getPage } from '../../lib/notion'
import * as types from '../../lib/types'
import {
socialImageTitle,
// socialImageSubtitle,
defaultPageCover,
defaultPageIcon,
rootNotionPageId,
socialImageSubtitle
} from '../../lib/config'
export interface SocialImageConfig {
title: string
subtitle?: string
eyebrow?: string
logo?: string
imageUrl?: string
unsplashId?: string
unsplashKeywords?: string
backgroundImageAnchor?: string
backgroundImageOverlay?: boolean
background?: string
color?: string
googleFont?: string
fontFamily?: string
watermark?: string
size?:
| 'facebook'
| 'twitter'
| 'ig-landscape'
| 'ig-portrait'
| 'ig-square'
| 'ig-story'
}
export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== 'GET') {
return res.status(405).send({ error: 'method not allowed' })
}
const pageId = req.query.pageId as string
if (!pageId) {
return res.status(400).send({ error: 'missing required parameter pageId' })
}
let recordMap: types.ExtendedRecordMap
let block: types.PageBlock
try {
recordMap = await getPage(pageId)
const pageBlockId = Object.keys(recordMap.block)[0]
block = recordMap.block[pageBlockId]?.value as types.PageBlock
if (!block) {
return res.status(404).send({
error: `unable to resolve root block for notion page "${pageId}"`
})
}
} catch (err) {
return res
.status(404)
.send({ error: `unable to load notion page "${pageId}"` })
}
const isRootPage = parsePageId(block.id) === parsePageId(rootNotionPageId)
const image = await createSocialImage({
imageUrl: mapNotionImageUrl(
block.format?.page_cover || defaultPageCover,
block
),
logo: mapNotionImageUrl(defaultPageIcon, block),
title: isRootPage
? socialImageTitle
: getBlockTitle(block, recordMap) || socialImageTitle,
subtitle: isRootPage ? socialImageSubtitle : undefined
// subtitle: getPageDescription(block, recordMap) || socialImageSubtitle
})
res.setHeader(
'Cache-Control',
'public, immutable, s-maxage=31536000, max-age=31536000, stale-while-revalidate=60'
)
res.setHeader('Content-Type', 'image/jpeg')
res.status(200).send(image)
}
async function createSocialImage(params: SocialImageConfig) {
let browser
try {
// add font support for emojis
// @see https://github.com/alixaxel/chrome-aws-lambda#fonts
await chromium.font(
'https://raw.githack.com/googlei18n/noto-emoji/master/fonts/NotoColorEmoji.ttf'
)
browser = await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath,
headless: true, // chromium.headless,
ignoreHTTPSErrors: true
})
const res = await renderSocialImage({
template: 'article',
templateParams: params,
templateStyles: `h1 { font-size: 96px; text-align: center; } h2 { margin-top: 48px; font-size: 48px; text-align: center; }`,
size: params.size,
browser
})
return res
} finally {
if (browser) {
await browser.close()
}
}
}