11require ( "dotenv" ) . config ( ) ;
2+ const path = require ( "path" ) ;
23const express = require ( "express" ) ;
34const cors = require ( "cors" ) ;
45const helmet = require ( "helmet" ) ;
@@ -16,6 +17,7 @@ const getConfig = require("./src/udf/getConfig");
1617const getSymbols = require ( "./src/udf/getSymbols" ) ;
1718const getHistory = require ( "./src/udf/getHistory" ) ;
1819const { getQuote, getFiatCurrencyLimits } = require ( "./src/api/fiatOnRamp" ) ;
20+ const { getTokenIcon } = require ( "./src/api/getTokenIcon" ) ;
1921
2022const app = express ( ) ;
2123
@@ -24,6 +26,7 @@ app.use(helmet());
2426app . use ( morgan ( "dev" ) ) ;
2527app . use ( compression ( ) ) ;
2628app . use ( express . json ( ) ) ;
29+ app . use ( "/public" , express . static ( path . join ( __dirname , "public" ) ) ) ;
2730
2831const asyncHandler = ( fn ) => async ( req , res , next ) => {
2932 try {
@@ -49,6 +52,48 @@ app.get("/api/transactions", asyncHandler(getTransactions));
4952app . post ( "/api/fiat-on-ramp/quote" , asyncHandler ( getQuote ) ) ;
5053app . get ( "/api/fiat-on-ramp/currencies" , asyncHandler ( getFiatCurrencyLimits ) ) ;
5154
55+ app . get ( "/api/token-icon" , async ( req , res , next ) => {
56+ try {
57+ const result = await getTokenIcon ( req . query ) ;
58+
59+ if ( ! result . success ) {
60+ return res . status ( 404 ) . json ( { error : "Icon not found" } ) ;
61+ }
62+
63+ const ext = path . extname ( result . iconPath ) . toLowerCase ( ) ;
64+ const mimeTypes = {
65+ ".png" : "image/png" ,
66+ ".jpg" : "image/jpeg" ,
67+ ".jpeg" : "image/jpeg" ,
68+ ".svg" : "image/svg+xml" ,
69+ ".webp" : "image/webp" ,
70+ ".gif" : "image/gif" ,
71+ } ;
72+
73+ const mimeType = mimeTypes [ ext ] || "image/png" ;
74+ const fileName = path . basename ( result . iconPath ) ;
75+ const tokenName = result . token . includes ( "." )
76+ ? result . token . split ( "." ) . pop ( )
77+ : result . token ;
78+
79+ res . setHeader ( "Content-Type" , mimeType ) ;
80+ res . setHeader ( "Cache-Control" , "public, max-age=3600" ) ;
81+ res . setHeader (
82+ "Content-Disposition" ,
83+ `inline; filename="${ tokenName } -icon${ ext } "`
84+ ) ;
85+
86+ if ( result . fallback ) {
87+ res . setHeader ( "X-Fallback" , "true" ) ;
88+ }
89+
90+ res . sendFile ( result . iconPath ) ;
91+ } catch ( error ) {
92+ console . error ( "Error serving token icon:" , error ) ;
93+ res . status ( 500 ) . json ( { error : error . message } ) ;
94+ }
95+ } ) ;
96+
5297app . get ( "/health" , async ( req , res ) => {
5398 try {
5499 const { query } = require ( "./clients/pg" ) ;
0 commit comments