### Install Deno Runtime Source: https://github.com/fedify-dev/botkit/blob/main/docs/start.md Instructions for installing Deno 2 or higher on different operating systems using platform-specific commands. ```bash curl -fsSL https://deno.land/install.sh | sh ``` ```zsh curl -fsSL https://deno.land/install.sh | sh ``` ```powershell irm https://deno.land/install.ps1 | iex ``` -------------------------------- ### Install Deno Runtime on Linux Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md This command downloads and executes the Deno installation script, which is the recommended way to get Deno on most Linux systems. ```bash curl -fsSL https://deno.land/install.sh | sh ``` -------------------------------- ### Deno Serve Console Output Source: https://github.com/fedify-dev/botkit/blob/main/docs/start.md Example console output from the deno serve command, indicating that the HTTP server is listening on a specific address and port. ```plaintext deno serve: Listening on http://0.0.0.0:8000/ ``` -------------------------------- ### Run BotKit Bot with Deno Serve Source: https://github.com/fedify-dev/botkit/blob/main/docs/start.md Bash command to run the BotKit bot using deno serve, exposing it via an HTTP server. ```bash deno serve -A ./bot.ts ``` -------------------------------- ### Create BotKit Project and Add Dependency Source: https://github.com/fedify-dev/botkit/blob/main/docs/start.md Commands to create a new directory for your bot project and add BotKit as a dependency using the Deno package manager. ```bash mkdir my-bot/ cd my-bot/ deno add jsr:@fedify/botkit ``` -------------------------------- ### Configure Deno for Temporal API Source: https://github.com/fedify-dev/botkit/blob/main/docs/start.md JSON configuration for the deno.json file to enable the unstable Temporal API, which is required by BotKit. ```json { "imports": { "@fedify/botkit": "jsr:@fedify/botkit@0.2.0" }, "unstable": ["temporal"] } ``` -------------------------------- ### Create BotKit Instance Source: https://github.com/fedify-dev/botkit/blob/main/docs/start.md TypeScript code to instantiate a new BotKit bot with a username, display name, summary, and in-memory key-value store and message queue for development purposes. ```typescript import { createBot, InProcessMessageQueue, MemoryKvStore, text, } from "@fedify/botkit"; const bot = createBot({ username: "mybot", name: "My Bot", summary: text`A bot powered by BotKit.`, kv: new MemoryKvStore(), queue: new InProcessMessageQueue(), }); ``` -------------------------------- ### Export Bot Instance for Deno Serve Source: https://github.com/fedify-dev/botkit/blob/main/docs/start.md TypeScript code to export the bot instance as a default export, making it runnable with the deno serve command. ```typescript export default bot; ``` -------------------------------- ### Reload, Enable, and Start Botkit Systemd Service Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Executes commands to reload the systemd daemon, enable the botkit-bot service for automatic startup on boot, and immediately start the service. ```bash sudo systemctl daemon-reload # Enable service to start on boot sudo systemctl enable botkit-bot # Start the service sudo systemctl start botkit-bot ``` -------------------------------- ### Example: Creating a Simple ActivityPub Bot with BotKit Source: https://github.com/fedify-dev/botkit/blob/main/README.md This TypeScript example demonstrates how to create a basic ActivityPub bot using BotKit. It shows how to initialize a bot with a username, display name, icon, and summary, configure Redis for key-value storage and message queuing, define a response to mentions, and schedule an hourly post. This illustrates BotKit's simplicity for building complete bots in a single file. ```TypeScript import { createBot, mention, text } from "@fedify/botkit"; import { RedisKvStore } from "@fedify/redis"; import { Redis } from "ioredis"; // Create a bot instance: const bot = createBot({ // The bot will have fediverse handle "@greetbot@mydomain": username: "greetbot", // Set the display name: name: "Greet Bot", // Set the profile icon (avatar): icon: new URL("https://mydomain/icon.png"), // Set the bio: summary: text`Hi, there! I'm a simple fediverse bot created by ${mention("@hongminhee@hollo.social")}.`, // Use Redis as a key-value store: kv: new RedisKvStore(new Redis()), // Use Redis as a message queue: queue: new RedisMessageQueue(() => new Redis()), }); // A bot can respond to a mention: bot.onMention = async (session, message) => { await message.reply(text`Hi, ${message.actor}!`); }; // Or, a bot also can actively publish a post: const session = bot.getSession("https://mydomain/"); setInterval(async () => { await session.publish(text`Hi, folks! It's an hourly greeting.`); }, 1000 * 60 * 60); export default bot; ``` -------------------------------- ### Install Deno Deploy CLI (`deployctl`) Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/deno-deploy.md This command installs the `deployctl` utility globally, which is essential for interacting with Deno Deploy. The flags `-gArf` ensure a global installation, grant all necessary permissions, and force an overwrite if the utility is already present. ```sh deno install -gArf jsr:@deno/deployctl ``` -------------------------------- ### Expose Local Bot with Fedify Tunnel Source: https://github.com/fedify-dev/botkit/blob/main/docs/start.md This bash command uses the `fedify tunnel` CLI tool to create a public tunnel for a local server running on port 8000, making the bot accessible from the internet. Ensure the `fedify` command-line tool is installed. ```bash fedify tunnel 8000 ``` -------------------------------- ### Handle BotKit Follow Event Source: https://github.com/fedify-dev/botkit/blob/main/docs/start.md TypeScript code demonstrating how to set an onFollow event handler to publish a direct message when the bot is followed by another user. ```typescript bot.onFollow = async (session, follower) => { await session.publish(text`Thanks for following me, ${follower}!`, { visibility: "direct", }); }; ``` -------------------------------- ### Install Caddy Web Server on Linux Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Provides commands to install the Caddy web server across different Linux distributions (Debian/Ubuntu, RHEL/Fedora, Arch Linux) for handling HTTPS and reverse proxy. ```bash # Install required packages sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https # Add Caddy repository curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \ sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \ sudo tee /etc/apt/sources.list.d/caddy-stable.list # Install Caddy sudo apt update sudo apt install caddy ``` ```bash # Add Caddy repository dnf install 'dnf-command(copr)' dnf copr enable @caddy/caddy # Install Caddy dnf install caddy ``` ```bash # Install from official repositories sudo pacman -S caddy ``` -------------------------------- ### Greeting Bot Example with BotKit Source: https://github.com/fedify-dev/botkit/blob/main/docs/examples.md This example demonstrates various ways to publish messages using BotKit. It covers sending direct messages with attachments on follow, direct messages on unfollow, replying to mentions and replies, and scheduled greeting messages with timed deletion. ```TypeScript import { BotKit } from '@fedify/botkit'; const bot = new BotKit({ // ... bot configuration ... }); // Send DM with image on follow bot.on('follow', async (event) => { await bot.sendDirectMessage(event.actor, 'Thanks for following!', { attachments: [{ type: 'image', url: 'https://example.com/welcome.png' }] }); }); // Send DM on unfollow bot.on('unfollow', async (event) => { await bot.sendDirectMessage(event.actor, 'Sorry to see you go!'); }); // Reply to replies bot.on('reply', async (event) => { await bot.reply(event.activity, 'Thanks for replying!'); }); // Reply to mentions bot.on('mention', async (event) => { await bot.reply(event.activity, 'Hello there!'); }); // Scheduled greeting message let greetingMessageId: string | null = null; setInterval(async () => { const message = await bot.publish('Hello from BotKit!'); greetingMessageId = message.id; setTimeout(async () => { if (greetingMessageId) { await bot.delete(greetingMessageId); greetingMessageId = null; } }, 30 * 1000); // Delete after 30 seconds }, 60 * 1000); // Every minute bot.start(); ``` -------------------------------- ### Clone BotKit Repository and Navigate Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Clones your bot's Git repository from GitHub and changes the current directory to the newly cloned repository, preparing for further setup. ```bash git clone https://github.com/yourusername/your-bot.git cd your-bot ``` -------------------------------- ### Configure BotKit for Proxy Tunneling Source: https://github.com/fedify-dev/botkit/blob/main/docs/start.md This TypeScript snippet demonstrates how to configure a BotKit instance to operate correctly behind a reverse proxy or tunneling service by setting the `behindProxy` option to `true`. This is crucial when exposing a local bot to the public internet. ```typescript const bot = createBot({ username: "mybot", name: "My Bot", summary: text`A bot powered by BotKit.`, kv: new MemoryKvStore(), queue: new InProcessMessageQueue(), behindProxy: true }); ``` -------------------------------- ### Deno Serve Listening Confirmation Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/bot.md This console output confirms that the Deno server has successfully started and is listening for incoming HTTP requests on the specified address and port, making the bot accessible locally. ```bash deno serve: Listening on http://0.0.0.0:8000/ ``` -------------------------------- ### Instantiate a Bot instance using createBot Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/bot.md Demonstrates how to create a `Bot` instance using the `createBot()` function. It shows the basic setup with a username and a memory-based key-value store, and explains the optional `TContextData` type parameter, typically set to `void`. ```typescript import { createBot } from "@fedify/bot"; import { MemoryKvStore } from "@fedify/fedify"; const bot = createBot({ username: "my_bot", kv: new MemoryKvStore(kv), }); ``` -------------------------------- ### Docker Compose Setup for Valkey Key-Value Store Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/store-mq.md Provides a Docker Compose configuration to run a Valkey server locally, exposing port 6379 and persisting data in a named volume for development or self-hosting. ```yaml version: '3' services: valkey: image: valkey/valkey:8-alpine command: valkey-server --appendonly yes volumes: - valkey-data:/data ports: - "6379:6379" volumes: valkey-data: ``` -------------------------------- ### Running Fedify Bot with Deno Serve Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/bot.md This Bash command shows how to start the exported Fedify bot using Deno's built-in HTTP server. The `-A` flag grants all permissions, and `./bot.ts` specifies the bot's entry file. ```bash deno serve -A ./bot.ts ``` -------------------------------- ### Install Fedify Package for BotKit Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/deno-deploy.md This command adds the `@fedify/fedify` package to your Deno bot project. This package provides core functionalities required for building and running BotKit applications. ```sh deno add jsr:@fedify/fedify ``` -------------------------------- ### Docker Compose Setup for PostgreSQL Key-Value Store Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/store-mq.md Provides a Docker Compose configuration to run a PostgreSQL server locally, exposing port 5432 and persisting data in a named volume, with predefined user, password, and database. ```yaml version: '3' services: postgres: image: postgres:17-alpine environment: POSTGRES_USER: botkit POSTGRES_PASSWORD: secret POSTGRES_DB: botkit volumes: - postgres-data:/var/lib/postgresql/data ports: - "5432:5432" volumes: postgres-data: ``` -------------------------------- ### Configure Redis or Valkey Message Queue for Botkit Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/store-mq.md This example shows how to set up a message queue using Redis or Valkey, which is recommended for production deployments due to its high performance and reliable message delivery. The `@fedify/redis` package is necessary. It can also be shared with the KV store and benefits from good monitoring tools. ```typescript import { RedisMessageQueue } from "@fedify/redis"; import { Redis } from "ioredis"; function getRedis(): Redis { return new Redis({ host: Deno.env.get("REDIS_HOST"), port: parseInt(Deno.env.get("REDIS_PORT") ?? "6379"), password: Deno.env.get("REDIS_PASSWORD"), tls: Deno.env.get("REDIS_TLS") === "true" }); } const bot = createBot({ username: "mybot", kv: new RedisKvStore(getRedis()), queue: new RedisMessageQueue(getRedis) }); ``` -------------------------------- ### Example: Handling an Emoji Reaction in BotKit Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md This TypeScript example demonstrates an `onReact` event handler. When a user reacts with an emoji to a message belonging to the bot, the bot sends a direct message thanking the actor and mentioning the specific emoji used. It verifies the message ownership before responding. ```typescript bot.onReact = async (session, reaction) => { if (reaction.message.actor.id?.href !== session.actorId.href) return; await session.publish( text`Thanks for reacting with ${reaction.emoji} to my message, ${reaction.actor}!`, { visibility: "direct" } ); }; ``` -------------------------------- ### Reply to a Message in Botkit Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md This example demonstrates how to create a reply to an existing message using the `~Message.reply()` method. It shows a chain of replies, where a reply can also be replied to. ```typescript const message = await session.publish( text`This is a message that will be replied to.` ); const reply = await message.reply(text`This is a reply to the message.`); const reply2 = await reply.reply(text`This is a reply to the reply.`); ``` -------------------------------- ### Example: Handling an Unlike Activity in BotKit Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md This TypeScript example shows an `onUnlike` event handler. When a user unlikes a message belonging to the bot, the bot sends a direct message expressing regret for the unliking action. It ensures the unliked message is the bot's own before responding. ```typescript bot.onUnlike = async (session, like) => { if (like.message.actor.id?.href !== session.actorId.href) return; await session.publish( text`I'm sorry to hear that you unliked my message, ${like.actor}.`, { visibility: "direct" } ); }; ``` -------------------------------- ### Get Message Language Hint (TypeScript) Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md Explains how to retrieve the language hint of a message using the `~Message.language` property, which returns a `LanguageTag` object. Shows how to get a BCP 47 language tag string using `LanguageTag.compact()`. ```typescript message.language.compact() // e.g., "en", "en-US", "zh-Hant" ``` -------------------------------- ### Get Bot's Fediverse Handle (actorHandle) Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/session.md Shows how to retrieve the bot's fediverse handle (e.g., `@myBot@myDomain`) using the `session.actorHandle` property, suitable for user-friendly mentions. ```typescript bot.onFollow = async (session, actor) => { await session.publish( markdown(`I'm ${session.actorHandle}. Thanks for following me!`) ); }; ``` -------------------------------- ### Bot Follows an Actor Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/session.md Illustrates how the bot can follow another actor using the `session.follow()` method. The example shows the bot automatically following back anyone who follows it. Notes on asynchronous nature and argument types are included. ```typescript bot.onFollow = async (session, actor) => { await session.follow(actor); }; ``` -------------------------------- ### Reply to Bot Mention Event with Question in TypeScript Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md An example of the `bot.onMention` event handler that replies to a message mentioning the bot. It demonstrates interacting with the `Message` object to ask a question back to the actor. ```typescript bot.onMention = async (session, message) => { await message.reply(text`You called me, ${message.actor}?`); }; ``` -------------------------------- ### Share Message with Custom Visibility in Botkit Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md This example shows how to specify the visibility of a shared message. The `visibility` option can be used to control the audience for the boosted message. ```typescript await message.share({ visibility: "followers" }); ``` -------------------------------- ### Exporting Fedify Bot for Deno Serve Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/bot.md This TypeScript snippet demonstrates how to create a `Bot` object using `@fedify/bot` and export it as the default module. This setup allows the bot to be directly used as a request handler for the `deno serve` command. ```typescript import { createBot } from "@fedify/bot"; const bot = createBot({ // Omitted other options for brevity }); export default bot; // [!code highlight] ``` -------------------------------- ### Get Published Messages with Custom Order (TypeScript) Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md Illustrates how to specify the order of published messages (e.g., "oldest") by providing the `order` option to the `Session.getOutbox()` method. ```typescript session.getOutbox({ order: "oldest" }) ``` -------------------------------- ### Handle Like Events with Bot.onLike Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md Illustrates the use of the `~Bot.onLike` event handler, which is called when someone likes messages on your bot or actors your bot follows. The example shows how to send a direct message in response to a like activity. ```typescript bot.onLike = async (session, like) => { ``` -------------------------------- ### Example: Handling a Like Activity in BotKit Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md This TypeScript code snippet demonstrates the core logic for an `onLike` event handler in BotKit. It checks if the liked message belongs to the bot and, if so, publishes a direct thank you message to the actor who performed the like. ```typescript if (like.message.actor.id?.href !== session.actorId.href) return; await session.publish( text`Thanks for liking my message, ${like.actor}!`, { visibility: "direct" } ); ``` -------------------------------- ### Configure PostgreSQL Message Queue for Botkit Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/store-mq.md This snippet illustrates how to integrate PostgreSQL as a message queue for your Botkit application, particularly useful if you're already using PostgreSQL for storage. It offers ACID compliance, transaction support, and good long-term persistence. The `@fedify/postgres` package is required for this setup. ```typescript import { PostgresMessageQueue } from "@fedify/postgres"; import postgres from "postgres"; const sql = postgres(Deno.env.get("DATABASE_URL")); const bot = createBot({ username: "mybot", kv: new PostgresKvStore(sql), queue: new PostgresMessageQueue(sql) }); ``` -------------------------------- ### Reply to Message with Custom Visibility in Botkit Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md This example demonstrates how to specify the visibility of a reply message, overriding the default inheritance from the original message. The `visibility` option can be set to control who can see the reply. ```typescript const reply = await message.reply( text`This is a direct reply to the message.`, { visibility: "direct" }, ); ``` -------------------------------- ### BotKit MemoryRepository Overview Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/repository.md The `MemoryRepository` stores data in memory, meaning that data is not persisted across restarts. It's best suited for development and testing environments where data doesn't have to be shared across multiple nodes. No setup is required. ```APIDOC MemoryRepository: Description: Stores data in memory; data is not persisted across restarts. Use Cases: Development and testing environments where data sharing across nodes is not required. Comparison to KvRepository with MemoryKvStore: - In practice, there's no difference. - MemoryRepository is more convenient and slightly more efficient (doesn't go through KvStore interface). ``` -------------------------------- ### Handle General Messages with Bot.onMessage Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md Illustrates the use of the `~Bot.onMessage` event handler, which is called for any message received by your bot, including normal timeline messages, mentions, replies, and direct messages. The example shows how to reply to a message containing the word 'BotKit'. ```typescript bot.onMessage = async (session, message) => { if (message.text.match(/\bbotkit\b/i)) { await message.reply(text`You mentioned ${em("BotKit")}!`); } }; ``` -------------------------------- ### Handle Shared Messages with Bot.onSharedMessage Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md Demonstrates how to use the `~Bot.onSharedMessage` event handler, which is invoked when someone shares (boosts) a message on your bot. The example shows how to re-share the original message in response to the share activity. ```typescript bot.onSharedMessage = async (session, sharedMessage) => { await sharedMessage.original.share(); }; ``` -------------------------------- ### Format Hashtags with markdown() in TypeScript Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/text.md This example demonstrates how to use the `markdown()` function to format a hashtag. The function not only formats the hashtag but also denotes it so that ActivityPub software can recognize it as a hashtag, making it searchable in the fediverse. ```typescript markdown(`Here's a hashtag: #BotKit`) ``` -------------------------------- ### Creating a Basic BotKit Bot Source: https://github.com/fedify-dev/botkit/blob/main/docs/intro.md Demonstrates how to initialize a BotKit bot, configure its basic properties, and set up event handlers for mentions and scheduled posts. ```typescript import { createBot, MemoryKvStore, text } from "@fedify/botkit"; const bot = createBot({ username: "weatherbot", name: "Seoul Weather Bot", summary: text`I post daily weather updates for Seoul!`, kv: new MemoryKvStore(), // ... configuration options }); // Respond to mentions bot.onMention = async (session, message) => { await message.reply( text`Current temperature in Seoul is 18°C with clear skies!` ); }; // Post scheduled updates setInterval(async () => { const session = bot.getSession("https://weather.example.com"); await session.publish( text`Good morning! Today's forecast for Seoul: 🌡️ High: 22°C 💨 Low: 15°C ☀️ Clear skies expected` ); }, 1000 * 60 * 60 * 24); // Daily updates ``` -------------------------------- ### Delay Follow Request Acceptance in TypeScript Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md Illustrates how to manually accept a follow request after a delay using `setTimeout` within the `bot.onFollow` event handler. This example shows how to override the default `followerPolicy` for specific requests. ```typescript bot.onFollow = async (session, followRequest) => { setTimeout(async () => { await followRequest.accept(); }, 1000 * 60 * 60); }; ``` -------------------------------- ### Check Bot Follow Status and Respond (TypeScript) Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/session.md This TypeScript example demonstrates how to use `bot.onMention` to check if your bot follows a given actor using `session.follows(message.author)`. It then publishes a different text response based on whether the bot is already following the actor or not. The `session.follows()` method accepts various argument types like `Actor`, `string`, and `URL`, and returns `false` if the actor doesn't exist or is inaccessible. ```TypeScript bot.onMention = async (session, message) => { const follows = await session.follows(message.author); await session.publish( follows ? text`Hi ${message.author}, I'm already following you!` : text`Hi ${message.author}, I don't follow you yet.` ); }; ``` -------------------------------- ### Publish a Direct Message with Visibility Option Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md Illustrates how to control the visibility of a published message using the `visibility` option. This example sets the message to 'direct', making it visible only to mentioned users, similar to Mastodon's 'specific people' option. ```typescript await session.publish(text`Hello, ${mention("@fedify@hollo.social")}!`, { visibility: "direct" }); ``` -------------------------------- ### Create and Set Permissions for Bot Directory Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Creates the `/opt/botkit` directory and assigns ownership to the 'botkit' user, preparing it for the bot's files and ensuring proper access control. ```bash sudo mkdir -p /opt/botkit sudo chown botkit:botkit /opt/botkit ``` -------------------------------- ### Get Message Object from Session Publish Method Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md Shows how to get a `Message` object as the return value when publishing a new message using `Session.publish()`. The method returns an `AuthorizedMessage` object, which is a specialized `Message` type. ```typescript const session = bot.getSession("https://mydomain"); const message = await session.publish(text`Hello, world!`); ``` -------------------------------- ### Create Dockerfile for BotKit Deno Application Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/docker.md This Dockerfile sets up a Deno environment for a BotKit application, caches dependencies, copies source code, and defines the entry point for running the bot. It also sets a default SERVER_NAME environment variable. ```dockerfile FROM denoland/deno:2.1.9 WORKDIR /app # Cache dependencies COPY deno.json deno.json COPY deno.lock deno.lock RUN deno install # Copy source code COPY . . # The bot needs network access and environment variables ENV SERVER_NAME=your-domain.com # Run the bot CMD ["deno", "run", "-A", "bot.ts"] ``` -------------------------------- ### Example: Handling Undoing an Emoji Reaction in BotKit Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md This TypeScript example shows an `onUnreact` event handler. It specifically checks if a 'heart' emoji reaction was removed from a bot's message and sends a direct message acknowledging the action. The handler ensures the message belongs to the bot before processing. ```typescript bot.onUnreact = async (session, reaction) => { if (reaction.message.actor.id?.href !== session.actorId.href) return; if (reaction.emoji === "❤️") { await session.publish( text`I see you took back your heart reaction, ${reaction.actor}.`, { visibility: "direct" } ); } }; ``` -------------------------------- ### Deploy BotKit Bot to Deno Deploy Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/deno-deploy.md This command initiates the deployment of your Deno application to Deno Deploy. On the first deployment, `deployctl` will automatically attempt to guess the project name from your Git repository or directory and identify common entrypoint files like `main.ts`. ```sh deployctl deploy ``` -------------------------------- ### Delete a Reply Message in Botkit Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md This example demonstrates how to delete a reply message after it has been published. The `~Message.reply()` method returns an `AuthorizedMessage` object, which has a `delete()` method to remove the message. ```typescript const reply = await message.reply(text`This reply will be deleted in a minute.`); setTimeout(async () => { await reply.delete(); }, 1000 * 60); ``` -------------------------------- ### Get Published Messages within a Date Range (TypeScript) Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md Shows how to filter published messages by a specific date range using the `since` and `until` options with `Temporal.Instant` when calling `Session.getOutbox()`. ```typescript session.getOutbox({ since: Temporal.Instant.from("2025-01-01T00:00:00Z"), until: Temporal.Instant.from("2025-01-31T23:59:59.999Z") }) ``` -------------------------------- ### Deploy BotKit Docker Container to Fly.io Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/docker.md Steps to deploy a Dockerized BotKit application to Fly.io using the Fly.io CLI, including launching the app, setting environment variables, and initiating the deployment. ```bash fly launch ``` ```bash fly secrets set SERVER_NAME=your-domain.com ``` ```bash fly deploy ``` -------------------------------- ### Publishing Rich Content with BotKit Source: https://github.com/fedify-dev/botkit/blob/main/docs/intro.md Illustrates how to create and publish messages with rich content, including links, hashtags, and image attachments, using BotKit's `session.publish` method. ```typescript await session.publish( text`Check out ${link("BotKit docs", "https://botkit.fedify.dev/")}! ${hashtag("FediverseBot")}`, { attachments: [ new Image({ mediaType: "image/png", url: new URL("https://example.com/chart.png"), name: "Daily statistics" }), ], } ); ``` -------------------------------- ### Get Bot's Actor URI (actorId) Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/session.md Demonstrates accessing the bot's unique URI through the `session.actorId` property, useful for referring to the bot in messages or interactions. ```typescript bot.onFollow = async (session, actor) => { await session.publish( text`Hi, ${actor}! I'm ${session.actorId}. Thanks for following me!` ); }; ``` -------------------------------- ### Create Session with Bot.getSession() Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/session.md Demonstrates how to create a new Session object by calling the `Bot.getSession()` method with a hardcoded server origin. ```typescript const session = bot.getSession("https://mydomain"); ``` -------------------------------- ### Handling Follow Events in BotKit Source: https://github.com/fedify-dev/botkit/blob/main/docs/intro.md Shows how to respond to a new follower by publishing a direct message using the `bot.onFollow` event handler. ```typescript bot.onFollow = async (session, follower) => { await session.publish( text`Thanks for following me, ${follower}!`, { visibility: "direct" } ); }; ``` -------------------------------- ### Create Dedicated User for BotKit Bot Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Creates a new system user 'botkit' with no login shell, which is recommended for security best practices when running services. ```bash sudo useradd -r -s /bin/false botkit ``` -------------------------------- ### Create Session using Environment Variable Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/session.md Shows how to create a Session object using the `Bot.getSession()` method, retrieving the server name from an environment variable (`SERVER_NAME`) for dynamic configuration. Includes error handling for a missing environment variable. ```typescript const SERVER_NAME = Deno.env.get("SERVER_NAME"); if (SERVER_NAME == null) { console.error("The SERVER_NAME environment variable is not set."); Deno.exit(1); } const session = bot.getSession(`https://${SERVER_NAME}`); ``` -------------------------------- ### Bot Unfollows an Actor Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/session.md Demonstrates how the bot can unfollow an actor by calling the `session.unfollow()` method. The example shows the bot unfollowing if one of its followers unfollows it. Notes on argument types are included. ```typescript bot.onUnfollow = async (session, actor) => { await session.unfollow(actor); }; ``` -------------------------------- ### Deploy BotKit Bot with Explicit Project and Entrypoint Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/deno-deploy.md This command allows for more precise control over the deployment process by explicitly specifying the project name and the entrypoint file for your Deno application. This overrides `deployctl`'s automatic detection, ensuring the correct files are used. ```sh deployctl deploy --project=mybot --entrypoint=bot.ts ``` -------------------------------- ### Create Systemd Service File for BotKit Bot Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Defines a systemd service unit file for the BotKit bot, configuring its description, dependencies, user, working directory, execution command, restart policy, and security settings for reliable operation. ```ini [Unit] Description=BotKit Bot After=network.target Wants=caddy.service [Service] Type=simple User=botkit Group=botkit Environment=SERVER_NAME=your-domain.com # Add any other environment variables your bot needs Environment=NODE_ENV=production WorkingDirectory=/opt/botkit # Make sure to use the full path to deno ExecStart=/home/botkit/.deno/bin/deno run -A bot.ts # Restart policy Restart=always RestartSec=10 # Security settings NoNewPrivileges=true ProtectSystem=strict ProtectHome=true PrivateTmp=true PrivateDevices=true # Resource limits CPUQuota=80% MemoryMax=1G [Install] WantedBy=multi-user.target ``` -------------------------------- ### Get Message Object from Bot Event Handler Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md Demonstrates how to obtain a `Message` object from an event handler, specifically the `onMention` event, when a message is received from the fediverse. The `message` parameter in the callback is the `Message` object. ```typescript import { createBot } from "@fedify/bot"; const bot = createBot({ // Omitted other options for brevity }); bot.onMention = async (session, message) => { // `message` is a `Message` object }; ``` -------------------------------- ### Configure BotKit with Deno KV Store Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/store-mq.md Configures BotKit to use Deno KV, a built-in key-value store ideal for Deno Deploy, offering automatic replication and ACID transactions. ```typescript import { DenoKvStore } from "@fedify/fedify/x/deno"; const kv = await Deno.openKv(); const bot = createBot({ username: "mybot", kv: new DenoKvStore(kv), // ... other configuration }); ``` -------------------------------- ### Interpolating JavaScript Objects into Text Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/text.md Demonstrates how any JavaScript object interpolated into a `text` template string is automatically converted to its string representation using `String()`. This example shows a number being interpolated. ```typescript text`The number is ${42}.` ``` -------------------------------- ### Configure BotKit to use Deno KV for Storage and Queue Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/deno-deploy.md This TypeScript code snippet demonstrates how to initialize a BotKit bot to utilize Deno KV for both persistent data storage and message queuing. It involves opening a Deno KV database instance and passing it to the `DenoKvStore` and `DenoKvMessageQueue` constructors during bot creation. ```typescript import { createBot } from "@fedify/botkit"; import { DenoKvMessageQueue, DenoKvStore } from "@fedify/fedify/x/deno"; const kv = await Deno.openKv(); const bot = createBot({ username: "mybot", kv: new DenoKvStore(kv), queue: new DenoKvMessageQueue(kv), // ... other configuration }); ``` -------------------------------- ### Bot Configuration: Web Page Options Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/bot.md Details the `pages` options within `CreateBotOptions`, including `color` for theme customization and `css` for injecting custom styles. Provides a comprehensive list of available theme colors for the bot's web pages. ```APIDOC CreateBotOptions.pages: description: The options for the web pages of the bot. PagesOptions.color: description: The color of the theme. It will be used for the theme color of the web pages. The default color is "green". available_colors: - "amber" - "azure" - "blue" - "cyan" - "fuchsia" - "green" (default) - "grey" - "indigo" - "jade" - "lime" - "orange" - "pink" - "pumpkin" - "purple" - "red" - "sand" - "slate" - "violet" - "yellow" - "zinc" see_also: "Pico CSS docs - Colors section: https://picocss.com/docs/colors" PagesOptions.css: description: The custom CSS to be injected into the web pages. It should be a string of CSS code. ``` -------------------------------- ### Automatically deleting old messages Source: https://github.com/fedify-dev/botkit/blob/main/docs/recipes.md To automatically delete old messages after a certain period, you can use Session.getOutbox() method, AuthorizedMessage.delete() method, and the setInterval() function together. The following example shows how to delete all messages older than a week: ```typescript async function deleteOldPosts(session: Session): Promise { const now = Temporal.Now.instant(); const oneWeekAgo = now.subtract({ hours: 7 * 24 }); const oldPosts = session.getOutbox({ until: oneWeekAgo }); for await (const post of oldPosts) { await post.delete(); } } setInterval( deleteOldPosts, 1000 * 60 * 60, bot.getSession("https://yourdomain") ); ``` -------------------------------- ### Configure Caddyfile for HTTPS and Reverse Proxy Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Creates a Caddyfile configuration for your domain, enabling automatic HTTPS with Let's Encrypt, proxying requests to your bot running on localhost:8000, and adding basic security headers. ```caddyfile your-domain.com { # Automatic HTTPS tls { # Email for Let's Encrypt notifications email your-email@example.com } # Proxy all requests to your bot reverse_proxy localhost:8000 # Basic security headers header { # Enable HSTS Strict-TransportSecurity "max-age=31536000;" # Prevent clickjacking X-Frame-Options "DENY" # XSS protection X-Content-Type-Options "nosniff" X-XSS-Protection "1; mode=block" } } ``` -------------------------------- ### Run Fedify Bot with `BEHIND_PROXY` Environment Variable Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/bot.md This Bash command demonstrates how to launch the Deno server for the bot while setting the `BEHIND_PROXY` environment variable to `true`. This enables the bot to correctly interpret `X-Forwarded-*` headers from tunneling services. ```bash BEHIND_PROXY=true deno serve -A --port 8000 ./bot.ts ``` -------------------------------- ### Publish a Basic Message to Fediverse Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/message.md Illustrates the basic usage of `Session.publish()` to send a simple 'Hello, world!' message to the fediverse. It emphasizes that the method takes a `Text` object, not a plain string. ```typescript await session.publish(text`Hello, world!`); ``` -------------------------------- ### Deploy BotKit Bot with Environment Variable File Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/deno-deploy.md This command facilitates the deployment of your bot by loading environment variables from a specified file, such as `.env`, using the `--env-file` flag. This approach is convenient for managing multiple environment variables in a structured way. ```sh deployctl deploy --env-file=.env ``` -------------------------------- ### Session Object API Reference Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/session.md API documentation for the Session object and related methods, detailing properties and functions for interacting with the fediverse. ```APIDOC Bot: getSession(origin: string): Session origin: The origin of the server to which your bot belongs. Session: actorId: string The URI of the bot actor. actorHandle: string The fediverse handle of the bot (e.g., @myBot@myDomain). getActor(): Actor Returns the Actor object of the bot. follow(actor: Actor | URL | string): Promise Sends a follow request to an actor. actor: The actor to follow. Can be an Actor object, a URL (URI of the actor), or a string (URI or fediverse handle). unfollow(actor: Actor | URL | string): Promise Sends an unfollow request to an actor. actor: The actor to unfollow. Can be an Actor object, a URL (URI of the actor), or a string (URI or fediverse handle). follows(): boolean Checks if the bot follows a given actor. ``` -------------------------------- ### Define Bot Software Metadata with CreateBotOptions Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/bot.md Sets metadata about the bot server, used for the NodeInfo protocol. It includes the software's canonical name, version (as a `SemVer` object), and optional repository and homepage URLs. The name must comply with the `/^[a-z0-9-]+$/` pattern. ```APIDOC `~CreateBotOptions.software` Metadata about the bot server, used for NodeInfo protocol. Properties: - `name` (required): Canonical name of the bot software. Pattern: `/^[a-z0-9-]+$/`. - `version` (required): `SemVer` object. Create using `parseSemVer()` function. - `repository` (optional): `URL` of source code repository. - `homepage` (optional): `URL` of homepage. ``` ```typescript import { createBot, parseSemVer } from "@fedify/botkit"; const bot = createBot({ // Omitted other options for brevity software: { name: "my-bot", version: parseSemVer("1.0.0"), // [!code highlight] } }); ``` -------------------------------- ### Configure BotKit with PostgreSQL KV Store Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/store-mq.md Configures BotKit to use PostgreSQL as the key-value store, suitable for deployments requiring complex queries or ACID compliance. It connects using a database URL from environment variables. ```typescript import { PostgresKvStore } from "@fedify/postgres"; import postgres from "postgres"; const sql = postgres(Deno.env.get("DATABASE_URL")); const bot = createBot({ username: "mybot", kv: new PostgresKvStore(sql), }); ``` -------------------------------- ### Verify Botkit Systemd Service Status and Logs Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Checks the operational status of the botkit-bot service and displays its real-time logs, providing immediate feedback on service health and activity. ```bash # Check service status sudo systemctl status botkit-bot # View logs sudo journalctl -u botkit-bot -f ``` -------------------------------- ### Configure BotKit with Redis or Valkey KV Store Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/store-mq.md Configures BotKit to use Redis or Valkey as the key-value store, recommended for high-performance production deployments. It connects using environment variables for host, port, password, and TLS. ```typescript import { RedisKvStore } from "@fedify/redis"; import { Redis } from "ioredis"; const redis = new Redis({ host: Deno.env.get("REDIS_HOST"), port: parseInt(Deno.env.get("REDIS_PORT") ?? "6379"), password: Deno.env.get("REDIS_PASSWORD"), tls: Deno.env.get("REDIS_TLS") === "true", }); const bot = createBot({ username: "mybot", kv: new RedisKvStore(redis), }); ``` -------------------------------- ### Handle Mentions and Replies, Avoiding Duplicate Actions (Alternative) Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md This alternative example shows how to prevent the `~Bot.onReply` event handler from being called when a reply message mentioning the bot is received. Instead, `~Bot.onMention` handles the interaction, preventing redundant processing. ```typescript bot.onMention = async (session, message) => { await message.reply(text`You called me, ${message.actor}?`); }; bot.onReply = async (session, reply) => { if (!reply.mentions.some(m => m.href.href === session.actorId.href)) { await reply.reply(text`Thanks for your reply, ${reply.actor}!`); } }; ``` -------------------------------- ### Restart Caddy Service Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Restarts the Caddy service using systemctl to apply new configurations or changes, ensuring the web server is running with the latest settings. ```bash sudo systemctl restart caddy ``` -------------------------------- ### Set Permissions for Caddyfile Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Changes the ownership of the Caddyfile to root and sets read-only permissions for others, ensuring proper security for the configuration file. ```bash sudo chown root:root /etc/caddy/Caddyfile sudo chmod 644 /etc/caddy/Caddyfile ``` -------------------------------- ### Following back Source: https://github.com/fedify-dev/botkit/blob/main/docs/recipes.md To let your bot follow back all of its followers, you can use the onFollow event with the Session.follow() method together. ```typescript bot.onFollow = async (session, followRequest) => { await followRequest.accept(); await session.follow(followRequest.follower); }; ``` -------------------------------- ### Interpolating block `Text` objects creates new paragraphs Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/text.md Explains that interpolating a block `Text` object within another `Text` object will close the current paragraph and start a new one, demonstrating the block-level behavior. ```typescript text`Hello! ${text`This is a new paragraph.`}` ``` -------------------------------- ### Monitor Botkit Service Logs in Real-time Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Provides a command to continuously stream the logs of the botkit-bot service, which is crucial for real-time monitoring and debugging. ```bash sudo journalctl -u botkit-bot -f ``` -------------------------------- ### Configure Deno KV Message Queue for Botkit Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/store-mq.md This snippet demonstrates how to configure a message queue using Deno KV for your Botkit application. It's ideal for Deno Deploy environments, offering automatic scaling and no additional infrastructure. Note that the `@fedify/fedify` package is required. While convenient, it has limited throughput and is Deno-specific. ```typescript import { DenoKvMessageQueue } from "@fedify/fedify/x/deno"; const kv = await Deno.openKv(); const bot = createBot({ username: "mybot", kv: new DenoKvStore(kv), queue: new DenoKvMessageQueue(kv) }); bot.federation.startQueue(); ``` -------------------------------- ### Automatic HTML Escaping in Text Interpolation Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/text.md Explains that HTML strings interpolated into `text` templates are automatically escaped to prevent rendering as HTML, ensuring security and plain text output. This example shows `` tags being escaped. ```typescript text`The following HTML will be escaped: ${"bold"}.` ``` -------------------------------- ### Check Caddy Service Status and Logs Source: https://github.com/fedify-dev/botkit/blob/main/docs/deploy/self-hosting.md Checks the current status of the Caddy service and displays its real-time logs, which is useful for debugging and monitoring its operation. ```bash sudo systemctl status caddy sudo journalctl -u caddy --follow ``` -------------------------------- ### Handle General Messages, Avoiding Duplicates with Mentions Source: https://github.com/fedify-dev/botkit/blob/main/docs/concepts/events.md This example shows how to prevent the `~Bot.onMessage` event handler from being called when a mention message is received. This is useful to avoid redundant actions if `~Bot.onMention` is already handling mention-specific logic, ensuring event handlers do not conflict. ```typescript bot.onMention = async (session, message) => { await message.reply(text`You called me, ${message.actor}?`); }; bot.onMessage = async (session, message) => { if (message.mentions.some(m => m.href.href === session.actorId.href)) { return; } if (message.text.match(/\bbotkit\b/i)) { await message.reply(text`You mentioned ${em("BotKit")}!`); } }; ```