+25
deno.lock
+25
deno.lock
···
3
"specifiers": {
4
"npm:@atcute/bluesky@^2.0.2": "2.0.2_@atcute+client@3.0.1",
5
"npm:@atcute/client@^3.0.1": "3.0.1",
6
"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
"npm:@tsconfig/svelte@^5.0.4": "5.0.4",
8
"npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3",
···
26
},
27
"@atcute/client@3.0.1": {
28
"integrity": "sha512-j51SuQYQj5jeKrx1DCXx+Q3fpVvO0JYGnKnJAdDSlesSLjPXjvnx1abC+hkuro58KRHHJvRA6P1MC0pmJsWfcg=="
29
},
30
"@esbuild/aix-ppc64@0.25.2": {
31
"integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag=="
···
443
"dependencies": [
444
"npm:@atcute/bluesky@^2.0.2",
445
"npm:@atcute/client@^3.0.1",
446
"npm:@sveltejs/vite-plugin-svelte@^5.0.3",
447
"npm:@tsconfig/svelte@^5.0.4",
448
"npm:svelte-check@^4.1.5",
···
3
"specifiers": {
4
"npm:@atcute/bluesky@^2.0.2": "2.0.2_@atcute+client@3.0.1",
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",
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",
8
"npm:@tsconfig/svelte@^5.0.4": "5.0.4",
9
"npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3",
···
27
},
28
"@atcute/client@3.0.1": {
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=="
53
},
54
"@esbuild/aix-ppc64@0.25.2": {
55
"integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag=="
···
467
"dependencies": [
468
"npm:@atcute/bluesky@^2.0.2",
469
"npm:@atcute/client@^3.0.1",
470
+
"npm:@atcute/identity-resolver@~0.1.2",
471
"npm:@sveltejs/vite-plugin-svelte@^5.0.3",
472
"npm:@tsconfig/svelte@^5.0.4",
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
src="https://pds.witchcraft.systems/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.authorAvatarCid}"
13
/>
14
{/if}
15
-
<p>{post.displayName} | {post.timenotstamp}</p>
16
</div>
17
<div id="postContent">
18
<p>{post.text}</p>
19
-
{#if post.replyingDid}
20
-
<p>Replying to: {post.replyingDid}</p>
21
{/if}
22
{#if post.imagesCid}
23
<div id="imagesContainer">
···
12
src="https://pds.witchcraft.systems/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.authorAvatarCid}"
13
/>
14
{/if}
15
+
<p>{post.displayName} | {post.authorHandle} | {post.timenotstamp}</p>
16
</div>
17
<div id="postContent">
18
<p>{post.text}</p>
19
+
{#if post.replyingUri}
20
+
<p>Replying to: {post.replyingUri.repo}</p>
21
{/if}
22
{#if post.imagesCid}
23
<div id="imagesContainer">
+62
-12
src/lib/pdsfetch.ts
+62
-12
src/lib/pdsfetch.ts
···
7
At,
8
ComAtprotoRepoListRecords,
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";
14
15
interface AccountMetadata {
16
did: string;
17
displayName: string;
18
avatarCid: string | null;
19
}
20
class Post {
21
authorDid: string;
22
authorAvatarCid: string | null;
23
displayName: string;
24
text: string;
25
timestamp: number;
26
timenotstamp: string;
27
-
quotingDid: string | null;
28
-
replyingDid: string | null;
29
imagesCid: string[] | null;
30
videosLinkCid: string | null;
31
···
35
) {
36
this.authorDid = account.did;
37
this.authorAvatarCid = account.avatarCid;
38
this.displayName = account.displayName;
39
const post = record.value as AppBskyFeedPost.Record;
40
this.timenotstamp = post.createdAt;
41
this.text = post.text;
42
this.timestamp = Date.parse(post.createdAt);
43
if (post.reply) {
44
-
this.replyingDid = didFromATuri(post.reply.parent.uri).repo;
45
} else {
46
-
this.replyingDid = null;
47
}
48
-
this.quotingDid = null;
49
this.imagesCid = null;
50
this.videosLinkCid = null;
51
switch (post.embed?.$type) {
···
58
this.videosLinkCid = post.embed.video.ref.$link;
59
break;
60
case "app.bsky.embed.record":
61
-
this.quotingDid = didFromATuri(post.embed.record.uri).repo;
62
break;
63
case "app.bsky.embed.recordWithMedia":
64
-
this.quotingDid = didFromATuri(post.embed.record.record.uri).repo;
65
switch (post.embed.media.$type) {
66
case "app.bsky.embed.images":
67
this.imagesCid = post.embed.media.images.map((imageRecord) =>
···
79
}
80
}
81
82
-
const didFromATuri = (aturi: string) => {
83
const parts = aturi.split("/");
84
return {
85
repo: parts[2],
···
110
},
111
});
112
const value = data.value as AppBskyActorProfile.Record;
113
const account: AccountMetadata = {
114
did: did,
115
displayName: value.displayName || "",
116
avatarCid: null,
117
};
···
145
};
146
};
147
148
const fetchAllPosts = async () => {
149
const users: AccountMetadata[] = await getAllMetadataFromPds();
150
const postRecords = await Promise.all(
···
167
return posts;
168
};
169
170
export { fetchAllPosts, getAllMetadataFromPds, Post };
171
export type { AccountMetadata };
···
7
At,
8
ComAtprotoRepoListRecords,
9
} from "@atcute/client/lexicons";
10
+
import {
11
+
CompositeDidDocumentResolver,
12
+
PlcDidDocumentResolver,
13
+
WebDidDocumentResolver,
14
+
} from "@atcute/identity-resolver";
15
16
interface AccountMetadata {
17
did: string;
18
displayName: string;
19
+
handle: string;
20
avatarCid: string | null;
21
}
22
+
interface atUriObject {
23
+
repo: string;
24
+
collection: string;
25
+
rkey: string;
26
+
}
27
class Post {
28
authorDid: string;
29
authorAvatarCid: string | null;
30
+
authorHandle: string;
31
displayName: string;
32
text: string;
33
timestamp: number;
34
timenotstamp: string;
35
+
quotingUri: atUriObject | null;
36
+
replyingUri: atUriObject | null;
37
imagesCid: string[] | null;
38
videosLinkCid: string | null;
39
···
43
) {
44
this.authorDid = account.did;
45
this.authorAvatarCid = account.avatarCid;
46
+
this.authorHandle = account.handle;
47
this.displayName = account.displayName;
48
const post = record.value as AppBskyFeedPost.Record;
49
this.timenotstamp = post.createdAt;
50
this.text = post.text;
51
this.timestamp = Date.parse(post.createdAt);
52
if (post.reply) {
53
+
this.replyingUri = processAtUri(post.reply.parent.uri);
54
} else {
55
+
this.replyingUri = null;
56
}
57
+
this.quotingUri = null;
58
this.imagesCid = null;
59
this.videosLinkCid = null;
60
switch (post.embed?.$type) {
···
67
this.videosLinkCid = post.embed.video.ref.$link;
68
break;
69
case "app.bsky.embed.record":
70
+
this.quotingUri = processAtUri(post.embed.record.uri);
71
break;
72
case "app.bsky.embed.recordWithMedia":
73
+
this.quotingUri = processAtUri(post.embed.record.record.uri);
74
switch (post.embed.media.$type) {
75
case "app.bsky.embed.images":
76
this.imagesCid = post.embed.media.images.map((imageRecord) =>
···
88
}
89
}
90
91
+
const processAtUri = (aturi: string): atUriObject => {
92
const parts = aturi.split("/");
93
return {
94
repo: parts[2],
···
119
},
120
});
121
const value = data.value as AppBskyActorProfile.Record;
122
+
const handle = await blueskyHandleFromDid(did);
123
const account: AccountMetadata = {
124
did: did,
125
+
handle: handle,
126
displayName: value.displayName || "",
127
avatarCid: null,
128
};
···
156
};
157
};
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
+
192
const fetchAllPosts = async () => {
193
const users: AccountMetadata[] = await getAllMetadataFromPds();
194
const postRecords = await Promise.all(
···
211
return posts;
212
};
213
214
+
const testApiCall = async () => {
215
+
const { data } = await rpc.get("com.atproto.sync.listRepos", {
216
+
params: {},
217
+
});
218
+
console.log(data);
219
+
};
220
export { fetchAllPosts, getAllMetadataFromPds, Post };
221
export type { AccountMetadata };