@@ -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
477559const downloadIpMap = new Map < string , Set < string > > ( ) ;
0 commit comments