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 backoff?: number; 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 && cb.backoff) { 82 cb.setConnectionStatus("error"); 83 cb.setError(`websocket closed abnormally: (${ev.code}) ${ev.reason}`); 84 const newData = { backoff: cb.backoff * 2, ...cb }; 85 setTimeout(() => connect(newData), cb.backoff); 86 } else if (ev.code === 1000 || ev.code === 1001 || ev.code === 1005) { 87 cb.setError(null); 88 } else { 89 cb.setConnectionStatus("error"); 90 cb.setError(`websocket failed: (${ev.code}) ${ev.reason}`); 91 } 92 }; 93 94 ws.onerror = (error: Event) => { 95 cb.setConnectionStatus("error"); 96 cb.setError("connection failed"); 97 console.error("WebSocket error:", error); 98 }; 99 100 return ws; 101 } catch (error) { 102 cb.setConnectionStatus("error"); 103 cb.setError(`failed to create connection: ${error}`); 104 console.error("Failed to create WebSocket:", error); 105 } 106 107 return; 108}; 109 110export default connect;