@@ -34,7 +34,7 @@ import { catchError, map, share, switchMap, tap } from "rxjs/operators";
3434export async function getFavicon (
3535 req : Request ,
3636 res : Response ,
37- services : Services
37+ services : Services ,
3838) {
3939 const url = new URL ( req . url , `http://${ req . headers . host } ` ) ;
4040 const { redis } = services ;
@@ -58,30 +58,30 @@ export async function getFavicon(
5858 size,
5959 dpr : dpr || 1 ,
6060 theme,
61- } ) )
61+ } ) ) ,
6262 ) ;
6363
6464 const cachedImage$ = params$ . pipe (
6565 switchMap ( ( { url, size, dpr, theme } ) => {
6666 const key = { url, size, dpr, theme } ;
6767 // Skip cache in development if Redis is not available
68- if ( process . env . NODE_ENV === ' development' && ! redis ) {
68+ if ( process . env . NODE_ENV === " development" && ! redis ) {
6969 return of ( null ) ;
7070 }
7171 return from ( getCachedImage ( key , redis ) ) ;
7272 } ) ,
73- share ( )
73+ share ( ) ,
7474 ) ;
7575
7676 const [ cached$ , uncached$ ] = partition (
7777 cachedImage$ ,
78- ( cachedImage ) : cachedImage is IconMetadata => cachedImage != null
78+ ( cachedImage ) : cachedImage is IconMetadata => cachedImage != null ,
7979 ) ;
8080
8181 const response$ = merge (
8282 combineLatest ( [ cached$ , params$ ] ) . pipe (
8383 switchMap ( ( [ cachedImage , params ] ) =>
84- cachedFaviconResponse$ ( params , cachedImage , services , defer )
84+ cachedFaviconResponse$ ( params , cachedImage , services , defer ) ,
8585 ) ,
8686 tap ( ( { expiry, objectKey } ) => {
8787 const faviconHost = process . env . RAYCAST_FAVICON_HOST ;
@@ -91,35 +91,27 @@ export async function getFavicon(
9191 res . set ( responseHeaders ( { expiry } ) ) ;
9292 res . redirect ( `https://${ faviconHost } /${ objectKey } ` ) ;
9393 }
94- } )
94+ } ) ,
9595 ) ,
9696 combineLatest ( [ uncached$ , params$ ] ) . pipe (
9797 switchMap ( ( [ _ , params ] ) =>
9898 combineLatest ( [
9999 of ( params ) ,
100100 uncachedFaviconResponse$ ( params , services , defer ) ,
101- ] )
101+ ] ) ,
102102 ) ,
103103 tap ( async ( [ { size, dpr, url, theme } , result ] ) => {
104104 if ( result . found ) {
105- let { blob, expiry } = result ;
106-
107- // Apply theme-based processing if needed
108- try {
109- blob = await processImageForTheme ( blob , theme , url ) ;
110- } catch ( error ) {
111- console . error ( 'Error processing image for theme:' , error ) ;
112- }
113-
105+ const { blob, expiry } = result ;
114106 res . type ( blob . type ) ;
115107 const buffer = await blob . arrayBuffer ( ) ;
116108 res . set ( responseHeaders ( { size : blob . size , expiry } ) ) ;
117109 res . send ( Buffer . from ( buffer ) ) ;
118110 } else {
119111 res . status ( 404 ) . send ( "Not found" ) ;
120112 }
121- } )
122- )
113+ } ) ,
114+ ) ,
123115 ) ;
124116
125117 try {
@@ -136,10 +128,15 @@ export async function getFavicon(
136128}
137129
138130function cachedFaviconResponse$ (
139- params : { url : URL ; size : SizeParam ; dpr : DevicePixelRatioParam ; theme ?: ThemeParam } ,
131+ params : {
132+ url : URL ;
133+ size : SizeParam ;
134+ dpr : DevicePixelRatioParam ;
135+ theme ?: ThemeParam ;
136+ } ,
140137 icon : IconMetadata ,
141138 services : Services ,
142- defer : ( work : Promise < any > ) => void
139+ defer : ( work : Promise < any > ) => void ,
143140) {
144141 const { redis } = services ;
145142 return combineLatest ( [ of ( params ) , of ( icon ) ] ) . pipe (
@@ -151,16 +148,16 @@ function cachedFaviconResponse$(
151148 {
152149 lastAccess : new Date ( ) ,
153150 } ,
154- redis
155- )
151+ redis ,
152+ ) ,
156153 ) ;
157154 }
158155 } ) ,
159156 switchMap ( ( [ _ , cachedImage ] ) => {
160157 const { objectKey } = cachedImage ;
161158 return combineLatest ( [ of ( cachedImage ) , of ( objectKey ) ] ) ;
162159 } ) ,
163- map ( ( [ { expiry } , objectKey ] ) => ( { expiry, objectKey } ) )
160+ map ( ( [ { expiry } , objectKey ] ) => ( { expiry, objectKey } ) ) ,
164161 ) ;
165162}
166163
@@ -172,59 +169,74 @@ function uncachedFaviconResponse$(
172169 theme ?: ThemeParam ;
173170 } ,
174171 services : Services ,
175- defer : ( work : Promise < any > ) => void
172+ defer : ( work : Promise < any > ) => void ,
176173) : Observable < { found : true ; blob : Blob ; expiry : Date } | { found : false } > {
177174 const loadResult$ = of ( params ) . pipe (
178175 switchMap ( ( { url, size, dpr, theme } ) =>
179176 loadIconsForValidatedURL$ ( url , size , dpr , theme ) ,
180177 ) ,
181- share ( )
178+ share ( ) ,
182179 ) ;
183180
184181 const [ foundIcon$ , notFoundIcon$ ] = partition (
185182 loadResult$ ,
186183 ( loadResult ) : loadResult is { icon : Icon ; foundIcons : IconSource [ ] } =>
187- loadResult . icon != null
184+ loadResult . icon != null ,
188185 ) ;
189186
190187 return merge (
191188 combineLatest ( [ foundIcon$ , of ( params ) ] ) . pipe (
192- switchMap ( ( [ { icon, foundIcons } , { url, size, dpr, theme } ] ) => {
189+ switchMap ( async ( [ { icon, foundIcons } , { url, size, dpr, theme } ] ) => {
193190 const { image } = icon ;
194- const { blob, expiry } = image ;
191+ let { blob, expiry } = image ;
192+
193+ try {
194+ blob = await processImageForTheme ( blob , theme , url ) ;
195+ } catch ( error ) {
196+ console . error (
197+ "Error processing image for theme before caching:" ,
198+ error ,
199+ ) ;
200+ }
201+
202+ const processedIcon = {
203+ ...icon ,
204+ image : { ...image , blob } ,
205+ } ;
206+
195207 const key = { url, size, dpr, theme } ;
196- defer ( cacheFavicon ( key , icon , services ) ) ;
197- return of ( { found : true , blob, expiry } as const ) ;
198- } )
208+ defer ( cacheFavicon ( key , processedIcon , services ) ) ;
209+ return { found : true , blob, expiry } as const ;
210+ } ) ,
199211 ) ,
200212 combineLatest ( [ notFoundIcon$ , of ( params ) ] ) . pipe (
201213 switchMap ( ( [ _ , params ] ) => {
202214 const { url, size, dpr } = params ;
203215 return of ( { found : false } as const ) ;
204- } )
205- )
216+ } ) ,
217+ ) ,
206218 ) ;
207219}
208220
209221function loadIconsForValidatedURL$ (
210222 url : URL ,
211223 size : SizeParam ,
212224 dpr : DevicePixelRatioParam ,
213- theme ?: ThemeParam
225+ theme ?: ThemeParam ,
214226) : Observable < IconLoadResult > {
215227 const results$ = of ( { url, size, theme } ) . pipe (
216228 switchMap ( ( { url, size, theme } ) =>
217229 combineLatest ( [
218230 loadFaviconIco$ ( url ) ,
219231 loadFaviconFromHTMLPage$ ( url , size , dpr , theme ) ,
220- ] )
221- )
232+ ] ) ,
233+ ) ,
222234 ) ;
223235
224236 return combineLatest ( [ of ( url ) , of ( theme ) , results$ ] ) . pipe (
225237 map ( ( [ url , theme , [ favicon , page ] ] ) =>
226- bestResult ( url , { favicon : favicon , page : page } , theme )
227- )
238+ bestResult ( url , { favicon : favicon , page : page } , theme ) ,
239+ ) ,
228240 ) ;
229241}
230242
@@ -240,7 +252,7 @@ export function getURLParam$(url: URL) {
240252 throw new APIError ( 400 , "missing_url" , "Missing 'url' query parameter" ) ;
241253 }
242254 return urlParam ;
243- } )
255+ } ) ,
244256 ) ;
245257}
246258
@@ -262,9 +274,9 @@ export function getSizeParam$(url: URL) {
262274 throw new APIError (
263275 400 ,
264276 "invalid_size" ,
265- `Invalid 'size' query parameter. Valid sizes are ${ allSizes . join ( ", " ) } `
277+ `Invalid 'size' query parameter. Valid sizes are ${ allSizes . join ( ", " ) } ` ,
266278 ) ;
267- } )
279+ } ) ,
268280 ) ;
269281}
270282
@@ -282,7 +294,7 @@ export function getDevicePixelRatioParam$(url: URL) {
282294 throw new APIError (
283295 400 ,
284296 "invalid_dpr" ,
285- `Invalid 'dpr' query parameter. This should be a number`
297+ `Invalid 'dpr' query parameter. This should be a number` ,
286298 ) ;
287299 }
288300
@@ -292,7 +304,7 @@ export function getDevicePixelRatioParam$(url: URL) {
292304 } ) ,
293305 catchError ( ( ) => {
294306 throw makeInternalError ( ) ;
295- } )
307+ } ) ,
296308 ) ;
297309}
298310
@@ -311,9 +323,9 @@ export function getThemeParam$(url: URL) {
311323 throw new APIError (
312324 400 ,
313325 "invalid_theme" ,
314- "Invalid 'theme' query parameter. Valid values are 'light' or 'dark'"
326+ "Invalid 'theme' query parameter. Valid values are 'light' or 'dark'" ,
315327 ) ;
316- } )
328+ } ) ,
317329 ) ;
318330}
319331
@@ -331,6 +343,6 @@ export function parsedAndValidatedURL$(urlString: string) {
331343 map ( validatedURL ) ,
332344 catchError ( ( ) => {
333345 throw new APIError ( 400 , "invalid_url" , "Invalid 'url' query parameter" ) ;
334- } )
346+ } ) ,
335347 ) ;
336348}
0 commit comments