Skip to content

Add Bluesky favorites viewer tool#118

Merged
simonw merged 2 commits intomainfrom
claude/bluesky-favorites-viewer-01TofmmMwqFN4s2spYuXeavU
Nov 27, 2025
Merged

Add Bluesky favorites viewer tool#118
simonw merged 2 commits intomainfrom
claude/bluesky-favorites-viewer-01TofmmMwqFN4s2spYuXeavU

Conversation

@simonw
Copy link
Owner

@simonw simonw commented Nov 27, 2025

New tool to view posts liked/favorited by any Bluesky user.
Accepts profile URL, DID, or @username via ?user= query string.
Fetches up to 200 liked posts with pagination support.


Build bluesky-faves.html - a tool similar to the existing Bluesky thread viewer, but it takes the profile URL or DID or @username, puts that in the query string as ?user=… and then fetches the most recent 200 posts favorited by that user and displays them with the most recent at the top

New tool to view posts liked/favorited by any Bluesky user.
Accepts profile URL, DID, or @username via ?user= query string.
Fetches up to 200 liked posts with pagination support.
@claude
Copy link
Contributor

claude bot commented Nov 27, 2025

Claude finished @simonw's task —— View job


Code Review Complete ✅

I've completed a comprehensive review of the Bluesky favorites viewer tool. Here's my detailed feedback:

Tasks

  • Read CLAUDE.md for repo-specific guidelines
  • Read and analyze bluesky-faves.html file
  • Review code quality and best practices
  • Check for potential bugs or issues
  • Evaluate performance considerations
  • Assess security concerns
  • Review test coverage considerations
  • Post comprehensive review feedback

🟢 Code Quality & Best Practices

Strengths:

  • Well-structured HTML/CSS/JS: Clean separation with embedded styles and script in a single-file approach
  • Responsive design: Proper mobile breakpoints at 600px with appropriate adjustments
  • Modern CSS: Uses flexbox, CSS variables via custom properties, and modern selectors
  • Semantic HTML: Proper use of form elements, semantic structure
  • Accessibility considerations: alt attributes, aria-* could be improved but basic structure is sound
  • Modern JavaScript: Uses async/await, proper event handling, ES6+ features

Areas for improvement:

  • Consider extracting large inline styles to external CSS for better maintainability
  • Add more semantic HTML5 elements (<main>, <section>, <article>)
  • Consider adding aria-live regions for status updates for screen readers

🟡 Potential Bugs & Issues

Minor Issues:

  1. Avatar fallback (lines 377, 416): Empty src="" when no avatar - should use placeholder image or hide element
  2. URL parsing edge case (lines 314-324): Could be more robust with malformed URLs
  3. Memory accumulation: allPosts array grows indefinitely with "Load More" - consider implementing a maximum limit
  4. Error handling: Some async operations lack proper error boundaries

Recommended fixes:

// Better avatar handling
document.getElementById('userAvatar').src = profile.avatar || 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGNpcmNsZSBjeD0iMzIiIGN5PSIzMiIgcj0iMzIiIGZpbGw9IiNmMGYwZjAiLz4KPHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPC9zdmc+';

// Memory management
const MAX_POSTS = 1000;
if (allPosts.length >= MAX_POSTS) {
  loadMore.style.display = 'none';
  showStatus('Maximum posts loaded', true);
  return;
}

🟢 Performance Considerations

Good practices:

  • Lazy loading: Images use loading="lazy" attribute
  • Efficient DOM updates: Appends posts incrementally rather than rebuilding entire list
  • Reasonable batch size: 100 posts per request is well-balanced
  • Cursor-based pagination: Proper API pagination implementation

Optimization opportunities:

  • Virtual scrolling: For very long lists (1000+ posts), consider implementing virtual scrolling
  • Image optimization: Could add decoding="async" to images
  • Debouncing: Form submission could benefit from debouncing rapid clicks

🟡 Security Concerns

Identified issues:

  1. XSS Prevention (line 438-442): escapeHtml() function is good but could be more robust:
