Giter Site home page Giter Site logo

bot's Introduction

Skyware

@skyware/bot

A framework for building bots on Bluesky.

Documentation

Features

  • Events: Receive and respond to events in real time with zero setup.
  • Rate Limiting: Automatically handle rate limits and caching.
  • High-level API: A simple, high-level API designed for ease of use.

Installation

npm install @skyware/bot

Example Usage

import { Bot } from "@skyware/bot";

const bot = new Bot();
await bot.login({ identifier: "···", password: "···" });

bot.on("reply", async (post) => {
    await post.reply({ text: "Thanks for replying to my post!" });
    await post.like();
    await post.author.follow();
})

bot's People

Contributors

futurgh avatar shelob9 avatar

Stargazers

Omniraptor avatar Dave Lunny avatar Clara Menezes avatar Andre Felippe  avatar Guilherme Lara avatar Emerson Delatorre avatar João Inácio Neto avatar Fred Recco avatar Giovanni Estevam avatar Cristian Silva avatar daniel carvalho avatar Lesano Tsuki avatar Meisam Maani avatar Vinicius avatar Eric Bailey avatar fadhlu avatar PSingletary avatar  avatar Nate Goldman avatar Nick Beattie avatar

Watchers

 avatar

Forkers

shelob9 nerdcha

bot's Issues

BUG: Rate limit is 1000 times more limiting than intended

Here you create the rate limiter with 3000 operations per 300*1000 seconds, so a thousand times less than the official rate.

(rateLimitOptions?.rateLimitInterval ?? 300) * 1000,

As you can see it's supossed to be seconds and I guess you treat it as if it was milliseconds:
https://github.com/Borewit/rate-limit-threshold

So after some time your rate-limited client stops making my requests with sleeps, allowing me only 3000 calls per 3.5 days.

Cron Job

Hi, I am not sure if I am doing something wrong, or it's a library issue. I have a very basic bot, that posts stuff on schedule:

const bot = new Bot();

await bot.login({
  identifier: process.env.BSKY_BOT_HANDLE!,
  password: process.env.BSKY_BOT_PASSWORD!,
});

const job = new CronJob('0 */2 * * *', async () => {
  await bot.post({
    text: "text of the post,
  });
});

job.start();

On the first run it posts the message successfully. But nothing is posted on the consecutive runs. What am I missing?

Thanks!

Stopping a Bot?

Hello! Great software!! It's being really useful to me.

I have a question and I will give you a context.

My question is in the title. How can I stop a Bot instance? I cannot find methods like "close" or "disconnect". I guess if I don't stop them and I create new ones that would create a memory leak and maybe quota issues with the APIs.

The context is that I'm using your Firehose library to search for certain posts in the Firehose, in real time, and then I use your Bot library to gather more data about them... and after some hours, maybe more than a day, I see the Firewhose is still working but somethings wrong in my code. I'm trying to debug the problem. Maybe the bot is not behaving as before? Does the websocket reconnect if it disconnects because a network problem or server reset? I wonder if I can restart the Bot or dispose it and make a new instance, but I would like to stop it for that.

I'll keep debugging my software because it's all probably my fault in any case.

Thanks for any answer you can give me!

getProfiles() to get multiple profiles in a single API call

Hello! I love your project.

Today I used patch-package to patch @skyware/[email protected] for the project I'm working on.

In order to save API calls i needed a getProfiles() method so I created it. Feel free to use my code if you want.

This approach combines cached and not cached results, otherwise the code would be much simpler. Anyway I'm sure you can do better code. 😅 Meanwhile I'll keep the method with the help of 'patch-package'.

