11import { validateResourceId } from "../feedback/resources.js" ;
22import type { Resource } from "../feedback/resources.js" ;
3- import type { Vote , VoteResult } from "../protocol/github.js" ;
3+ import type { ViewerVote , Vote , VoteResult } from "../protocol/github.js" ;
44
5- export interface ReactionState {
5+ interface CounterState {
66 id : string | null ;
77 up : number ;
88 down : number ;
99 age : number ;
1010 stale : boolean ;
1111}
1212
13+ export interface ReactionState extends CounterState {
14+ viewer : ViewerVote ;
15+ }
16+
1317interface ReactionEnvelope {
1418 v : 1 ;
1519 site : string ;
16- items : Record < string , ReactionState > ;
20+ items : Record < string , CounterState > ;
1721}
1822
1923export interface ClientOptions {
@@ -86,9 +90,10 @@ export class FeedbackClient {
8690 const result = new Map < string , ReactionState > ( ) ;
8791 for ( const key of normalized ) {
8892 const state = payload . items [ key ] ?? emptyState ( ) ;
89- if ( ! isReactionState ( state ) ) throw new TypeError ( "Invalid feedback service response" ) ;
90- result . set ( key , state ) ;
91- this . #storeReaction( key , state ) ;
93+ if ( ! isCounterState ( state ) ) throw new TypeError ( "Invalid feedback service response" ) ;
94+ const combined = { ...state , viewer : this . #cachedReaction( key ) ?. viewer ?? "none" } ;
95+ result . set ( key , combined ) ;
96+ this . #storeReaction( key , combined ) ;
9297 }
9398 return result ;
9499 }
@@ -168,6 +173,7 @@ export class FeedbackClient {
168173 down : result . down ,
169174 age : 0 ,
170175 stale : true ,
176+ viewer : result . viewer ,
171177 } ) ;
172178 return result ;
173179 }
@@ -239,7 +245,7 @@ export class FeedbackError extends Error {
239245}
240246
241247function emptyState ( ) : ReactionState {
242- return { id : null , up : 0 , down : 0 , age : 0 , stale : false } ;
248+ return { id : null , up : 0 , down : 0 , age : 0 , stale : false , viewer : "none" } ;
243249}
244250
245251function isEnvelope ( value : unknown , site : string ) : value is ReactionEnvelope {
@@ -248,7 +254,7 @@ function isEnvelope(value: unknown, site: string): value is ReactionEnvelope {
248254 return candidate . v === 1 && candidate . site === site && ! ! candidate . items && typeof candidate . items === "object" ;
249255}
250256
251- function isReactionState ( value : unknown ) : value is ReactionState {
257+ function isCounterState ( value : unknown ) : value is CounterState {
252258 if ( ! value || typeof value !== "object" ) return false ;
253259 const state = value as Partial < ReactionState > ;
254260 return (
@@ -260,6 +266,14 @@ function isReactionState(value: unknown): value is ReactionState {
260266 ) ;
261267}
262268
269+ function isReactionState ( value : unknown ) : value is ReactionState {
270+ return isCounterState ( value ) && isViewerVote ( ( value as Partial < ReactionState > ) . viewer ) ;
271+ }
272+
273+ function isViewerVote ( value : unknown ) : value is ViewerVote {
274+ return value === "up" || value === "down" || value === "both" || value === "none" ;
275+ }
276+
263277function counterKey ( site : string , resource : string ) : string {
264278 return `cppsocial.feedback.v1.${ site } .reaction.${ resource } ` ;
265279}
0 commit comments