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

serve icons w doctype header [SLT-547] #3500

Merged
merged 3 commits into from
Jan 28, 2025
Merged

serve icons w doctype header [SLT-547] #3500

merged 3 commits into from
Jan 28, 2025

Conversation

trajan0x
Copy link
Contributor

@trajan0x trajan0x commented Jan 28, 2025

Description

Modification to add doctype header

Summary by CodeRabbit

Release Notes

  • New Features

    • Added SVG header processing utility for icon routes.
    • Improved handling of SVG and image content types.
  • Dependencies

    • Added jsdom library to support SVG processing.
  • Bug Fixes

    • Enhanced icon route response to ensure proper SVG header inclusion.

The update improves icon rendering and content type management for token and chain icons.

Copy link
Contributor

coderabbitai bot commented Jan 28, 2025

Walkthrough

This pull request introduces a new dependency jsdom to the packages/rest-api/package.json and adds a utility function addSvgHeaderIfMissing in svgUtils.ts. The changes enhance SVG image handling in the address and chain icon routes by ensuring proper XML headers are present. The new utility function processes SVG buffers using JSDOM, adding XML headers when missing while maintaining the original SVG content.

Changes

File Change Summary
packages/rest-api/package.json Added jsdom dependency at version ^26.0.0
packages/rest-api/src/routes/addressIconRoute.ts Modified image processing to use addSvgHeaderIfMissing for SVG content
packages/rest-api/src/routes/chainIconRoute.ts Similar modifications to handle SVG content with new utility function
packages/rest-api/src/utils/svgUtils.ts Added new addSvgHeaderIfMissing utility function to process SVG buffers

Possibly related PRs

  • add svg route #3424: The changes in this PR also involve modifications to the package.json file, specifically adding new dependencies, which is directly related to the main PR's addition of the jsdom dependency.

Suggested labels

size/s

Suggested reviewers

  • bigboydiamonds
  • abtestingalpha
  • Defi-Moses

Poem

🐰 SVG headers, once astray
Now dance with JSDOM's gentle sway
Buffers transformed, XML complete
A rabbit's magic, clean and neat!
Icons shine bright, headers in sight 🎨


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38e1c6a and 4a92515.

📒 Files selected for processing (1)
  • packages/rest-api/src/routes/chainIconRoute.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/rest-api/src/routes/chainIconRoute.ts
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: test
  • GitHub Check: test
  • GitHub Check: Cloudflare Pages

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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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

cloudflare-workers-and-pages bot commented Jan 28, 2025

Deploying sanguine-fe with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4a92515
Status:⚡️  Build in progress...

View logs

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: 2

🧹 Nitpick comments (2)
packages/rest-api/src/utils/svgUtils.ts (1)

1-8: Consider using TypeScript's built-in Buffer type

Instead of importing Buffer from 'buffer', consider using TypeScript's built-in Node.js types which include Buffer.

-import { Buffer } from 'buffer'
packages/rest-api/src/routes/chainIconRoute.ts (1)

42-42: Consider adding content length header

For proper client-side handling, consider adding the Content-Length header to the response.

     res.set({
       'Cache-Control': 'public, max-age=604800',
       'Content-Type': contentType,
+      'Content-Length': processedBuffer.length,
     })

Also applies to: 45-45

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8811b0d and 9c4f10d.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (4)
  • packages/rest-api/package.json (1 hunks)
  • packages/rest-api/src/routes/addressIconRoute.ts (2 hunks)
  • packages/rest-api/src/routes/chainIconRoute.ts (2 hunks)
  • packages/rest-api/src/utils/svgUtils.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: lint
  • GitHub Check: changesets-integrity-checker
  • GitHub Check: lint
🔇 Additional comments (3)
packages/rest-api/src/routes/addressIconRoute.ts (2)

40-46: Validate content type before processing

Similar to chainIconRoute.ts, the default content type assumption might lead to incorrect processing of non-SVG files.

Apply the same fix as suggested for chainIconRoute.ts.


51-51: Consider adding content length header

For consistency with chainIconRoute.ts, add the Content-Length header here as well.

Apply the same fix as suggested for chainIconRoute.ts.

Also applies to: 54-54

packages/rest-api/package.json (1)

35-35: ⚠️ Potential issue

Verify jsdom version compatibility

The specified jsdom version ^26.0.0 is not yet released (as of January 2025). The latest stable version is 22.1.0. Please update to use a released version.

