+25
deno.lock
+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
+2
-1
package.json
+3
-3
src/lib/PostComponent.svelte
+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
+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 };