diff --git a/node_modules/@skyware/bot/dist/bot/Bot.d.ts b/node_modules/@skyware/bot/dist/bot/Bot.d.ts
index bde7f4f..20f6f54 100644
--- a/node_modules/@skyware/bot/dist/bot/Bot.d.ts
+++ b/node_modules/@skyware/bot/dist/bot/Bot.d.ts
@@ -121,6 +121,12 @@ export declare class Bot extends EventEmitter {
      * @param options Optional configuration.
      */
     getProfile(didOrHandle: string, options?: BaseBotGetMethodOptions): Promise<Profile>;
+    /**
+     * Fetch some profiles by DID or handle.
+     * @param didsOrHandles The users DIDs or handles.
+     * @param options Optional configuration.
+     */
+    getProfiles(didsOrHandles: string, options?: BaseBotGetMethodOptions): Promise<Profile[]>;
     /**
      * Fetch a list by its AT URI.
      * @param uri The list's AT URI.
diff --git a/node_modules/@skyware/bot/dist/bot/Bot.js b/node_modules/@skyware/bot/dist/bot/Bot.js
index 610f5f7..921ab13 100644
--- a/node_modules/@skyware/bot/dist/bot/Bot.js
+++ b/node_modules/@skyware/bot/dist/bot/Bot.js
@@ -219,6 +219,39 @@ export class Bot extends EventEmitter {
             this.cache.profiles.set(didOrHandle, profile);
         return profile;
     }
+    /**
+     * Fetch some profiles by DID or handle.
+     * @param didsOrHandles The users DIDs or handles.
+     * @param options Optional configuration.
+     */
+    async getProfiles(didsOrHandles, options = {}) {
+        const cachedKeys = options.skipCache ? null : [...didsOrHandles.filter(x=>this.cache.profiles.has(x))];
+        const cachedData = options.skipCache ? null : new Map(cachedKeys.map(x=>[x,this.cache.profiles.get(x)]));
+        const notCachedKeys = options.skipCache ? didsOrHandles : [...didsOrHandles.filter(x=>!cachedData.has(x))];
+        const profilesView = notCachedKeys.length == 0 ? null : await this.agent.getProfiles({ actors: notCachedKeys }).catch((e) => {
+            throw new Error(`Failed to fetch profiles.`, { cause: e });
+        });
+        const receivedProfiles = profilesView ? [...profilesView.data.profiles.map(p=>Profile.fromView(p, this))] : [];
+        if (!options.noCacheResponse) {
+            // Cache them by did or handle as requested
+            for (const profile of receivedProfiles) {
+                if (didsOrHandles.indexOf(profile.did) >= 0) {
+                    this.cache.profiles.set(profile.did, profile);
+                } else if (didsOrHandles.indexOf(profile.handle) >= 0) {
+                    this.cache.profiles.set(profile.handle, profile);
+                }
+            }
+        }
+        // Construct a result in the same order if possible (missing profiles will not be there)
+        const res = [...didsOrHandles.map(k=>{
+            if (cachedData && cachedData.has(k)) {
+                return cachedData.get(k);
+            } else {
+                return receivedProfiles.find(p=>p.did==k || p.handle==k) || null;
+            }
+        }).filter(p=>p)];
+        return res;
+    }
     /**
      * Fetch a list by its AT URI.
      * @param uri The list's AT URI.

This issue body was partially generated by patch-package.

Problem using typescript

I have this source code

import { AtpAgent, AtpSessionData } from "@atproto/api";
import { getSession, saveSession } from "../redis";
import { Bot } from "@skyware/bot";
import "dotenv/config";

export const generateAgentAndBot = async (): Promise<[AtpAgent,Bot]> => {
  const bot = new Bot();
  const agent = new AtpAgent({
    service: "https://bsky.social",
    persistSession: async (evt: string, session: AtpSessionData | undefined) => {
      await saveSession(JSON.stringify(session));
      console.log('Persist session');
    }
  });

  const session = await getSession();

  if (session) {
    console.log("Resume session");
    await agent.resumeSession(JSON.parse(session));
    await bot.resumeSession(JSON.parse(session))
    return [agent, bot];
  }

  const  { data } = await agent.login({
    identifier: String(process.env.IDENTIFIER),
    password: String(process.env.PASSWORD),
  });
  await bot.resumeSession({
    refreshJwt: data.refreshJwt,
    accessJwt: data.accessJwt,
    handle: data.handle,
    did: data.did,
    email: data.email,
    emailConfirmed: data.emailConfirmed,
    emailAuthFactor: data.emailAuthFactor,
    active: !!data.active,
    status: data.status
  })

  console.log("Create a new Session");

  return [agent, bot];
};

and when I run I receive this error on terminal

/home/cristian/github/save-to-later/node_modules/ts-node/dist/index.js:851
            return old(m, filename);
                   ^
Error [ERR_REQUIRE_ESM]: require() of ES Module /home/cristian/github/save-to-later/node_modules/@skyware/bot/dist/index.js from /home/cristian/github/save-to-later/src/config/agentProxy.ts not supported.
Instead change the require of index.js in /home/cristian/github/save-to-later/src/config/agentProxy.ts to a dynamic import() which is available in all CommonJS modules.
    at require.extensions.<computed> [as .js] (/home/cristian/github/save-to-later/node_modules/ts-node/dist/index.js:851:20)
    at Object.<anonymous> (/home/cristian/github/save-to-later/src/config/agentProxy.ts:15:15)
    at m._compile (/home/cristian/github/save-to-later/node_modules/ts-node/dist/index.js:857:29) {
  code: 'ERR_REQUIRE_ESM'
}
[nodemon] app crashed - waiting for file changes before starting...

Example on using session

If the current session is expired,

how should i resume the session?
can you provide an example

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.