-    "jsdom": "^26.0.0",
+    "jsdom": "^22.1.0",

Comment on lines +9 to +44
export const addSvgHeaderIfMissing = (buffer: ArrayBuffer): Buffer => {
const content = Buffer.from(buffer).toString('utf-8')

// Create a DOM with the SVG content
const dom = new JSDOM(content, { contentType: 'image/svg+xml' })
const document = dom.window.document

// Get the serialized content to check if we need to add headers
const serialized = dom.serialize()
const needsXmlHeader = !serialized.includes('<?xml')
const needsDoctype = !serialized.includes('<!DOCTYPE')

if (!needsXmlHeader && !needsDoctype) {
return Buffer.from(content)
}

// Build the final SVG with required headers
let finalSvg = ''
if (needsXmlHeader) {
finalSvg += XML_HEADER + '\n'
}
if (needsDoctype) {
finalSvg += DOCTYPE + '\n'
}

// Add the SVG content
const svgElement = document.querySelector('svg')
if (svgElement) {
finalSvg += svgElement.outerHTML
} else {
// If no SVG element found, return original content
return Buffer.from(content)
}

return Buffer.from(finalSvg)
}
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 error handling for malformed SVG content

The current implementation might throw if the input is not valid UTF-8 or if JSDOM fails to parse the content. Consider adding try-catch blocks to handle these cases gracefully.

 export const addSvgHeaderIfMissing = (buffer: ArrayBuffer): Buffer => {
+  try {
     const content = Buffer.from(buffer).toString('utf-8')
 
     // Create a DOM with the SVG content
     const dom = new JSDOM(content, { contentType: 'image/svg+xml' })
     const document = dom.window.document
 
     // Get the serialized content to check if we need to add headers
     const serialized = dom.serialize()
     const needsXmlHeader = !serialized.includes('<?xml')
     const needsDoctype = !serialized.includes('<!DOCTYPE')
 
     if (!needsXmlHeader && !needsDoctype) {
       return Buffer.from(content)
     }
 
     // Build the final SVG with required headers
     let finalSvg = ''
     if (needsXmlHeader) {
       finalSvg += XML_HEADER + '\n'
     }
     if (needsDoctype) {
       finalSvg += DOCTYPE + '\n'
     }
 
     // Add the SVG content
     const svgElement = document.querySelector('svg')
     if (svgElement) {
       finalSvg += svgElement.outerHTML
     } else {
       // If no SVG element found, return original content
       return Buffer.from(content)
     }
 
     return Buffer.from(finalSvg)
+  } catch (error) {
+    console.warn('Failed to process SVG, returning original content:', error)
+    return Buffer.from(buffer)
+  }
 }
📝 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
export const addSvgHeaderIfMissing = (buffer: ArrayBuffer): Buffer => {
const content = Buffer.from(buffer).toString('utf-8')
// Create a DOM with the SVG content
const dom = new JSDOM(content, { contentType: 'image/svg+xml' })
const document = dom.window.document
// Get the serialized content to check if we need to add headers
const serialized = dom.serialize()
const needsXmlHeader = !serialized.includes('<?xml')
const needsDoctype = !serialized.includes('<!DOCTYPE')
if (!needsXmlHeader && !needsDoctype) {
return Buffer.from(content)
}
// Build the final SVG with required headers
let finalSvg = ''
if (needsXmlHeader) {
finalSvg += XML_HEADER + '\n'
}
if (needsDoctype) {
finalSvg += DOCTYPE + '\n'
}
// Add the SVG content
const svgElement = document.querySelector('svg')
if (svgElement) {
finalSvg += svgElement.outerHTML
} else {
// If no SVG element found, return original content
return Buffer.from(content)
}
return Buffer.from(finalSvg)
}
export const addSvgHeaderIfMissing = (buffer: ArrayBuffer): Buffer => {
try {
const content = Buffer.from(buffer).toString('utf-8')
// Create a DOM with the SVG content
const dom = new JSDOM(content, { contentType: 'image/svg+xml' })
const document = dom.window.document
// Get the serialized content to check if we need to add headers
const serialized = dom.serialize()
const needsXmlHeader = !serialized.includes('<?xml')
const needsDoctype = !serialized.includes('<!DOCTYPE')
if (!needsXmlHeader && !needsDoctype) {
return Buffer.from(content)
}
// Build the final SVG with required headers
let finalSvg = ''
if (needsXmlHeader) {
finalSvg += XML_HEADER + '\n'
}
if (needsDoctype) {
finalSvg += DOCTYPE + '\n'
}
// Add the SVG content
const svgElement = document.querySelector('svg')
if (svgElement) {
finalSvg += svgElement.outerHTML
} else {
// If no SVG element found, return original content
return Buffer.from(content)
}
return Buffer.from(finalSvg)
} catch (error) {
console.warn('Failed to process SVG, returning original content:', error)
return Buffer.from(buffer)
}
}

