Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add svg route #3424

Merged
merged 5 commits into from
Dec 1, 2024
Merged

add svg route #3424

merged 5 commits into from
Dec 1, 2024

Conversation

trajan0x
Copy link
Contributor

@trajan0x trajan0x commented Dec 1, 2024

Description

Adds an svg route

Summary by CodeRabbit

  • New Features
    • Introduced new routes for fetching chain icons and token icons based on chainId and address.
    • Added support for caching images for improved performance.
  • Dependencies
    • Added new dependencies: @synapsecns/synapse-constants and cross-fetch to enhance functionality.

Copy link
Contributor

coderabbitai bot commented Dec 1, 2024

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The pull request introduces new dependencies to the package.json of the @synapsecns/rest-api project and adds new Express routers for handling HTTP GET requests for chain and token icons based on chainId and address. Two routes are registered to serve these icons, with error handling implemented for missing chains, tokens, and fetch failures.

Changes

File Change Summary
packages/rest-api/package.json - Added dependency: @synapsecns/synapse-constants (^1.8.3)
- Added dependency: cross-fetch (^4.0.0)
packages/rest-api/src/routes/chainIconRoute.ts - Introduced new Express router for handling /:chainId.svg GET requests.
- Implemented error handling for missing chains and fetch failures.
- Exported the new router.
packages/rest-api/src/routes/index.ts - Registered new route /chainIcon using the chainIconRoute.
- Registered new route /tokenIcon using the addressIconRoute.
packages/rest-api/src/routes/addressIconRoute.ts - Introduced new Express router for handling /:chainId/:address.svg GET requests.
- Implemented error handling for missing tokens and fetch failures.
- Exported the new router.

Possibly related PRs

Suggested reviewers

  • Defi-Moses
  • bigboydiamonds

🐰 In the code we hop and play,
New routes and dependencies lead the way.
Fetching icons with great delight,
Chain by chain, we’ll take flight!
Errors caught, we’ll never stray,
Hopping forward, come what may! 🐇


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (1)
packages/rest-api/src/routes/chainIconRoute.ts (1)

1-5: Consider using built-in fetch API

The implementation looks good, but consider using the built-in fetch API available in Node.js 18+ instead of the node-fetch package to reduce dependencies.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 62edd40 and 6dd7418.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (3)
  • packages/rest-api/package.json (2 hunks)
  • packages/rest-api/src/routes/chainIconRoute.ts (1 hunks)
  • packages/rest-api/src/routes/index.ts (2 hunks)
🔇 Additional comments (2)
packages/rest-api/package.json (1)

26-26: Verify version compatibility with rest-api

Let's ensure the version of @synapsecns/synapse-constants (^1.8.3) is compatible with the rest-api package version (1.8.9).

✅ Verification successful

Version compatibility verified between rest-api and synapse-constants

The version of @synapsecns/synapse-constants (^1.8.3) is perfectly aligned with the current version (1.8.3) of the package. Additionally, other packages in the monorepo (@synapsecns/explorer-ui and @synapsecns/bridge-docs) are using the same version range, indicating consistent version management across the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check version alignment between packages

# Check if synapse-constants is used in other packages
fd -t f package.json -x jq -r 'select(.dependencies."@synapsecns/synapse-constants" != null) | "\(.name): \(.dependencies."@synapsecns/synapse-constants")"'

# Check the latest version of synapse-constants
if [ -f "packages/synapse-constants/package.json" ]; then
  jq -r '.version' packages/synapse-constants/package.json
fi

Length of output: 367

packages/rest-api/src/routes/index.ts (1)

14-14: Verify route naming convention

The implementation looks good and follows the existing pattern. However, let's verify if the route name chainIcon follows the project's naming convention, as other routes use camelCase for compound words (e.g., tokenList, bridgeTxStatus).

Also applies to: 29-29

✅ Verification successful

Route naming follows existing convention

The route name chainIcon follows the established camelCase naming convention in the codebase, consistent with other compound word routes like tokenList, bridgeTxStatus, bridgeTxInfo, destinationTokens, etc.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check route naming patterns in the codebase
rg "router\.use\('/.+'" packages/rest-api/src/routes/

