Monorepo for Tangled
0

Configure Feed

Select the types of activity you want to include in your feed.

web/src/routes: grab vouches from both directions

Signed-off-by: oppiliappan <me@oppi.li>

oppiliappan (Jul 15, 2026, 11:02 AM +0100) 04d93c9e 661bb86c

+40 -22
+40 -22
web/src/routes/[handle]/+page.ts
··· 141 141 did, 142 142 doc 143 143 ? { 144 - did: doc.did, 145 - handle: doc.handle, 146 - avatar: doc.avatar, 147 - followers, 148 - following, 149 - isSelf, 150 - viewerFollowRkey 151 - } 144 + did: doc.did, 145 + handle: doc.handle, 146 + avatar: doc.avatar, 147 + followers, 148 + following, 149 + isSelf, 150 + viewerFollowRkey 151 + } 152 152 : { did, handle: did, followers, following, isSelf, viewerFollowRkey } 153 153 ); 154 154 }); 155 155 return unique.map((did) => byDid.get(did) as PersonData); 156 156 }; 157 157 158 - const resolveVouches = async (ctx: BobbinContext, items: ListItem[]): Promise<VouchData[]> => { 158 + const resolveVouches = async ( 159 + ctx: BobbinContext, 160 + items: ListItem[], 161 + direction: "incoming" | "outgoing" 162 + ): Promise<VouchData[]> => { 159 163 const cache = new IdentityCache(ctx); 160 164 return Promise.all( 161 165 items.map(async (item): Promise<VouchData> => { 162 166 const value = item.value as VouchRecord; 163 - const voucher = didFromUri(item.uri); 164 - const doc = await cache.resolve(voucher).catch(() => null); 167 + const otherDid = 168 + direction === "incoming" ? didFromUri(item.uri) : rkeyFromUri(item.uri); 169 + const doc = await cache.resolve(otherDid).catch(() => null); 165 170 return { 166 171 uri: item.uri, 167 - did: voucher, 168 - handle: doc?.handle ?? voucher, 172 + did: otherDid, 173 + handle: doc?.handle ?? otherDid, 169 174 avatar: doc?.avatar, 170 175 kind: value.kind === "denounce" ? "denounce" : "vouch", 176 + direction, 171 177 reason: value.reason, 172 178 createdAt: value.createdAt 173 179 }; ··· 234 240 const [found, viewerStarRkeys] = await Promise.all([ 235 241 q 236 242 ? search(ctx, { q, nsid: "sh.tangled.repo", author: did, limit: PAGE_LIMIT }).then( 237 - (page) => page.hits 238 - ) 243 + (page) => page.hits 244 + ) 239 245 : fetchPage(ctx, "sh.tangled.repo.listRepos", { subject: did, limit: PAGE_LIMIT }).then( 240 - (page) => page.items 241 - ), 246 + (page) => page.items 247 + ), 242 248 parent.auth?.did ? listStarRkeys(ctx, parent.auth.did) : undefined 243 249 ]); 244 250 return { ··· 278 284 }; 279 285 } 280 286 case "vouches": { 281 - const page = await fetchPage(ctx, "sh.tangled.graph.listVouches", { 282 - subject: did, 283 - limit: PAGE_LIMIT 284 - }); 285 - return { tab, vouches: await resolveVouches(ctx, page.items) }; 287 + const [incomingPage, outgoingPage] = await Promise.all([ 288 + fetchPage(ctx, "sh.tangled.graph.listVouches", { subject: did, limit: PAGE_LIMIT }), 289 + fetchPage(ctx, "sh.tangled.graph.listVouchesBy", { subject: did, limit: PAGE_LIMIT }) 290 + ]); 291 + const [incoming, outgoing] = await Promise.all([ 292 + resolveVouches(ctx, incomingPage.items, "incoming"), 293 + resolveVouches(ctx, outgoingPage.items, "outgoing") 294 + ]); 295 + const vouches = [...incoming, ...outgoing].sort( 296 + (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() 297 + ); 298 + return { 299 + tab, 300 + vouches, 301 + isSelf: parent.auth?.did === did, 302 + profileHandle: handle 303 + }; 286 304 } 287 305 case "starred": { 288 306 const [page, viewerStarRkeys] = await Promise.all([