Skip to content

Commit 3886299

Browse files
committed
feat: add search endpoint
1 parent 95ef5a0 commit 3886299

File tree

1 file changed

+83
-1
lines changed

1 file changed

+83
-1
lines changed

src/routes/extensions.ts

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,89 @@ app.get('/extensions/categories', async (c) => {
471471
name,
472472
extensions: _count.extensions
473473
})));
474-
})
474+
});
475+
476+
app.get('/extensions/search', async (c) => {
477+
try {
478+
const query = c.req.query('q');
479+
const page = Math.max(1, parseInt(c.req.query('page') || '1', 10));
480+
const limit = Math.min(
481+
200,
482+
Math.max(1, parseInt(c.req.query('limit') || String(DEFAULT_PAGE_SIZE), 10))
483+
);
484+
const skip = (page - 1) * limit;
485+
486+
if (!query || query.trim().length === 0) {
487+
return c.json({ error: 'Search query is required' }, 400);
488+
}
489+
490+
const searchTerm = query.trim().toLowerCase();
491+
const storage = c.get('storage');
492+
const baseUrl = c.get('baseUrl');
493+
494+
// Search extensions by name, title, or description
495+
const where: any = {
496+
AND: [
497+
{ killListedAt: null },
498+
{
499+
OR: [
500+
{ name: { contains: searchTerm } },
501+
{ title: { contains: searchTerm } },
502+
{ description: { contains: searchTerm } },
503+
],
504+
},
505+
],
506+
};
507+
508+
const total = await prisma.extension.count({ where });
509+
510+
const extensions = await prisma.extension.findMany({
511+
where,
512+
skip,
513+
take: limit,
514+
orderBy: {
515+
downloadCount: 'desc',
516+
},
517+
include: {
518+
author: {
519+
include: {
520+
github: true,
521+
},
522+
},
523+
categories: true,
524+
platforms: true,
525+
commands: true,
526+
},
527+
});
528+
529+
// Format the extensions
530+
const items = await Promise.all(
531+
extensions.map((ext) => formatExtensionResponse(ext, storage, baseUrl))
532+
);
533+
534+
return c.json({
535+
extensions: items,
536+
query: query.trim(),
537+
pagination: {
538+
page,
539+
limit,
540+
total,
541+
totalPages: Math.ceil(total / limit),
542+
hasNext: page < Math.ceil(total / limit),
543+
hasPrev: page > 1,
544+
},
545+
});
546+
} catch (error) {
547+
console.error('Search extensions error:', error);
548+
return c.json(
549+
{
550+
error: 'Internal server error',
551+
message: error instanceof Error ? error.message : 'Unknown error',
552+
},
553+
500
554+
);
555+
}
556+
});
475557

476558
// Map of extension key (author/name) to Set of IPs that have downloaded it
477559
const downloadIpMap = new Map<string, Set<string>>();

0 commit comments

Comments
 (0)