import 'dotenv/config'; import {Bot, IncomingChatPreference, RichText} from "@skyware/bot"; import fetchRetry from "fetch-retry"; import { appendFileSync } from "fs"; global.fetch = fetchRetry(global.fetch); var bot = new Bot({ emitEvents: false, emitChatEvents: true }); bot.on("error", error => { console.error("bot error", error); }); await bot.login({ identifier: process.env.IDENTIFIER, password: process.env.PASSWORD }); await bot.setChatPreference(IncomingChatPreference.All); bot.on("message", async message => { try { var sender = await message.getSender(); var conversation = await message.getConversation(); if (!conversation) { console.error("missing conversation"); } if (message.text.startsWith('/')) { let respond = text => conversation.sendMessage({text}); let cmd = message.text.split(' ')[0].slice(1).toLowerCase(); let commandList = `/list, /leave, /join, /ping`; switch(cmd) { case "ping": await respond("pong"); return; case "list": let {conversations} = await bot.listConversations(); await respond(`${conversations.length} members in group chat: ${conversations.map(c => '@' + c.members.find(m => m.did != bot.profile.did).handle).join(', ')}`); return; case "leave": await respond(`You left the group chat and will no longer receive messages! Send any message to join again, or send /join to re-join silently.`); await conversation.leave(); return; case "join": await respond(`You joined the group chat`); return; case "help": await respond(`Commands: ${commandList}`); return; default: await respond(`Only these commands are accepted: ${commandList}`); return; } } var logline = `${message.sentAt.toISOString()},${message.senderDid},${sender.displayName},${sender.handle},${message.text}`; console.log(logline); appendFileSync(`chatlog.csv`, logline + '\n'); var text = message.text; var facets = message.facets || []; var linkedName = sender.displayName || sender.handle; var prefix = `${linkedName}: `; var prefixByteLength = new Blob([prefix]).size; facets = facets.map(f => { var facet = f.toRecord(); facet.index.byteStart += prefixByteLength; facet.index.byteEnd += prefixByteLength; return facet; }); text = prefix + text; facets.unshift({ index: { byteStart: 0, byteEnd: new Blob([linkedName]).size }, features: [{ did: sender.did, "$type": "app.bsky.richtext.facet#mention" }] }); var {conversations} = await bot.listConversations(); var otherConservations = conversations.filter(c => c.id != conversation?.id); //otherConservations = otherConservations.filter(c => c.members.length > 1); // doesn't work, bsky doesnt let you know when they leave? var messages = otherConservations.map(c => ({ conversationId: c.id, text, facets })); await bot.sendMessages(messages, {resolveFacets: false}); } catch (error) { console.error(error); conversation?.sendMessage({text: error.message}).catch(error => console.error(error)); } }); global.bot = bot;