${renderToStaticMarkup(
post.preview
- ? (post.preview || []).map((block, idx) =>
+ ? (post.preview || []).map((block: any, idx: number) =>
textBlock(block, false, post.title + idx)
)
: post.content
@@ -54,13 +55,8 @@ function mapToEntry(post) {
`
}
-function concat(total, item) {
- return total + item
-}
-
-function createRSS(blogPosts = []) {
- const postsString = blogPosts.map(mapToEntry).reduce(concat, '')
-
+function createRSS(blogPosts: any[] = []) {
+ const postsString = blogPosts.map(mapToEntry).join('')
return `
My Blog
@@ -73,25 +69,33 @@ function createRSS(blogPosts = []) {
}
async function main() {
- await loadEnvConfig(process.cwd())
- serverConstants.NOTION_TOKEN = process.env.NOTION_TOKEN
- serverConstants.BLOG_INDEX_ID = serverConstants.normalizeId(
- process.env.BLOG_INDEX_ID
- )
+ loadEnvConfig(process.cwd())
+
+ const token = process.env.NOTION_TOKEN
+ const blogIndex = process.env.BLOG_INDEX_ID
+
+ if (!token || !blogIndex) {
+ throw new Error(`❌ NOTION_TOKEN ou BLOG_INDEX_ID não estão definidos.`)
+ }
+
+ serverConstants.NOTION_TOKEN = token
+ serverConstants.BLOG_INDEX_ID = serverConstants.normalizeId(blogIndex)
const postsTable = await getBlogIndex(true)
- const neededAuthors = new Set()
+ if (!postsTable || Object.keys(postsTable).length === 0) {
+ throw new Error(
+ `❌ Nenhum post carregado. Verifique o ID do blog ou a API.`
+ )
+ }
+
+ const neededAuthors = new Set()
const blogPosts = Object.keys(postsTable)
.map((slug) => {
const post = postsTable[slug]
- if (!postIsPublished(post)) return
-
- post.authors = post.Authors || []
-
- for (const author of post.authors) {
- neededAuthors.add(author)
- }
+ if (!postIsPublished(post)) return null
+ post.authors = post.Authors ?? []
+ post.authors.forEach((a: string) => neededAuthors.add(a))
return post
})
.filter(Boolean)
@@ -99,7 +103,7 @@ async function main() {
const { users } = await getNotionUsers([...neededAuthors])
blogPosts.forEach((post) => {
- post.authors = post.authors.map((id) => users[id])
+ post.authors = post.authors.map((id: string) => users[id])
post.link = getBlogLink(post.Slug)
post.title = post.Page
post.date = post.Date
@@ -107,7 +111,10 @@ async function main() {
const outputPath = './public/atom'
await writeFile(resolve(outputPath), createRSS(blogPosts))
- console.log(`Atom feed file generated at \`${outputPath}\``)
+ console.log(`✅ Atom feed gerado com sucesso: \`${outputPath}\``)
}
-main().catch((error) => console.error(error))
+main().catch((err) => {
+ console.error('❌ Erro ao gerar RSS:', err)
+ process.exit(1)
+})
diff --git a/src/lib/notion/createTable.js b/src/lib/notion/createTable.js
index d47a7185..4d8bbd34 100644
--- a/src/lib/notion/createTable.js
+++ b/src/lib/notion/createTable.js
@@ -347,7 +347,7 @@ async function getExistingexistingBlockId() {
}
const data = await res.json()
const id = Object.keys(data ? data.recordMap.block : {}).find(
- id => id !== pageId
+ (id) => id !== pageId
)
return id || uuid()
}
diff --git a/src/lib/notion/getBlogIndex.ts b/src/lib/notion/getBlogIndex.ts
index 2c02622a..3649b69b 100644
--- a/src/lib/notion/getBlogIndex.ts
+++ b/src/lib/notion/getBlogIndex.ts
@@ -13,20 +13,28 @@ export default async function getBlogIndex(previews = true) {
if (useCache) {
try {
postsTable = JSON.parse(await readFile(cacheFile, 'utf8'))
- } catch (_) {
- /* not fatal */
+ } catch (err) {
+ console.warn(
+ 'Failed to load blog index cache, will generate new one:',
+ err
+ )
}
}
if (!postsTable) {
try {
- const data = await rpc('loadPageChunk', {
+ interface NotionResponse {
+ recordMap: {
+ block: Record
+ }
+ }
+ const data = (await rpc('loadPageChunk', {
pageId: BLOG_INDEX_ID,
- limit: 100, // TODO: figure out Notion's way of handling pagination
+ limit: 100,
cursor: { stack: [] },
chunkNumber: 0,
verticalColumns: false,
- })
+ })) as NotionResponse
// Parse table with posts
const tableBlock = values(data.recordMap.block).find(
@@ -36,9 +44,10 @@ export default async function getBlogIndex(previews = true) {
postsTable = await getTableData(tableBlock, true)
} catch (err) {
console.warn(
- `Failed to load Notion posts, have you run the create-table script?`
+ `Failed to load Notion posts, have you run the create-table script?`,
+ err
)
- return {}
+ throw new Error('Failed to load Notion posts: ' + (err as Error).message)
}
// only get 10 most recent post's previews
@@ -49,6 +58,7 @@ export default async function getBlogIndex(previews = true) {
if (previews) {
await Promise.all(
postsKeys
+ .slice()
.sort((a, b) => {
const postA = postsTable[a]
const postB = postsTable[b]
diff --git a/src/lib/notion/getNotionAssetUrls.ts b/src/lib/notion/getNotionAssetUrls.ts
index 2db1eab1..e8f68584 100644
--- a/src/lib/notion/getNotionAssetUrls.ts
+++ b/src/lib/notion/getNotionAssetUrls.ts
@@ -31,7 +31,8 @@ export default async function getNotionAsset(
})
if (assetRes.ok) {
- return assetRes.json()
+ const data = await assetRes.json() as { signedUrls: string[] }
+ return data
} else {
console.log('bad request', assetRes.status)
res.json({ status: 'error', message: 'failed to load Notion asset' })
diff --git a/src/lib/notion/getNotionUsers.ts b/src/lib/notion/getNotionUsers.ts
index 3948a35a..a64f11f1 100644
--- a/src/lib/notion/getNotionUsers.ts
+++ b/src/lib/notion/getNotionUsers.ts
@@ -1,24 +1,34 @@
import rpc from './rpc'
+interface GetRecordValuesResponse {
+ results?: Array<{
+ value?: {
+ id: string
+ given_name?: string
+ family_name?: string
+ }
+ }>
+}
+
export default async function getNotionUsers(ids: string[]) {
- const { results = [] } = await rpc('getRecordValues', {
+ const { results = [] } = (await rpc('getRecordValues', {
requests: ids.map((id: string) => ({
id,
table: 'notion_user',
})),
- })
+ })) as GetRecordValuesResponse
const users: any = {}
for (const result of results) {
const { value } = result || { value: {} }
- const { given_name, family_name } = value
+ const { id = '', given_name = '', family_name = '' } = value as { id: string; given_name?: string; family_name?: string }
let full_name = given_name || ''
if (family_name) {
full_name = `${full_name} ${family_name}`
}
- users[value.id] = { full_name }
+ users[id] = { full_name }
}
return { users }
diff --git a/src/lib/notion/getPageData.ts b/src/lib/notion/getPageData.ts
index 292cc59c..5e339379 100644
--- a/src/lib/notion/getPageData.ts
+++ b/src/lib/notion/getPageData.ts
@@ -1,14 +1,31 @@
import rpc, { values } from './rpc'
+declare module './rpc' {
+ export default function rpc(fnName: string, body: any): Promise
+}
+
+interface RecordMap {
+ block: {
+ [key: string]: any
+ }
+}
+
+interface PageChunkData {
+ recordMap: RecordMap
+ cursor: {
+ stack: any[]
+ }
+}
+
export default async function getPageData(pageId: string) {
// a reasonable size limit for the largest blog post (1MB),
// as one chunk is about 10KB
const maximumChunckNumer = 100
try {
- var chunkNumber = 0
- var data = await loadPageChunk({ pageId, chunkNumber })
- var blocks = data.recordMap.block
+ let chunkNumber = 0
+ let data: PageChunkData = await loadPageChunk({ pageId, chunkNumber })
+ let blocks = data.recordMap.block
while (data.cursor.stack.length !== 0 && chunkNumber < maximumChunckNumer) {
chunkNumber = chunkNumber + 1
@@ -16,7 +33,7 @@ export default async function getPageData(pageId: string) {
blocks = Object.assign(blocks, data.recordMap.block)
}
const blockArray = values(blocks)
- if (blockArray[0] && blockArray[0].value.content) {
+ if (blockArray[0]?.value?.content) {
// remove table blocks
blockArray.splice(0, 3)
}
@@ -33,7 +50,7 @@ export function loadPageChunk({
cursor = { stack: [] },
chunkNumber = 0,
verticalColumns = false,
-}: any) {
+}: any): Promise {
return rpc('loadPageChunk', {
pageId,
limit,
diff --git a/src/lib/notion/getTableData.ts b/src/lib/notion/getTableData.ts
index 46b309f5..48ae94be 100644
--- a/src/lib/notion/getTableData.ts
+++ b/src/lib/notion/getTableData.ts
@@ -29,7 +29,7 @@ export default async function loadTable(collectionBlock: any, isPosts = false) {
row.id = entry.value.id
}
- schemaKeys.forEach(key => {
+ schemaKeys.forEach((key) => {
// might be undefined
let val = props[key] && props[key][0][0]
diff --git a/src/lib/notion/rpc.ts b/src/lib/notion/rpc.ts
index 8d6b3788..fe3e6b58 100644
--- a/src/lib/notion/rpc.ts
+++ b/src/lib/notion/rpc.ts
@@ -42,7 +42,7 @@ export function getBodyOrNull(res: Response) {
export function values(obj: any) {
const vals: any = []
- Object.keys(obj).forEach(key => {
+ Object.keys(obj).forEach((key) => {
vals.push(obj[key])
})
return vals
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index e27ab7f9..4c80453d 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -1,11 +1,13 @@
import '../styles/global.css'
import 'katex/dist/katex.css'
import Footer from '../components/footer'
+import Features from '../components/spotifyPlayer'
export default function MyApp({ Component, pageProps }) {
return (
<>
+
>
)
diff --git a/src/pages/blog/[slug].tsx b/src/pages/blog/[slug].tsx
index 3ed35917..9f650cd8 100644
--- a/src/pages/blog/[slug].tsx
+++ b/src/pages/blog/[slug].tsx
@@ -34,8 +34,8 @@ export async function getStaticProps({ params: { slug }, preview }) {
const postData = await getPageData(post.id)
post.content = postData.blocks
- for (let i = 0; i < postData.blocks.length; i++) {
- const { value } = postData.blocks[i]
+ for (const block of postData.blocks) {
+ const { value } = block
const { type, properties } = value
if (type == 'tweet') {
const src = properties.source[0][0]
@@ -47,7 +47,7 @@ export async function getStaticProps({ params: { slug }, preview }) {
const res = await fetch(
`https://api.twitter.com/1/statuses/oembed.json?id=${tweetId}`
)
- const json = await res.json()
+ const json = (await res.json()) as { html: string }
properties.html = json.html.split('