@@ -16,15 +16,16 @@ import {
1616import { globSync } from 'tinyglobby'
1717import { isProduction } from '../config/env'
1818import { BLUESKY_API } from '../shared/utils/constants'
19- import { mkdir } from 'node:fs/promises'
19+ import { mkdir , writeFile } from 'node:fs/promises'
2020import { existsSync } from 'node:fs'
21+ import crypto from 'node:crypto'
2122
2223/**
2324 * Fetches Bluesky avatars for a set of authors at build time.
2425 * Returns a map of handle → avatar URL.
2526 */
2627async function fetchBlueskyAvatars (
27- _imagesDir : string ,
28+ imagesDir : string ,
2829 handles : string [ ] ,
2930) : Promise < Map < string , string > > {
3031 const avatarMap = new Map < string , string > ( )
@@ -48,7 +49,17 @@ async function fetchBlueskyAvatars(
4849 const data = ( await response . json ( ) ) as { profiles : Array < { handle : string ; avatar ?: string } > }
4950
5051 for ( const profile of data . profiles ) {
51- if ( profile . avatar ) avatarMap . set ( profile . handle , profile . avatar )
52+ if ( profile . avatar ) {
53+ const hash = crypto . createHash ( 'sha256' ) . update ( profile . avatar ) . digest ( 'hex' )
54+ const dest = join ( imagesDir , `${ hash } .png` )
55+
56+ if ( ! existsSync ( dest ) ) {
57+ const res = await fetch ( `${ profile . avatar } @png` )
58+ await writeFile ( join ( imagesDir , `${ hash } .png` ) , res . body ! )
59+ }
60+
61+ avatarMap . set ( profile . handle , `/blog/avatar/${ hash } .png` )
62+ }
5263 }
5364 } catch ( error ) {
5465 console . warn ( `[blog] Failed to fetch Bluesky avatars:` , error )
@@ -74,7 +85,7 @@ function resolveAuthors(authors: Author[], avatarMap: Map<string, string>): Reso
7485 * Resolves Bluesky avatars at build time.
7586 */
7687async function loadBlogPosts ( blogDir : string , imagesDir : string ) : Promise < BlogPostFrontmatter [ ] > {
77- const files : string [ ] = globSync ( join ( blogDir , '*.md' ) )
88+ const files : string [ ] = globSync ( join ( blogDir , '*.md' ) . replace ( / \\ / g , '/' ) )
7889
7990 // First pass: extract raw frontmatter and collect all Bluesky handles
8091 const rawPosts : Array < { frontmatter : Record < string , unknown > } > = [ ]
0 commit comments