function escapeHtml(text) {
  if (!text) return '';
  return text
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, ''');
}
  1. URL validation (lines 512-514): Direct URL manipulation without validation
  2. External links: Uses target="_blank" with rel="noopener" ✅ (good practice)

Recommendations:

  • Add CSP headers if deploying to production
  • Consider input sanitization for the user input field
  • Validate URLs before setting in browser history

🔴 Test Coverage

Current state: No automated tests present

Recommendations:

  • Unit tests for utility functions (parseUserInput, escapeHtml, generateTextOutput)
  • Integration tests for API calls (could use mock responses)
  • E2E tests for user workflows (form submission, pagination)
  • Accessibility testing with tools like axe-core

Example test structure:

// parseUserInput tests
expect(parseUserInput('https://bsky.app/profile/example.com')).toBe('example.com');
expect(parseUserInput('@username')).toBe('username.bsky.social');
expect(parseUserInput('did:plc:abc123')).toBe('did:plc:abc123');

🟢 Overall Assessment

This is a well-implemented single-page application that demonstrates good understanding of modern web development practices. The code is clean, functional, and addresses the core requirements effectively.

Strengths:

  • Clean, maintainable code structure
  • Good user experience with loading states and error handling
  • Proper API integration with Bluesky's public endpoints
  • Responsive design that works across devices
  • Thoughtful features like copy-to-clipboard and URL state management

Priority improvements:

  1. Add basic test coverage for critical functions
  2. Improve error handling robustness
  3. Enhance XSS protection
  4. Consider memory management for large datasets

The tool successfully delivers on its promise to view Bluesky favorites with a clean, user-friendly interface. The implementation shows solid technical skills and attention to user experience.

The app.bsky.feed.getActorLikes endpoint requires authentication and
only allows fetching your own likes. This fix uses the public
com.atproto.repo.listRecords endpoint to fetch like records, then
app.bsky.feed.getPosts to get the actual post content.
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Nov 27, 2025

Deploying tools with  Cloudflare Pages  Cloudflare Pages

Latest commit: 06e334b
Status: ✅  Deploy successful!
Preview URL: https://ebe63621.tools-b1q.pages.dev
Branch Preview URL: https://claude-bluesky-favorites-vie.tools-b1q.pages.dev

View logs

@claude
Copy link
Contributor

claude bot commented Nov 27, 2025

Claude finished @simonw's task —— View job


Code Review Complete ✅

I've completed a comprehensive review of the Bluesky favorites viewer tool. Here's my detailed feedback:

Tasks

  • Read CLAUDE.md for repo-specific guidelines
  • Read and analyze bluesky-faves.html file
  • Review code quality and best practices
  • Check for potential bugs or issues
  • Evaluate performance considerations
  • Assess security concerns
  • Review test coverage considerations
  • Post comprehensive review feedback

🟢 Code Quality & Best Practices

Strengths:

  • Well-structured HTML/CSS/JS: Clean separation with embedded styles and script in a single-file approach
  • Responsive design: Proper mobile breakpoints at 600px with appropriate adjustments
  • Modern CSS: Uses flexbox, CSS variables via custom properties, and modern selectors
  • Semantic HTML: Proper use of form elements, semantic structure
  • Accessibility considerations: alt attributes, aria-* could be improved but basic structure is sound
  • Modern JavaScript: Uses async/await, proper event handling, ES6+ features

Areas for improvement:

  • Consider extracting large inline styles to external CSS for better maintainability
  • Add more semantic HTML5 elements (<main>, <section>, <article>)
  • Consider adding aria-live regions for status updates for screen readers

🟡 Potential Bugs & Issues

Minor Issues:

  1. Avatar fallback (lines 434, 473): Empty src="" when no avatar - should use placeholder image or hide element
  2. URL parsing edge case (lines 314-324): Could be more robust with malformed URLs
  3. Memory accumulation: allPosts array grows indefinitely with "Load More" - consider implementing a maximum limit
  4. Error handling: Some async operations lack proper error boundaries

Recommended fixes:

// Better avatar handling
document.getElementById('userAvatar').src = profile.avatar || 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGNpcmNsZSBjeD0iMzIiIGN5PSIzMiIgcj0iMzIiIGZpbGw9IiNmMGYwZjAiLz4KPHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPC9zdmc+';

// Memory management
const MAX_POSTS = 1000;
if (allPosts.length >= MAX_POSTS) {
  loadMore.style.display = 'none';
  showStatus('Maximum posts loaded', true);
  return;
}

🟢 Performance Considerations

Good practices:

  • Lazy loading: Images use loading="lazy" attribute
  • Efficient DOM updates: Appends posts incrementally rather than rebuilding entire list
  • Reasonable batch size: 100 posts per request is well-balanced
  • Cursor-based pagination: Proper API pagination implementation

Optimization opportunities:

  • Virtual scrolling: For very long lists (1000+ posts), consider implementing virtual scrolling
  • Image optimization: Could add decoding="async" to images
  • Debouncing: Form submission could benefit from debouncing rapid clicks

🟡 Security Concerns

Identified issues:

  1. XSS Prevention (line 495-499): escapeHtml() function is good but could be more robust:
function escapeHtml(text) {
  if (!text) return '';
  return text
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, ''');
}
  1. URL validation (lines 569-571): Direct URL manipulation without validation
  2. External links: Uses target="_blank" with rel="noopener" ✅ (good practice)

Recommendations:

  • Add CSP headers if deploying to production
  • Consider input sanitization for the user input field
  • Validate URLs before setting in browser history

🔴 Test Coverage

Current state: No automated tests present

Recommendations:

  • Unit tests for utility functions (parseUserInput, escapeHtml, generateTextOutput)
  • Integration tests for API calls (could use mock responses)
  • E2E tests for user workflows (form submission, pagination)
  • Accessibility testing with tools like axe-core

Example test structure:

// parseUserInput tests
expect(parseUserInput('https://bsky.app/profile/example.com')).toBe('example.com');
expect(parseUserInput('@username')).toBe('username.bsky.social');
expect(parseUserInput('did:plc:abc123')).toBe('did:plc:abc123');

🟢 Overall Assessment

This is a well-implemented single-page application that demonstrates good understanding of modern web development practices. The code is clean, functional, and addresses the core requirements effectively.

Strengths:

  • Clean, maintainable code structure
  • Good user experience with loading states and error handling
  • Proper API integration with Bluesky's public endpoints
  • Responsive design that works across devices
  • Thoughtful features like copy-to-clipboard and URL state management

Priority improvements:

  1. Add basic test coverage for critical functions
  2. Improve error handling robustness
  3. Enhance XSS protection
  4. Consider memory management for large datasets

The tool successfully delivers on its promise to view Bluesky favorites with a clean, user-friendly interface. The implementation shows solid technical skills and attention to user experience.


@simonw simonw merged commit 1eef44d into main Nov 27, 2025
4 checks passed
@simonw simonw deleted the claude/bluesky-favorites-viewer-01TofmmMwqFN4s2spYuXeavU branch November 27, 2025 00:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants