this repo has no description

Handle resolution

ari.express e9507880 6628b3d0

verified
+25
deno.lock
··· 3 3 "specifiers": { 4 4 "npm:@atcute/bluesky@^2.0.2": "2.0.2_@atcute+client@3.0.1", 5 5 "npm:@atcute/client@^3.0.1": "3.0.1", 6 + "npm:@atcute/identity-resolver@~0.1.2": "0.1.2_@atcute+identity@0.1.3", 6 7 "npm:@sveltejs/vite-plugin-svelte@^5.0.3": "5.0.3_svelte@5.28.1__acorn@8.14.1_vite@6.3.2__picomatch@4.0.2", 7 8 "npm:@tsconfig/svelte@^5.0.4": "5.0.4", 8 9 "npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3", ··· 26 27 }, 27 28 "@atcute/client@3.0.1": { 28 29 "integrity": "sha512-j51SuQYQj5jeKrx1DCXx+Q3fpVvO0JYGnKnJAdDSlesSLjPXjvnx1abC+hkuro58KRHHJvRA6P1MC0pmJsWfcg==" 30 + }, 31 + "@atcute/identity-resolver@0.1.2_@atcute+identity@0.1.3": { 32 + "integrity": "sha512-fP2VbHD04kVcCdNi/Kszo6jFzqM7Pg3p33oGhfp2zVkwFKaVBlwCaFRWEga/Xvu/IDLwNdASGWnLqoA34SFeSg==", 33 + "dependencies": [ 34 + "@atcute/identity", 35 + "@atcute/util-fetch", 36 + "@badrap/valita" 37 + ] 38 + }, 39 + "@atcute/identity@0.1.3": { 40 + "integrity": "sha512-ndlD8nypHt8G00wixbozKdSNL0O8HTzBjFGEXeAcBUCXSZPBjRWbqtgyJxhgUWnr7swgxgw1mSbZwRB5b7xCiQ==", 41 + "dependencies": [ 42 + "@badrap/valita" 43 + ] 44 + }, 45 + "@atcute/util-fetch@1.0.1": { 46 + "integrity": "sha512-Clc0E/5ufyGBVfYBUwWNlHONlZCoblSr4Ho50l1LhmRPGB1Wu/AQ9Sz+rsBg7fdaW/auve8ulmwhRhnX2cGRow==", 47 + "dependencies": [ 48 + "@badrap/valita" 49 + ] 50 + }, 51 + "@badrap/valita@0.4.4": { 52 + "integrity": "sha512-GEhUCk9c4XbNxi+0YZHZsV4fYNd6HejfWuN4Ti4c02DauX+LyX5WY1Y3WfyZ8Pxxl0zqhs+MLtW98cMh86vv6g==" 29 53 }, 30 54 "@esbuild/aix-ppc64@0.25.2": { 31 55 "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==" ··· 443 467 "dependencies": [ 444 468 "npm:@atcute/bluesky@^2.0.2", 445 469 "npm:@atcute/client@^3.0.1", 470 + "npm:@atcute/identity-resolver@~0.1.2", 446 471 "npm:@sveltejs/vite-plugin-svelte@^5.0.3", 447 472 "npm:@tsconfig/svelte@^5.0.4", 448 473 "npm:svelte-check@^4.1.5",
+2 -1
package.json
··· 11 11 }, 12 12 "dependencies": { 13 13 "@atcute/bluesky": "^2.0.2", 14 - "@atcute/client": "^3.0.1" 14 + "@atcute/client": "^3.0.1", 15 + "@atcute/identity-resolver": "^0.1.2" 15 16 }, 16 17 "devDependencies": { 17 18 "@sveltejs/vite-plugin-svelte": "^5.0.3",
+3 -3
src/lib/PostComponent.svelte
··· 12 12 src="https://pds.witchcraft.systems/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.authorAvatarCid}" 13 13 /> 14 14 {/if} 15 - <p>{post.displayName} | {post.timenotstamp}</p> 15 + <p>{post.displayName} | {post.authorHandle} | {post.timenotstamp}</p> 16 16 </div> 17 17 <div id="postContent"> 18 18 <p>{post.text}</p> 19 - {#if post.replyingDid} 20 - <p>Replying to: {post.replyingDid}</p> 19 + {#if post.replyingUri} 20 + <p>Replying to: {post.replyingUri.repo}</p> 21 21 {/if} 22 22 {#if post.imagesCid} 23 23 <div id="imagesContainer">
+62 -12
src/lib/pdsfetch.ts
··· 7 7 At, 8 8 ComAtprotoRepoListRecords, 9 9 } from "@atcute/client/lexicons"; 10 - import type App from "../App.svelte"; 11 - // import { ComAtprotoRepoListRecords.Record } from "@atcute/client/lexicons"; 12 - // import { AppBskyFeedPost } from "@atcute/client/lexicons"; 13 - // import { AppBskyActorDefs } from "@atcute/client/lexicons"; 10 + import { 11 + CompositeDidDocumentResolver, 12 + PlcDidDocumentResolver, 13 + WebDidDocumentResolver, 14 + } from "@atcute/identity-resolver"; 14 15 15 16 interface AccountMetadata { 16 17 did: string; 17 18 displayName: string; 19 + handle: string; 18 20 avatarCid: string | null; 19 21 } 22 + interface atUriObject { 23 + repo: string; 24 + collection: string; 25 + rkey: string; 26 + } 20 27 class Post { 21 28 authorDid: string; 22 29 authorAvatarCid: string | null; 30 + authorHandle: string; 23 31 displayName: string; 24 32 text: string; 25 33 timestamp: number; 26 34 timenotstamp: string; 27 - quotingDid: string | null; 28 - replyingDid: string | null; 35 + quotingUri: atUriObject | null; 36 + replyingUri: atUriObject | null; 29 37 imagesCid: string[] | null; 30 38 videosLinkCid: string | null; 31 39 ··· 35 43 ) { 36 44 this.authorDid = account.did; 37 45 this.authorAvatarCid = account.avatarCid; 46 + this.authorHandle = account.handle; 38 47 this.displayName = account.displayName; 39 48 const post = record.value as AppBskyFeedPost.Record; 40 49 this.timenotstamp = post.createdAt; 41 50 this.text = post.text; 42 51 this.timestamp = Date.parse(post.createdAt); 43 52 if (post.reply) { 44 - this.replyingDid = didFromATuri(post.reply.parent.uri).repo; 53 + this.replyingUri = processAtUri(post.reply.parent.uri); 45 54 } else { 46 - this.replyingDid = null; 55 + this.replyingUri = null; 47 56 } 48 - this.quotingDid = null; 57 + this.quotingUri = null; 49 58 this.imagesCid = null; 50 59 this.videosLinkCid = null; 51 60 switch (post.embed?.$type) { ··· 58 67 this.videosLinkCid = post.embed.video.ref.$link; 59 68 break; 60 69 case "app.bsky.embed.record": 61 - this.quotingDid = didFromATuri(post.embed.record.uri).repo; 70 + this.quotingUri = processAtUri(post.embed.record.uri); 62 71 break; 63 72 case "app.bsky.embed.recordWithMedia": 64 - this.quotingDid = didFromATuri(post.embed.record.record.uri).repo; 73 + this.quotingUri = processAtUri(post.embed.record.record.uri); 65 74 switch (post.embed.media.$type) { 66 75 case "app.bsky.embed.images": 67 76 this.imagesCid = post.embed.media.images.map((imageRecord) => ··· 79 88 } 80 89 } 81 90 82 - const didFromATuri = (aturi: string) => { 91 + const processAtUri = (aturi: string): atUriObject => { 83 92 const parts = aturi.split("/"); 84 93 return { 85 94 repo: parts[2], ··· 110 119 }, 111 120 }); 112 121 const value = data.value as AppBskyActorProfile.Record; 122 + const handle = await blueskyHandleFromDid(did); 113 123 const account: AccountMetadata = { 114 124 did: did, 125 + handle: handle, 115 126 displayName: value.displayName || "", 116 127 avatarCid: null, 117 128 }; ··· 145 156 }; 146 157 }; 147 158 159 + const identityResolve = async (did: At.Did) => { 160 + const resolver = new CompositeDidDocumentResolver({ 161 + methods: { 162 + plc: new PlcDidDocumentResolver(), 163 + web: new WebDidDocumentResolver(), 164 + }, 165 + }); 166 + 167 + if (did.startsWith("did:plc:") || did.startsWith("did:web:")) { 168 + const doc = await resolver.resolve( 169 + did as `did:plc:${string}` | `did:web:${string}`, 170 + ); 171 + return doc; 172 + } else { 173 + throw new Error(`Unsupported DID type: ${did}`); 174 + } 175 + }; 176 + 177 + const blueskyHandleFromDid = async (did: At.Did) => { 178 + const doc = await identityResolve(did); 179 + if (doc.alsoKnownAs) { 180 + const handleAtUri = doc.alsoKnownAs.find((url) => url.startsWith("at://")); 181 + const handle = handleAtUri?.split("/")[2]; 182 + if (!handle) { 183 + return "Handle not found"; 184 + } else { 185 + return handle; 186 + } 187 + } else { 188 + return "Handle not found"; 189 + } 190 + }; 191 + 148 192 const fetchAllPosts = async () => { 149 193 const users: AccountMetadata[] = await getAllMetadataFromPds(); 150 194 const postRecords = await Promise.all( ··· 167 211 return posts; 168 212 }; 169 213 214 + const testApiCall = async () => { 215 + const { data } = await rpc.get("com.atproto.sync.listRepos", { 216 + params: {}, 217 + }); 218 + console.log(data); 219 + }; 170 220 export { fetchAllPosts, getAllMetadataFromPds, Post }; 171 221 export type { AccountMetadata };