import type { RequestHandler } from './$types' import { prisma } from '$lib/server/database' import { logger } from '$lib/server/logger' // Helper function to escape XML special characters function escapeXML(str: string): string { if (!str) return '' return str .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, ''') } // Helper function to convert content to HTML for full content function convertContentToHTML(content: any): string { if (!content || !content.blocks) return '' return content.blocks .map((block: any) => { switch (block.type) { case 'paragraph': return `
${escapeXML(block.content || '')}
` case 'heading': const level = block.level || 2 return `${escapeXML(block.content || '')}
` } }) .join('\n') } // Helper function to extract text summary from content function extractTextSummary(content: any, maxLength: number = 300): string { if (!content || !content.blocks) return '' const text = content.blocks .filter((block: any) => block.type === 'paragraph' && block.content) .map((block: any) => block.content) .join(' ') return text.length > maxLength ? text.substring(0, maxLength) + '...' : text } // Helper function to format RFC 822 date function formatRFC822Date(date: Date): string { return date.toUTCString() } export const GET: RequestHandler = async (event) => { try { // Get published posts from Universe const posts = await prisma.post.findMany({ where: { status: 'published', publishedAt: { not: null } }, orderBy: { publishedAt: 'desc' }, take: 25 }) // Get published albums that show in universe const universeAlbums = await prisma.album.findMany({ where: { status: 'published', showInUniverse: true }, include: { photos: { where: { status: 'published', showInPhotos: true }, orderBy: { displayOrder: 'asc' }, take: 1 // Get first photo for cover image }, _count: { select: { photos: true } } }, orderBy: { createdAt: 'desc' }, take: 15 }) // Get published photography albums const photoAlbums = await prisma.album.findMany({ where: { status: 'published', isPhotography: true }, include: { photos: { where: { status: 'published', showInPhotos: true }, orderBy: { displayOrder: 'asc' }, take: 1 // Get first photo for cover image }, _count: { select: { photos: { where: { status: 'published', showInPhotos: true } } } } }, orderBy: { createdAt: 'desc' }, take: 15 }) // Combine all content types const items = [ ...posts.map((post) => ({ type: 'post', section: 'universe', id: post.id.toString(), title: post.title || `${post.postType.charAt(0).toUpperCase() + post.postType.slice(1)} Post`, description: post.excerpt || extractTextSummary(post.content) || '', content: convertContentToHTML(post.content), link: `${event.url.origin}/universe/${post.slug}`, guid: `${event.url.origin}/universe/${post.slug}`, pubDate: post.publishedAt || post.createdAt, updatedDate: post.updatedAt, postType: post.postType, linkUrl: post.linkUrl || null })), ...universeAlbums.map((album) => ({ type: 'album', section: 'universe', id: album.id.toString(), title: album.title, description: album.description || `Photo album with ${album._count.photos} photo${album._count.photos !== 1 ? 's' : ''}`, content: album.description ? `${escapeXML(album.description)}
` : '', link: `${event.url.origin}/photos/${album.slug}`, guid: `${event.url.origin}/photos/${album.slug}`, pubDate: album.createdAt, updatedDate: album.updatedAt, photoCount: album._count.photos, coverPhoto: album.photos[0], location: album.location })), ...photoAlbums .filter((album) => !universeAlbums.some((ua) => ua.id === album.id)) // Avoid duplicates .map((album) => ({ type: 'album', section: 'photos', id: album.id.toString(), title: album.title, description: album.description || `Photography album${album.location ? ` from ${album.location}` : ''} with ${album._count.photos} photo${album._count.photos !== 1 ? 's' : ''}`, content: album.description ? `${escapeXML(album.description)}
` : '', link: `${event.url.origin}/photos/${album.slug}`, guid: `${event.url.origin}/photos/${album.slug}`, pubDate: album.createdAt, updatedDate: album.updatedAt, photoCount: album._count.photos, coverPhoto: album.photos[0], location: album.location, date: album.date })) ].sort((a, b) => new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime()) const now = new Date() const lastBuildDate = formatRFC822Date(now) // Build RSS XML following best practices const rssXml = `