Comment on lines 31 to 37
const contentType = response.headers.get('content-type') || 'image/svg+xml'

// Only process SVG files
const processedBuffer =
contentType === 'image/svg+xml'
? addSvgHeaderIfMissing(buffer)
: Buffer.from(buffer)
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

Validate content type before processing

The default content type of 'image/svg+xml' might lead to incorrect processing of non-SVG files. Consider using the actual content type from the response headers.

-    const contentType = response.headers.get('content-type') || 'image/svg+xml'
+    const contentType = response.headers.get('content-type')
+    if (!contentType) {
+      throw new Error('Content-Type header missing from response')
+    }
📝 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
const contentType = response.headers.get('content-type') || 'image/svg+xml'
// Only process SVG files
const processedBuffer =
contentType === 'image/svg+xml'
? addSvgHeaderIfMissing(buffer)
: Buffer.from(buffer)
const contentType = response.headers.get('content-type')
if (!contentType) {
throw new Error('Content-Type header missing from response')
}
// Only process SVG files
const processedBuffer =
contentType === 'image/svg+xml'
? addSvgHeaderIfMissing(buffer)
: Buffer.from(buffer)

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: 2

🧹 Nitpick comments (2)
packages/rest-api/src/routes/chainIconRoute.ts (1)

11-11: Enhance query parameter validation and documentation.

The query parameter handling could be more robust:

  1. Add JSDoc to document the headers parameter
  2. Validate against unexpected values
  3. Use a more explicit boolean conversion
+/**
+ * @param {string} [req.query.headers] - When 'true', adds XML headers to SVG files
+ */
-  const addHeaders = req.query.headers === 'true'
+  const addHeaders = ['true', '1', 'yes'].includes(req.query.headers?.toLowerCase() ?? '')
packages/rest-api/src/routes/addressIconRoute.ts (1)

12-12: Consider validating the headers query parameter.

The current implementation only checks for 'true', but other values will silently default to false. Consider explicit validation to handle invalid inputs.

-  const addHeaders = req.query.headers === 'true'
+  const headersParam = req.query.headers?.toString().toLowerCase()
+  if (headersParam && !['true', 'false'].includes(headersParam)) {
+    res.status(400).json({ error: 'Invalid headers parameter. Use "true" or "false".' })
+    return
+  }
+  const addHeaders = headersParam === 'true'
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c4f10d and 38e1c6a.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • packages/rest-api/src/routes/addressIconRoute.ts (2 hunks)
  • packages/rest-api/src/routes/chainIconRoute.ts (2 hunks)
🧰 Additional context used
🪛 GitHub Check: lint
packages/rest-api/src/routes/addressIconRoute.ts

[warning] 44-44:
Insert ⏎·····


[warning] 45-45:
Insert ··


[warning] 46-46:
Insert ··

packages/rest-api/src/routes/chainIconRoute.ts

[warning] 35-35:
Insert ⏎·····


[warning] 36-36:
Insert ··


[warning] 37-37:
Insert ··

🪛 GitHub Actions: Typescript Packages
packages/rest-api/src/routes/addressIconRoute.ts

[warning] 44-46: Formatting issues with whitespace and line breaks

packages/rest-api/src/routes/chainIconRoute.ts

[warning] 35-37: Formatting issues with whitespace and line breaks

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: test
  • GitHub Check: lint
🔇 Additional comments (6)
packages/rest-api/src/routes/chainIconRoute.ts (3)

5-5: LGTM! Clean import addition.

The new utility import is properly placed and follows the project's import conventions.


32-33: Validate content type before processing.

The default content type of 'image/svg+xml' might lead to incorrect processing of non-SVG files.


42-42: LGTM! Proper response handling.

The Content-Type header is correctly set and the processed buffer is properly sent in the response.