Length of output: 966

@@ -31,6 +32,7 @@
"http-proxy-middleware": "^3.0.3",
"jest": "^29.7.0",
"lodash": "^4.17.21",
"node-fetch": "^3.3.2",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider removing node-fetch dependency

Since the project requires Node.js >=18.17.0 (which has built-in fetch API), we could remove the node-fetch dependency and use the native fetch instead. This would reduce the package size and simplify dependencies.

-    "node-fetch": "^3.3.2",

Comment on lines +37 to +42
} catch (error) {
console.error('Error fetching chain icon:', error)
res.status(500).json({ error: 'Failed to fetch chain icon' })
}
return
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling and logging

The error handling could be enhanced:

  1. The return statement after try-catch is unnecessary
  2. Error logging should be structured and sanitized
  3. Different error types should have different status codes

Apply these improvements:

-  } catch (error) {
-    console.error('Error fetching chain icon:', error)
-    res.status(500).json({ error: 'Failed to fetch chain icon' })
-  }
-  return
+  } catch (error) {
+    // Sanitize error message
+    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
+    
+    // Log structured error
+    console.error({
+      error: 'Failed to fetch chain icon',
+      chainId,
+      message: errorMessage,
+      timestamp: new Date().toISOString()
+    })
+    
+    // Return appropriate status code
+    if (errorMessage.includes('Invalid URL') || errorMessage.includes('Invalid content type')) {
+      res.status(400).json({ error: 'Invalid chain icon configuration' })
+    } else if (error instanceof Error && error.name === 'AbortError') {
+      res.status(504).json({ error: 'Chain icon fetch timeout' })
+    } else {
+      res.status(500).json({ error: 'Failed to fetch chain icon' })
+    }
+  }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 7 to 19
router.get('/:chainId.svg', async (req, res) => {
const chainId = parseInt(req.params.chainId, 10)

// Find the chain with matching ID
const chain = Object.values(CHAINS).find(
(c): c is Chain =>
typeof c === 'object' && c !== null && 'id' in c && c.id === chainId,
)

if (!chain || !chain.chainImg) {
res.status(404).json({ error: 'Chain icon not found' })
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance input validation and type safety

While the chain validation is good, consider these improvements:

  1. Add input validation for chainId format before parsing
  2. Replace the type assertion with a proper type guard function

Consider this implementation:

 router.get('/:chainId.svg', async (req, res) => {
+  if (!/^\d+$/.test(req.params.chainId)) {
+    res.status(400).json({ error: 'Invalid chain ID format' })
+    return
+  }
   const chainId = parseInt(req.params.chainId, 10)
 
-  // Find the chain with matching ID
-  const chain = Object.values(CHAINS).find(
-    (c): c is Chain =>
-      typeof c === 'object' && c !== null && 'id' in c && c.id === chainId,
-  )
+  const isChain = (c: unknown): c is Chain =>
+    typeof c === 'object' && c !== null && 'id' in c && 'chainImg' in c
+
+  const chain = Object.values(CHAINS).find(isChain)

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 21 to 37
try {
// Fetch the image from the URL
const response = await fetch(chain.chainImg)
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.statusText}`)
}

const buffer = await response.buffer()

// Set cache headers (cache for 1 week)
res.set({
'Cache-Control': 'public, max-age=604800',
'Content-Type': response.headers.get('content-type') || 'image/svg+xml',
})

res.send(buffer)
} catch (error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Address security concerns in image fetching

Several security issues need to be addressed:

  1. No validation of the image URL
  2. No timeout on fetch requests
  3. No size limits on responses
  4. No validation of content type

Apply these security improvements:

   try {
+    // Validate URL
+    const imageUrl = new URL(chain.chainImg)
+    if (!['http:', 'https:'].includes(imageUrl.protocol)) {
+      throw new Error('Invalid URL protocol')
+    }
+
     // Fetch the image from the URL
-    const response = await fetch(chain.chainImg)
+    const controller = new AbortController()
+    const timeout = setTimeout(() => controller.abort(), 5000)
+    
+    const response = await fetch(imageUrl, {
+      signal: controller.signal,
+      headers: {
+        'Accept': 'image/svg+xml'
+      }
+    })
+    clearTimeout(timeout)
+
     if (!response.ok) {
       throw new Error(`Failed to fetch image: ${response.statusText}`)
     }
 
+    const contentType = response.headers.get('content-type')
+    if (!contentType?.startsWith('image/svg+xml')) {
+      throw new Error('Invalid content type')
+    }
+
+    // Limit response size to 1MB
+    const contentLength = parseInt(response.headers.get('content-length') ?? '0', 10)
+    if (contentLength > 1024 * 1024) {
+      throw new Error('Image too large')
+    }
+
     const buffer = await response.buffer()
 
     // Set cache headers (cache for 1 week)
     res.set({
       'Cache-Control': 'public, max-age=604800',
-      'Content-Type': response.headers.get('content-type') || 'image/svg+xml',
+      'Content-Type': 'image/svg+xml',
     })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
// Fetch the image from the URL
const response = await fetch(chain.chainImg)
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.statusText}`)
}
const buffer = await response.buffer()
// Set cache headers (cache for 1 week)
res.set({
'Cache-Control': 'public, max-age=604800',
'Content-Type': response.headers.get('content-type') || 'image/svg+xml',
})
res.send(buffer)
} catch (error) {
try {
// Validate URL
const imageUrl = new URL(chain.chainImg)
if (!['http:', 'https:'].includes(imageUrl.protocol)) {
throw new Error('Invalid URL protocol')
}
// Fetch the image from the URL
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), 5000)
const response = await fetch(imageUrl, {
signal: controller.signal,
headers: {
'Accept': 'image/svg+xml'
}
})
clearTimeout(timeout)
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.statusText}`)
}
const contentType = response.headers.get('content-type')
if (!contentType?.startsWith('image/svg+xml')) {
throw new Error('Invalid content type')
}
// Limit response size to 1MB
const contentLength = parseInt(response.headers.get('content-length') ?? '0', 10)
if (contentLength > 1024 * 1024) {
throw new Error('Image too large')
}
const buffer = await response.buffer()
// Set cache headers (cache for 1 week)
res.set({
'Cache-Control': 'public, max-age=604800',
'Content-Type': 'image/svg+xml',
})
res.send(buffer)
} catch (error) {

Copy link

codecov bot commented Dec 1, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Please upload report for BASE (master@62edd40). Learn more about missing BASE report.
Report is 1 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master       #3424   +/-   ##
============================================
  Coverage          ?   90.44834%           
============================================
  Files             ?          54           
  Lines             ?        1026           
  Branches          ?          82           
============================================
  Hits              ?         928           
  Misses            ?          95           
  Partials          ?           3           
Flag Coverage Δ
packages 90.44834% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

cloudflare-workers-and-pages bot commented Dec 1, 2024

Deploying sanguine-fe with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4883033
Status: ✅  Deploy successful!
Preview URL: https://7f2ae878.sanguine-fe.pages.dev
Branch Preview URL: https://fix-router.sanguine-fe.pages.dev

View logs

@github-actions github-actions bot added size/s and removed size/m labels Dec 1, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (3)
packages/rest-api/src/routes/addressIconRoute.ts (3)

1-5: Consider adding Express type imports for better type safety

Import Request and Response types from express to improve type safety in the route handler.

-import express from 'express'
+import express, { Request, Response } from 'express'

24-28: Improve error logging structure

The current logging could be more structured and informative.

-    console.log('Token not found or no icon:', { token })
+    console.log('Token icon not found', {
+      chainId,
+      address,
+      tokenFound: !!token,
+      hasIcon: token?.icon !== undefined
+    })

1-53: Consider implementing a CDN and caching strategy

To improve performance and reliability:

  1. Consider using a CDN to serve cached icons
  2. Implement a local cache to reduce external requests
  3. Add fallback icons for failed requests

This would reduce latency and dependencies on external services. Would you like assistance in implementing these improvements?

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6dd7418 and 107f8df.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (3)
  • packages/rest-api/src/routes/addressIconRoute.ts (1 hunks)
  • packages/rest-api/src/routes/chainIconRoute.ts (1 hunks)
  • packages/rest-api/src/routes/index.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/rest-api/src/routes/index.ts
  • packages/rest-api/src/routes/chainIconRoute.ts

Comment on lines +7 to +9
router.get('/:chainId/:address.svg', async (req, res) => {
const chainId = parseInt(req.params.chainId, 10)
const address = req.params.address.toLowerCase()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add input validation for chainId and address parameters

The current implementation lacks validation for:

  1. chainId (could be NaN)
  2. address format (should be a valid hex string)

This could lead to unnecessary processing of invalid requests.

 router.get('/:chainId/:address.svg', async (req, res) => {
   const chainId = parseInt(req.params.chainId, 10)
+  if (isNaN(chainId)) {
+    res.status(400).json({ error: 'Invalid chainId' })
+    return
+  }
   const address = req.params.address.toLowerCase()
+  if (!/^0x[a-f0-9]{40}$/i.test(address)) {
+    res.status(400).json({ error: 'Invalid address format' })
+    return
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
router.get('/:chainId/:address.svg', async (req, res) => {
const chainId = parseInt(req.params.chainId, 10)
const address = req.params.address.toLowerCase()
router.get('/:chainId/:address.svg', async (req, res) => {
const chainId = parseInt(req.params.chainId, 10)
if (isNaN(chainId)) {
res.status(400).json({ error: 'Invalid chainId' })
return
}
const address = req.params.address.toLowerCase()
if (!/^0x[a-f0-9]{40}$/i.test(address)) {
res.status(400).json({ error: 'Invalid address format' })
return
}

Comment on lines +11 to +22
// Find the token with matching address on the specified chain
const token = Object.values(BRIDGABLE_TOKENS[chainId] || []).find(
(t): t is Token =>
typeof t === 'object' &&
t !== null &&
'addresses' in t &&
Object.entries(t.addresses).some(([chain, addr]) => {
const matches =
parseInt(chain, 10) === chainId && addr.toLowerCase() === address
return matches
})
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Extract token lookup logic and optimize performance

The token lookup logic is complex and could benefit from:

  1. Extraction into a separate function for better maintainability
  2. Direct object lookup instead of array operations
+const findToken = (chainId: number, address: string): Token | undefined => {
+  const chainTokens = BRIDGABLE_TOKENS[chainId]
+  if (!chainTokens) return undefined
+  
+  return Object.values(chainTokens).find(
+    (t): t is Token =>
+      typeof t === 'object' &&
+      t !== null &&
+      'addresses' in t &&
+      Object.entries(t.addresses).some(([chain, addr]) =>
+        parseInt(chain, 10) === chainId && addr.toLowerCase() === address
+      )
+  )
+}
+
 router.get('/:chainId/:address.svg', async (req, res) => {
   const chainId = parseInt(req.params.chainId, 10)
   const address = req.params.address.toLowerCase()

-  const token = Object.values(BRIDGABLE_TOKENS[chainId] || []).find(
-    (t): t is Token =>
-      typeof t === 'object' &&
-      t !== null &&
-      'addresses' in t &&
-      Object.entries(t.addresses).some(([chain, addr]) => {
-        const matches =
-          parseInt(chain, 10) === chainId && addr.toLowerCase() === address
-        return matches
-      })
-  )
+  const token = findToken(chainId, address)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Find the token with matching address on the specified chain
const token = Object.values(BRIDGABLE_TOKENS[chainId] || []).find(
(t): t is Token =>
typeof t === 'object' &&
t !== null &&
'addresses' in t &&
Object.entries(t.addresses).some(([chain, addr]) => {
const matches =
parseInt(chain, 10) === chainId && addr.toLowerCase() === address
return matches
})
)
const findToken = (chainId: number, address: string): Token | undefined => {
const chainTokens = BRIDGABLE_TOKENS[chainId]
if (!chainTokens) return undefined
return Object.values(chainTokens).find(
(t): t is Token =>
typeof t === 'object' &&
t !== null &&
'addresses' in t &&
Object.entries(t.addresses).some(([chain, addr]) =>
parseInt(chain, 10) === chainId && addr.toLowerCase() === address
)
)
}
// Find the token with matching address on the specified chain
const token = findToken(chainId, address)

Comment on lines +30 to +51
try {
// Fetch the image from the URL
const response = await fetch(token.icon)
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.statusText}`)
}

