Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/llms-txt-hub / apps/web/app/api/websites/search/route.ts |
| Date | Not specified in source |
| Repository | Janady13/llms-txt-hub |
| Revision | e0f4bf978d4df168369c7601d9c5f5ea89e84377 |
| Branch | main |
| Path or archive member | apps/web/app/api/websites/search/route.ts |
| Original SHA-256 | 53ea234820060ea84580e4f1ea6d11f55d582f6a7aba471416c371a605188398 |
| Git blob SHA | abc1704d5b3fec5140c88681ff859ffe9a522934 |
| Reading-copy SHA-256 | 53ea234820060ea84580e4f1ea6d11f55d582f6a7aba471416c371a605188398 |
Recovered source transcript
Download complete source text ↓91 lines · 2.7 KB
import { logger } from '@thedaviddias/logging'
import { NextResponse } from 'next/server'
import { getWebsites } from '@/lib/content-loader'
interface SearchWebsitesResponse {
websites: Array<{
slug: string
name: string
description: string
website: string
category: string
publishedAt: string
isUnofficial?: boolean
}>
totalCount: number
query: string
}
/**
* API endpoint for searching all websites
* Searches across all 887+ websites regardless of what's loaded on the page
* Supports search by name, description, and category
*/
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url)
const query = searchParams.get('q')?.trim() || ''
const limit = Math.min(
200,
Math.max(10, Number.parseInt(searchParams.get('limit') || '100', 10))
)
if (!query) {
return NextResponse.json({
websites: [],
totalCount: 0,
query: ''
} as SearchWebsitesResponse)
}
const allWebsites = await getWebsites()
const searchQuery = query.toLowerCase()
// Search across name, description, and category
const matchingWebsites = allWebsites.filter(website => {
return (
website.name.toLowerCase().includes(searchQuery) ||
website.description.toLowerCase().includes(searchQuery) ||
website.category.toLowerCase().includes(searchQuery)
)
})
// Sort by relevance (exact name matches first, then description matches)
const sortedWebsites = matchingWebsites.sort((a, b) => {
const aNameMatch = a.name.toLowerCase().includes(searchQuery)
const bNameMatch = b.name.toLowerCase().includes(searchQuery)
if (aNameMatch && !bNameMatch) return -1
if (!aNameMatch && bNameMatch) return 1
// If both or neither match by name, sort by published date (newest first)
return new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime()
})
// Apply limit
const limitedWebsites = sortedWebsites.slice(0, limit)
const response: SearchWebsitesResponse = {
websites: limitedWebsites.map(website => ({
slug: website.slug,
name: website.name,
description: website.description,
website: website.website,
category: website.category,
publishedAt: website.publishedAt,
isUnofficial: website.isUnofficial
})),
totalCount: matchingWebsites.length,
query
}
return NextResponse.json(response)
} catch (error) {
logger.error('Error searching websites', {
data: error,
tags: { api: 'websites-search' }
})
return NextResponse.json({ error: 'Failed to search websites' }, { status: 500 })
}
}