data endpoint for entity 90008 (aka. a website)
0
fork

Configure Feed

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

at svelte 115 lines 3.2 kB view raw
1import { env } from '$env/dynamic/private'; 2import { AppBskyFeedPost } from '@atcute/bluesky'; 3 4import { Client, CredentialManager, ok, simpleFetchHandler } from '@atcute/client'; 5import { parse, type CanonicalResourceUri, type Did } from '@atcute/lexicons'; 6import { get, writable } from 'svelte/store'; 7 8export const PDS_URL = 'https://gaze.systems'; 9export const IDENTIFIER = 'did:web:guestbook.gaze.systems'; 10 11const constellationClient = new Client({ 12 handler: simpleFetchHandler({ service: 'https://constellation.microcosm.blue' }) 13}); 14const userClient = new Client({ 15 handler: simpleFetchHandler({ service: 'https://zwsp.xyz' }) 16}); 17const guestbookClient = writable<null | Client>(null); 18 19export type Post = { 20 record: AppBskyFeedPost.Main; 21 uri: CanonicalResourceUri; 22}; 23 24export const getGuestbookClient = async () => { 25 try { 26 let client = get(guestbookClient); 27 if (client === null) { 28 client = await loginToBsky(); 29 guestbookClient.set(client); 30 } 31 return client; 32 } catch (e) { 33 throw `cant login to bsky: ${e}`; 34 } 35}; 36 37const loginToBsky = async () => { 38 const password = env.BSKY_PASSWORD ?? null; 39 if (password === null) { 40 throw new Error('no password provided'); 41 } 42 const handler = new CredentialManager({ service: PDS_URL }); 43 const rpc = new Client({ handler }); 44 await handler.login({ identifier: IDENTIFIER, password }); 45 return rpc; 46}; 47 48export const getUserPosts = async ( 49 client: Client, 50 repo: Did, 51 count: number = 10, 52 cursor?: string 53) => { 54 const posts: Post[] = []; 55 // fetch requested amount of posts 56 while (posts.length < count - 1) { 57 const fetched = ok( 58 await client.get('com.atproto.repo.listRecords', { 59 params: { repo, collection: 'app.bsky.feed.post', cursor, limit: count } 60 }) 61 ); 62 for (const record of fetched.records) { 63 const post = parse(AppBskyFeedPost.mainSchema, record.value); 64 if (post.reply) continue; 65 posts.push({ 66 record: post, 67 uri: record.uri as CanonicalResourceUri 68 }); 69 } 70 cursor = fetched.cursor; 71 if (cursor === undefined) { 72 break; 73 } 74 } 75 return { posts: posts.slice(0, count), cursor }; 76}; 77 78const lastPosts = writable<Post[]>([]); 79 80export const updateLastPosts = async () => { 81 try { 82 const { posts } = await getUserPosts(userClient, 'did:plc:dfl62fgb7wtjj3fcbb72naae', 10); 83 lastPosts.set(posts); 84 } catch (err) { 85 console.log(`can't update last posts ${err}`); 86 } 87}; 88 89export const getLastPosts = () => { 90 return get(lastPosts); 91}; 92 93export const getReplies = async (client: Client, postUri: CanonicalResourceUri, forDid?: Did) => { 94 // todo: do cursor stuff here later if it matters 95 const backlinks = ok( 96 await constellationClient.get('blue.microcosm.links.getBacklinks', { 97 params: { 98 did: forDid ? [forDid] : [], 99 subject: postUri, 100 source: 'app.bsky.feed.post:reply.parent.uri' 101 } 102 }) 103 ); 104 const replies: Post[] = []; 105 for (const record of backlinks.records) { 106 const fetched = ok( 107 await client.get('com.atproto.repo.getRecord', { 108 params: { repo: record.did, collection: record.collection, rkey: record.rkey } 109 }) 110 ); 111 const post = parse(AppBskyFeedPost.mainSchema, fetched.value); 112 replies.push({ record: post, uri: fetched.uri as CanonicalResourceUri }); 113 } 114 return replies; 115};