A work-in-progress chat bot for Streamplace with chat overlay functionality
2
fork

Configure Feed

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

Filtering by wantedCollections, error handling in eventHandler, comprehensive error logging

+33 -4
+9
main.ts
··· 15 15 export const botInstances: Map<Did, StreamplaceBot> = new Map(); 16 16 export const followerAtUris: Map<Did, string> = new Map(); 17 17 18 + // Logging unhandled rejections and uncaught errors 19 + globalThis.addEventListener("unhandledrejection", (event) => { 20 + console.error("Unhandled rejection — this may crash the server:"); 21 + console.error(event.reason); 22 + }); 23 + globalThis.addEventListener("error", (event) => { 24 + console.error("Uncaught error:", event.message, event.error); 25 + }); 26 + 18 27 // Initialize for self 19 28 export const atprotoClient = new AtprotoClient(BOT_CREDENTIALS, BOT_SERVICE); 20 29 const botDid = isHandle(BOT_CREDENTIALS.identifier)
+9 -3
utils/eventHandler.ts
··· 31 31 this.handleActorProfile(event); 32 32 break; 33 33 case "app.bsky.graph.follow": 34 - this.handleBskyFollow(event); 34 + this.handleBskyFollow(event).catch(err => 35 + console.error("Error in handleBskyFollow:", err) 36 + ); 35 37 break; 36 38 case "place.stream.chat.message": 37 - this.handleChatMessage(event); 39 + this.handleChatMessage(event).catch(err => 40 + console.error("Error in handleChatMessage:", err) 41 + ); 38 42 break; 39 43 case "place.stream.chat.profile": 40 44 this.handleChatProfile(event); 41 45 break; 42 46 case "place.stream.live.teleport": 43 - this.handleTeleport(event); 47 + this.handleTeleport(event).catch(err => 48 + console.error("Error in handleTeleport:", err) 49 + ); 44 50 break; 45 51 case "online.timtinkers.bot.command": 46 52 this.handleNewCommand(event);
+15 -1
utils/websocket.ts
··· 2 2 import { JETSTREAM_URL } from "../env.ts"; 3 3 import { EventHandler } from "./eventHandler.ts"; 4 4 5 + // Collections we want to filter in Jetstream for 6 + const wantedCollections = [ 7 + "app.bsky.actor.profile", 8 + "app.bsky.graph.follow", 9 + "online.timtinkers.bot.command", 10 + "online.timtinkers.bot.shoutout", 11 + "place.stream.chat.message", 12 + "place.stream.chat.profile", 13 + "place.stream.live.teleport", 14 + ]; 15 + 5 16 // Client subscription message 6 17 interface SubscriptionMessage { 7 18 type: "subscribe" | "unsubscribe"; ··· 35 46 } 36 47 37 48 private connectToJetstream() { 38 - const jetstreamUrl = JETSTREAM_URL; 49 + const baseUrl = JETSTREAM_URL; 50 + const jetstreamUrl = `${baseUrl}?${ 51 + wantedCollections.map((c) => `wantedCollections=${c}`).join("&") 52 + }`; 39 53 this.jetstreamWs = new WebSocket(jetstreamUrl); 40 54 41 55 let pingInterval: number | null = null;