const buffer = await response.arrayBuffer()

// Set cache headers (cache for 1 week)
res.set({
'Cache-Control': 'public, max-age=604800',
'Content-Type': response.headers.get('content-type') || 'image/svg+xml',
})

res.send(Buffer.from(buffer))
} catch (error) {
console.error('Error fetching token icon:', error)
res.status(500).json({ error: 'Failed to fetch token icon' })
}
return
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add timeout and security measures for external requests

The external fetch operation needs additional safety measures:

  1. Request timeout
  2. URL validation
  3. Response size limits
+const isValidIconUrl = (url: string): boolean => {
+  try {
+    const parsed = new URL(url)
+    return ['http:', 'https:'].includes(parsed.protocol)
+  } catch {
+    return false
+  }
+}

 try {
+    if (!isValidIconUrl(token.icon)) {
+      throw new Error('Invalid icon URL')
+    }
+
+    const controller = new AbortController()
+    const timeout = setTimeout(() => controller.abort(), 5000)
+
-    const response = await fetch(token.icon)
+    const response = await fetch(token.icon, {
+      signal: controller.signal,
+      headers: {
+        'Accept': 'image/svg+xml,image/*'
+      }
+    })
+    clearTimeout(timeout)

     if (!response.ok) {
       throw new Error(`Failed to fetch image: ${response.statusText}`)
     }

+    const contentLength = response.headers.get('content-length')
+    if (contentLength && parseInt(contentLength, 10) > 1024 * 1024) {
+      throw new Error('Icon file too large')
+    }

     const buffer = await response.arrayBuffer()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
// Fetch the image from the URL
const response = await fetch(token.icon)
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.statusText}`)
}
const buffer = await response.arrayBuffer()
// Set cache headers (cache for 1 week)
res.set({
'Cache-Control': 'public, max-age=604800',
'Content-Type': response.headers.get('content-type') || 'image/svg+xml',
})
res.send(Buffer.from(buffer))
} catch (error) {
console.error('Error fetching token icon:', error)
res.status(500).json({ error: 'Failed to fetch token icon' })
}
return
})
try {
if (!isValidIconUrl(token.icon)) {
throw new Error('Invalid icon URL')
}
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), 5000)
const response = await fetch(token.icon, {
signal: controller.signal,
headers: {
'Accept': 'image/svg+xml,image/*'
}
})
clearTimeout(timeout)
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.statusText}`)
}
const contentLength = response.headers.get('content-length')
if (contentLength && parseInt(contentLength, 10) > 1024 * 1024) {
throw new Error('Icon file too large')
}
const buffer = await response.arrayBuffer()
// Set cache headers (cache for 1 week)
res.set({
'Cache-Control': 'public, max-age=604800',
'Content-Type': response.headers.get('content-type') || 'image/svg+xml',
})
res.send(Buffer.from(buffer))
} catch (error) {
console.error('Error fetching token icon:', error)
res.status(500).json({ error: 'Failed to fetch token icon' })
}
return
})

@github-actions github-actions bot added size/m and removed size/s labels Dec 1, 2024
@github-actions github-actions bot added size/s and removed size/m labels Dec 1, 2024
@trajan0x trajan0x merged commit 633da8c into master Dec 1, 2024
31 checks passed
@trajan0x trajan0x deleted the fix/router branch December 1, 2024 16:46
Copy link

codecov bot commented Dec 1, 2024

Bundle Report

Changes will increase total bundle size by 358.28kB (1.1%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
widget-cjs-esm 274.03kB 2.76kB (1.02%) ⬆️
@synapsecns/synapse-constants-esm-cjs 177.99kB 177.99kB (100%) ⬆️
@synapsecns/synapse-constants-cjs-esm 177.53kB 177.53kB (100%) ⬆️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant