@@ -100,7 +100,9 @@ interface FeedbackRequest {
100100 valueDecimals ?: number ;
101101 tag1 ?: string ;
102102 tag2 ?: string ;
103+ message ?: string ;
103104 endpoint ?: string ;
105+ outcome ?: number ;
104106 reviewerAddress ?: string ;
105107 feedbackURI ?: string ;
106108 feedbackHash ?: string ;
@@ -255,12 +257,14 @@ export function createIdentityApi(env: Env) {
255257 const nameFilter = c . req . query ( "name" ) ?. toLowerCase ( ) ;
256258 const ownerFilter = c . req . query ( "owner" ) ;
257259 const endpointTypesParam = c . req . query ( "endpointTypes" ) ;
260+ const orderParam = c . req . query ( "order" ) === "oldest" ? ( "oldest" as const ) : ( "newest" as const ) ;
258261 const limitParam = Number . parseInt ( c . req . query ( "limit" ) ?? "20" , 10 ) ;
259262 const offsetParam = Number . parseInt ( c . req . query ( "offset" ) ?? "0" , 10 ) ;
260263 const limit = Math . min ( Math . max ( limitParam , 1 ) , 50 ) ;
261264 const offset = Math . max ( offsetParam , 0 ) ;
262265
263266 const endpointTypes = endpointTypesParam ?. split ( "," ) . filter ( Boolean ) ?? [ ] ;
267+ const hasFilters = ! ! ( nameFilter || endpointTypes . length > 0 ) ;
264268
265269 try {
266270 const sati = createSatiClient ( network , env ) ;
@@ -272,29 +276,42 @@ export function createIdentityApi(env: Env) {
272276 return c . json ( { error : "Invalid owner address" } , 400 ) ;
273277 }
274278 agents = await sati . listAgentsByOwner ( ownerFilter as Address ) ;
279+ } else if ( hasFilters ) {
280+ // Fetch all agents when filters require full scan
281+ const result = await sati . listAllAgents ( {
282+ limit : Number ( stats . totalAgents ) ,
283+ offset : 0 ,
284+ order : orderParam ,
285+ } ) ;
286+ agents = result . agents ;
275287 } else {
276- const result = await sati . listAllAgents ( { limit : limit + offset , offset : 0 } ) ;
288+ const result = await sati . listAllAgents ( { limit : limit + offset , offset : 0 , order : orderParam } ) ;
277289 agents = result . agents . slice ( offset ) ;
278290 }
279291
280- // Fetch registration files and apply filters
281- const results = [ ] ;
282- for ( const agent of agents ) {
283- if ( results . length >= limit ) break ;
292+ // Fetch registration files in parallel
293+ const regFileResults = await Promise . allSettled (
294+ agents . map ( ( agent ) => fetchRegistrationFile ( agent . uri , { strict : true } ) ) ,
295+ ) ;
284296
285- const regFile = await fetchRegistrationFile ( agent . uri , { strict : true } ) ;
297+ // Apply filters and collect results
298+ const filtered : Array < Record < string , unknown > > = [ ] ;
299+ for ( let i = 0 ; i < agents . length ; i ++ ) {
300+ const agent = agents [ i ] ;
301+ const settled = regFileResults [ i ] ;
302+ const regFile = settled . status === "fulfilled" ? settled . value : null ;
286303
287304 if ( nameFilter ) {
288305 const agentName = ( regFile ?. name ?? agent . name ) . toLowerCase ( ) ;
289306 if ( ! agentName . includes ( nameFilter ) ) continue ;
290307 }
291308
292309 if ( endpointTypes . length > 0 ) {
293- const serviceNames = ( regFile ?. services ?? [ ] ) . map ( ( s ) => s . name ) ;
310+ const serviceNames = ( regFile ?. services ?? [ ] ) . map ( ( s : { name : string } ) => s . name ) ;
294311 if ( ! endpointTypes . some ( ( t ) => serviceNames . includes ( t ) ) ) continue ;
295312 }
296313
297- results . push ( {
314+ filtered . push ( {
298315 mint : agent . mint ,
299316 agentId : `${ CAIP2_CHAINS [ network ] } :${ agent . mint } ` ,
300317 owner : agent . owner ,
@@ -311,7 +328,10 @@ export function createIdentityApi(env: Env) {
311328 } ) ;
312329 }
313330
314- return c . json ( { agents : results , count : results . length , totalAgents : Number ( stats . totalAgents ) } ) ;
331+ // Apply pagination to filtered results
332+ const paginated = hasFilters ? filtered . slice ( offset , offset + limit ) : filtered . slice ( 0 , limit ) ;
333+
334+ return c . json ( { agents : paginated , count : paginated . length , totalAgents : Number ( stats . totalAgents ) } ) ;
315335 } catch ( error ) {
316336 console . error ( "[agents] ERROR:" , error ) ;
317337 return c . json ( { error : error instanceof Error ? error . message : "Failed to list agents" } , 500 ) ;
@@ -346,6 +366,7 @@ export function createIdentityApi(env: Env) {
346366
347367 let feedbackCount = 0 ;
348368 let totalValue = 0 ;
369+ let valueCount = 0 ;
349370
350371 for ( const schema of feedbackSchemas ) {
351372 const feedbacks = await sati . listFeedbacks ( {
@@ -358,6 +379,7 @@ export function createIdentityApi(env: Env) {
358379 feedbackCount ++ ;
359380 if ( parsed ?. value !== undefined ) {
360381 totalValue += parsed . value ;
382+ valueCount ++ ;
361383 }
362384 }
363385 }
@@ -371,14 +393,15 @@ export function createIdentityApi(env: Env) {
371393 image : regFile ?. image ?? "" ,
372394 uri : agent . uri ,
373395 memberNumber : Number ( agent . memberNumber ) ,
396+ nonTransferable : agent . nonTransferable ,
374397 active : regFile ?. active ?? true ,
375398 services : regFile ?. services ?? [ ] ,
376399 supportedTrust : regFile ?. supportedTrust ?? [ ] ,
377400 x402Support : regFile ?. x402Support ?? false ,
378401 registrations : regFile ?. registrations ?? [ ] ,
379402 reputation : {
380403 count : feedbackCount ,
381- summaryValue : feedbackCount > 0 ? Math . round ( totalValue / feedbackCount ) : 0 ,
404+ summaryValue : valueCount > 0 ? Math . round ( totalValue / valueCount ) : 0 ,
382405 summaryValueDecimals : 0 ,
383406 } ,
384407 } ) ;
@@ -412,7 +435,7 @@ export function createIdentityApi(env: Env) {
412435
413436 let count = 0 ;
414437 let totalValue = 0 ;
415- let hasValues = false ;
438+ let valueCount = 0 ;
416439
417440 for ( const schema of feedbackSchemas ) {
418441 const feedbacks = await sati . listFeedbacks ( {
@@ -431,14 +454,14 @@ export function createIdentityApi(env: Env) {
431454 count ++ ;
432455 if ( parsed ?. value !== undefined ) {
433456 totalValue += parsed . value ;
434- hasValues = true ;
457+ valueCount ++ ;
435458 }
436459 }
437460 }
438461
439462 return c . json ( {
440463 count,
441- summaryValue : hasValues ? Math . round ( totalValue / count ) : 0 ,
464+ summaryValue : valueCount > 0 ? Math . round ( totalValue / valueCount ) : 0 ,
442465 summaryValueDecimals : 0 ,
443466 } ) ;
444467 } catch ( error ) {
@@ -466,7 +489,7 @@ export function createIdentityApi(env: Env) {
466489
467490 let count = 0 ;
468491 let totalValue = 0 ;
469- let hasValues = false ;
492+ let valueCount = 0 ;
470493
471494 for ( const schema of feedbackSchemas ) {
472495 const feedbacks = await sati . listFeedbacks ( {
@@ -478,12 +501,12 @@ export function createIdentityApi(env: Env) {
478501 count ++ ;
479502 if ( parsed ?. value !== undefined ) {
480503 totalValue += parsed . value ;
481- hasValues = true ;
504+ valueCount ++ ;
482505 }
483506 }
484507 }
485508
486- const score = hasValues ? Math . round ( totalValue / count ) : 0 ;
509+ const score = valueCount > 0 ? Math . round ( totalValue / valueCount ) : 0 ;
487510 const label = "SATI" ;
488511 const value = count > 0 ? `${ score } /100 (${ count } )` : "no reviews" ;
489512 const color = count === 0 ? "#999" : score >= 70 ? "#4c1" : score >= 40 ? "#dfb317" : "#e05d44" ;
@@ -544,7 +567,6 @@ export function createIdentityApi(env: Env) {
544567 const nowSec = Math . floor ( Date . now ( ) / 1000 ) ;
545568
546569 const feedbackItems : Array < Record < string , unknown > > = [ ] ;
547- let feedbackIndex = 0 ;
548570
549571 for ( const schema of feedbackSchemas ) {
550572 const filter : Record < string , unknown > = { sasSchema : schema as Address } ;
@@ -564,16 +586,15 @@ export function createIdentityApi(env: Env) {
564586 const createdAt = nowSec - Math . floor ( slotDiff * 0.4 ) ;
565587
566588 feedbackItems . push ( {
567- compressedAddress : fb . address ,
589+ compressedAddress : bs58 . encode ( new Uint8Array ( fb . address ) ) ,
568590 clientAddress : fb . data . counterparty ,
569591 agentMint : fb . data . agentMint ,
570- feedbackIndex : feedbackIndex ++ ,
571- value : parsed ?. value ?? 0 ,
572- valueDecimals : parsed ?. valueDecimals ?? 0 ,
573- tag1 : parsed ?. tag1 ?? "" ,
574- tag2 : parsed ?. tag2 ?? "" ,
575- message : parsed ?. m ?? "" ,
576- endpoint : parsed ?. endpoint ?? "" ,
592+ value : parsed ?. value ?? null ,
593+ valueDecimals : parsed ?. valueDecimals ?? null ,
594+ tag1 : parsed ?. tag1 ?? null ,
595+ tag2 : parsed ?. tag2 ?? null ,
596+ message : parsed ?. m ?? null ,
597+ endpoint : parsed ?. endpoint ?? null ,
577598 outcome : fb . data . outcome ,
578599 createdAt,
579600 schema : schema === networkConfig . feedbackSchema ? "FeedbackV1" : "FeedbackPublicV1" ,
@@ -588,21 +609,26 @@ export function createIdentityApi(env: Env) {
588609 app . get ( "/api/feedback/:mint" , async ( c ) => {
589610 const mint = c . req . param ( "mint" ) ;
590611 const network = getNetwork ( c . req . query ( "network" ) ) ;
612+ const limitParam = Number . parseInt ( c . req . query ( "limit" ) ?? "50" , 10 ) ;
613+ const offsetParam = Number . parseInt ( c . req . query ( "offset" ) ?? "0" , 10 ) ;
614+ const limit = Math . min ( Math . max ( limitParam , 1 ) , 200 ) ;
615+ const offset = Math . max ( offsetParam , 0 ) ;
591616
592617 if ( ! isAddress ( mint ) ) {
593618 return c . json ( { error : "Invalid mint address" } , 400 ) ;
594619 }
595620
596621 try {
597622 const sati = createSatiClient ( network , env ) ;
598- const feedbackItems = await queryFeedback ( sati , network , mint as Address , {
623+ const allItems = await queryFeedback ( sati , network , mint as Address , {
599624 clientAddress : c . req . query ( "clientAddress" ) ,
600625 tag1 : c . req . query ( "tag1" ) ,
601626 tag2 : c . req . query ( "tag2" ) ,
602627 outcome : c . req . query ( "outcome" ) ,
603628 } ) ;
629+ const paginated = allItems . slice ( offset , offset + limit ) ;
604630
605- return c . json ( { feedbacks : feedbackItems , count : feedbackItems . length } ) ;
631+ return c . json ( { feedbacks : paginated , count : paginated . length , total : allItems . length } ) ;
606632 } catch ( error ) {
607633 console . error ( "[feedback list] ERROR:" , error ) ;
608634 return c . json ( { error : error instanceof Error ? error . message : "Failed to list feedback" } , 500 ) ;
@@ -615,23 +641,51 @@ export function createIdentityApi(env: Env) {
615641
616642 app . get ( "/api/feedback" , async ( c ) => {
617643 const network = getNetwork ( c . req . query ( "network" ) ) ;
644+ const limitParam = Number . parseInt ( c . req . query ( "limit" ) ?? "50" , 10 ) ;
645+ const offsetParam = Number . parseInt ( c . req . query ( "offset" ) ?? "0" , 10 ) ;
646+ const limit = Math . min ( Math . max ( limitParam , 1 ) , 200 ) ;
647+ const offset = Math . max ( offsetParam , 0 ) ;
618648
619649 try {
620650 const sati = createSatiClient ( network , env ) ;
621- const feedbackItems = await queryFeedback ( sati , network , undefined , {
651+ const allItems = await queryFeedback ( sati , network , undefined , {
622652 clientAddress : c . req . query ( "clientAddress" ) ,
623653 tag1 : c . req . query ( "tag1" ) ,
624654 tag2 : c . req . query ( "tag2" ) ,
625655 outcome : c . req . query ( "outcome" ) ,
626656 } ) ;
657+ const paginated = allItems . slice ( offset , offset + limit ) ;
627658
628- return c . json ( { feedbacks : feedbackItems , count : feedbackItems . length } ) ;
659+ return c . json ( { feedbacks : paginated , count : paginated . length , total : allItems . length } ) ;
629660 } catch ( error ) {
630661 console . error ( "[feedback global] ERROR:" , error ) ;
631662 return c . json ( { error : error instanceof Error ? error . message : "Failed to list feedback" } , 500 ) ;
632663 }
633664 } ) ;
634665
666+ // ---------------------------------------------------------------------------
667+ // GET /api/stats - Registry statistics
668+ // ---------------------------------------------------------------------------
669+
670+ app . get ( "/api/stats" , async ( c ) => {
671+ const network = getNetwork ( c . req . query ( "network" ) ) ;
672+
673+ try {
674+ const sati = createSatiClient ( network , env ) ;
675+ const stats = await sati . getRegistryStats ( ) ;
676+
677+ return c . json ( {
678+ totalAgents : Number ( stats . totalAgents ) ,
679+ groupMint : stats . groupMint ,
680+ authority : stats . authority ,
681+ isImmutable : stats . isImmutable ,
682+ } ) ;
683+ } catch ( error ) {
684+ console . error ( "[stats] ERROR:" , error ) ;
685+ return c . json ( { error : error instanceof Error ? error . message : "Failed to get stats" } , 500 ) ;
686+ }
687+ } ) ;
688+
635689 // ---------------------------------------------------------------------------
636690 // POST /api/feedback - Give feedback (free, server signs as counterparty)
637691 // ---------------------------------------------------------------------------
@@ -670,12 +724,17 @@ export function createIdentityApi(env: Env) {
670724 const serverPayer = await createKeyPairSignerFromBytes ( signerBytes ) ;
671725 const counterpartyAddress = serverPayer . address ;
672726
727+ // Map outcome number to enum (0=Negative, 1=Neutral, 2=Positive)
728+ const outcomeValue =
729+ body . outcome === 0 ? OutcomeEnum . Negative : body . outcome === 2 ? OutcomeEnum . Positive : OutcomeEnum . Neutral ;
730+
673731 // Build content JSON (ERC-8004 format) using SDK helper
674732 const contentBytes = buildFeedbackContent ( {
675733 value : body . value ,
676734 valueDecimals : body . valueDecimals ?? 0 ,
677735 tag1 : body . tag1 ,
678736 tag2 : body . tag2 ,
737+ message : body . message ,
679738 endpoint : body . endpoint ,
680739 reviewer : body . reviewerAddress ,
681740 feedbackURI : body . feedbackURI ,
@@ -692,7 +751,7 @@ export function createIdentityApi(env: Env) {
692751 agentMint : body . agentMint as Address ,
693752 counterparty : counterpartyAddress ,
694753 dataHash,
695- outcome : OutcomeEnum . Neutral ,
754+ outcome : outcomeValue ,
696755 contentType : ContentType . JSON ,
697756 content : contentBytes ,
698757 } ;
@@ -719,7 +778,7 @@ export function createIdentityApi(env: Env) {
719778 agentMint : body . agentMint as Address ,
720779 counterparty : counterpartyAddress ,
721780 dataHash,
722- outcome : OutcomeEnum . Neutral ,
781+ outcome : outcomeValue ,
723782 agentSignature : {
724783 pubkey : counterpartyAddress ,
725784 signature : counterpartySignature ,
0 commit comments