Also applies to: 45-45

packages/rest-api/src/routes/addressIconRoute.ts (3)

5-5: LGTM! Clear and well-placed import statement.


51-54: LGTM! Proper response handling with dynamic content type.

The response headers and buffer sending are correctly implemented, maintaining the caching behavior while supporting different content types.


41-42: Reconsider the default content type.

Defaulting to 'image/svg+xml' might be incorrect if the actual image is not an SVG. Consider using a more generic image type or responding with an error if the content type is missing.

Comment on lines 34 to 37
// Only process SVG files if headers are requested
const processedBuffer = contentType === 'image/svg+xml' && addHeaders
? addSvgHeaderIfMissing(buffer)
: Buffer.from(buffer)
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

Fix formatting issues.

The conditional block needs proper indentation and line breaks as flagged by the linter.

-    const processedBuffer = contentType === 'image/svg+xml' && addHeaders
-      ? addSvgHeaderIfMissing(buffer)
-      : Buffer.from(buffer)
+    const processedBuffer = contentType === 'image/svg+xml' && addHeaders
+        ? addSvgHeaderIfMissing(buffer)
+        : Buffer.from(buffer)
📝 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
// Only process SVG files if headers are requested
const processedBuffer = contentType === 'image/svg+xml' && addHeaders
? addSvgHeaderIfMissing(buffer)
: Buffer.from(buffer)
// Only process SVG files if headers are requested
const processedBuffer = contentType === 'image/svg+xml' && addHeaders
? addSvgHeaderIfMissing(buffer)
: Buffer.from(buffer)
🧰 Tools
🪛 GitHub Check: lint

[warning] 35-35:
Insert ⏎·····


[warning] 36-36:
Insert ··


[warning] 37-37:
Insert ··

🪛 GitHub Actions: Typescript Packages

[warning] 35-37: Formatting issues with whitespace and line breaks

Comment on lines +43 to +46
// Only process SVG files if headers are requested
const processedBuffer = contentType === 'image/svg+xml' && addHeaders
? addSvgHeaderIfMissing(buffer)
: Buffer.from(buffer)
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

Fix indentation as per linting rules.

The conditional expression needs proper indentation.

     // Only process SVG files if headers are requested
-    const processedBuffer = contentType === 'image/svg+xml' && addHeaders
-      ? addSvgHeaderIfMissing(buffer)
-      : Buffer.from(buffer)
+    const processedBuffer = contentType === 'image/svg+xml' && addHeaders
+        ? addSvgHeaderIfMissing(buffer)
+        : Buffer.from(buffer)
📝 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
// Only process SVG files if headers are requested
const processedBuffer = contentType === 'image/svg+xml' && addHeaders
? addSvgHeaderIfMissing(buffer)
: Buffer.from(buffer)
// Only process SVG files if headers are requested
const processedBuffer = contentType === 'image/svg+xml' && addHeaders
? addSvgHeaderIfMissing(buffer)
: Buffer.from(buffer)
🧰 Tools
🪛 GitHub Check: lint

[warning] 44-44:
Insert ⏎·····


[warning] 45-45:
Insert ··


[warning] 46-46:
Insert ··

🪛 GitHub Actions: Typescript Packages

[warning] 44-46: Formatting issues with whitespace and line breaks

@trajan0x
Copy link
Contributor Author

maybe less relevant

@trajan0x trajan0x merged commit d60545c into master Jan 28, 2025
31 of 35 checks passed
@trajan0x trajan0x deleted the fix/icon branch January 28, 2025 12:08
Copy link

codecov bot commented Jan 28, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 90.59166%. Comparing base (2847b63) to head (4a92515).
Report is 2 commits behind head on master.

❗ There is a different number of reports uploaded between BASE (2847b63) and HEAD (4a92515). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (2847b63) HEAD (4a92515)
solidity 1 0
Additional details and impacted files
@@                 Coverage Diff                 @@
##              master       #3500         +/-   ##
===================================================
- Coverage   98.89241%   90.59166%   -8.30075%     
===================================================
  Files             11          54         +43     
  Lines            632        1031        +399     
  Branches           0          82         +82     
===================================================
+ Hits             625         934        +309     
- Misses             7          95         +88     
- Partials           0           2          +2     
Flag Coverage Δ
packages 90.59166% <ø> (?)
solidity ?

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.

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