A Vue app that displays bluesky skeets in realtime as they are created.
1import type { WebsocketMessage } from '@/types/message'
2import type { Post } from '@/types/post'
3
4/**
5 * Converts a raw WebSocket message into a `FeedEntry` object, if possible.
6 *
7 * This function checks if the incoming WebSocket data is structured like a feed commit message
8 * with the required properties for a created post. If the data matches the expected shape,
9 * it extracts and returns a `FeedEntry` object. Otherwise, it returns `null`.
10 *
11 * @param data - The raw WebSocket data.
12 * @returns A `FeedEntry` object if the data represents a newly created post, otherwise `null`.
13 */
14export function websocketToFeedEntry(data: unknown): Post | null {
15 const wsData = JSON.parse(data as string) as WebsocketMessage
16 const message = wsData.message
17 const metaData = wsData.hydrated_metadata
18 if (
19 !message.commit ||
20 !message.commit.record ||
21 !message.commit.record['$type'] ||
22 !message.did ||
23 !message.commit.cid ||
24 !message.commit.rkey ||
25 message.commit.operation !== 'create'
26 ) {
27 return null
28 }
29 const messageUri = `at://${message.did}/${message.commit.record['$type']}/${message.commit.rkey}`
30 return {
31 cid: message.commit.cid,
32 uri: messageUri,
33 authorDid: message.did,
34 authorHandle: metaData.user.handle,
35 authorAvatar: metaData.user.avatar,
36 authorBanner: metaData.user.banner,
37 text: message.commit.record.text,
38 embed: message.commit.record.embed,
39 rootCid: message.commit.record.reply?.root.cid ?? message.commit.cid,
40 rootUri: message.commit.record.reply?.root.uri ?? messageUri,
41 }
42}