its for when you want to get like notifications for your reposts
1import { XrpcHandleResolver } from "@atcute/identity-resolver"; 2import { isDid, isHandle } from "@atcute/lexicons/syntax"; 3import { ConnectionStatus, Notification } from "./types.ts"; 4 5export interface Data { 6 setError: (error: string | null) => void; 7 setConnectionStatus: (status: ConnectionStatus) => void; 8 pushNotification: (item: Notification) => void; 9 actorId: string; 10 serviceDomain: string; 11 doRetry?: () => number | null; 12} 13 14const handleResolver = new XrpcHandleResolver({ 15 serviceUrl: "https://public.api.bsky.app", 16}); 17 18export const connect = async (cb: Data) => { 19 const didOrHandle = cb.actorId.trim(); 20 const host = cb.serviceDomain.trim(); 21 22 cb.setError(null); 23 cb.setConnectionStatus("connecting..."); 24 25 let did: string; 26 if (!didOrHandle) { 27 cb.setConnectionStatus("error"); 28 cb.setError("please enter a DID or a handle"); 29 return; 30 } else if (isHandle(didOrHandle)) { 31 try { 32 did = await handleResolver.resolve(didOrHandle); 33 } catch (error) { 34 cb.setConnectionStatus("error"); 35 cb.setError(`can't resolve handle: ${error}`); 36 return; 37 } 38 } else if (isDid(didOrHandle)) { 39 did = didOrHandle; 40 } else { 41 cb.setConnectionStatus("error"); 42 cb.setError("inputted DID / handle is not valid"); 43 return; 44 } 45 46 if (!host) { 47 cb.setError("please enter service host"); 48 cb.setConnectionStatus("error"); 49 return; 50 } 51 52 let proto = "wss"; 53 const domain = host.split(":").at(0) ?? ""; 54 if (["localhost", "0.0.0.0", "127.0.0.1"].some((v) => v === domain)) { 55 proto = "ws"; 56 } 57 58 const url = `${proto}://${host}/subscribe/${did}`; 59 60 try { 61 let ws = new WebSocket(url); 62 63 ws.onopen = () => { 64 cb.setConnectionStatus("connected"); 65 cb.setError(null); 66 console.log("WebSocket connected to:", url); 67 }; 68 69 ws.onmessage = (event: MessageEvent) => { 70 try { 71 cb.pushNotification(JSON.parse(event.data)); 72 } catch (error) { 73 console.error("Error parsing JSON:", error); 74 } 75 }; 76 77 ws.onclose = (ev) => { 78 cb.setConnectionStatus("disconnected"); 79 console.log("WebSocket disconnected"); 80 // abnormal closure 81 if (ev.code === 1006) { 82 cb.setConnectionStatus("error"); 83 const backoff = (cb.doRetry ?? (() => null))(); 84 if (backoff) { 85 cb.setError(`websocket closed abnormally: (${ev.code}) ${ev.reason}`); 86 setTimeout(() => connect(cb), backoff); 87 } 88 } else if (ev.code === 1000 || ev.code === 1001 || ev.code === 1005) { 89 cb.setError(null); 90 } else { 91 cb.setConnectionStatus("error"); 92 cb.setError(`websocket failed: (${ev.code}) ${ev.reason}`); 93 } 94 }; 95 96 ws.onerror = (error: Event) => { 97 cb.setConnectionStatus("error"); 98 cb.setError("connection failed"); 99 console.error("WebSocket error:", error); 100 }; 101 102 return ws; 103 } catch (error) { 104 cb.setConnectionStatus("error"); 105 cb.setError(`failed to create connection: ${error}`); 106 console.error("Failed to create WebSocket:", error); 107 } 108 109 return; 110}; 111 112export default connect;