#fedidev

:neobread: Bolet :neobread:javascript@app.wafrn.net
2025-05-06

In the wafrn app development recently, I have been paying more attention to android devices, because that is what is use daily, but with the power of React Native, iOS devices also get their updates.

Version 1.3.1 of the app has been sent to TestFlight and it will come within the following 1-2 days.
This includes fixes for things like the error on emoji reaction notification, and the dreaded drawing offset of WafrnPaint


#WafrnDev #FediDev
:neobread: Bolet :neobread:javascript@app.wafrn.net
2025-05-05

Great news for the wafrn app !!

As a culmination of the big journey of the past weeks, the Wafrn App is now listed in the official @unifiedpush documentation as one of the apps that support UnifiedPush

Check it at https://unifiedpush.org/users/apps/


#WafrnDev #FediDev #UnifiedPush #De-Google #FreeServices
ๆดช ๆฐ‘ๆ†™ (Hong Minhee)hongminhee@hackers.pub
2025-05-05

After reviewing FEP-5624: Per-object reply control policies and GoToSocial's interaction policy spec, I find myself leaning toward the latter for long-term considerations, though both have merit.

FEP-5624 is admirably focused and simpler to implement, which I appreciate. However, #GoToSocial's approach seems to offer some architectural advantages:

  1. The three-tier permission model (allow/require approval/deny) feels more flexible than binary allow/deny
  2. Separating approval objects from interactions appears more secure against forgery
  3. The explicit handling of edge cases (mentioned users, post authors) provides clearer semantics
  4. The extensible framework allows for handling diverse interaction types, not just replies

I wonder if creating an #FEP that extracts GoToSocial's interaction policy design into a standalone standard might be worthwhile. It could potentially serve as a more comprehensive foundation for access control in #ActivityPub.

This is merely my initial impression though. I'd be curious to hear other developers' perspectives on these approaches.

#FEP5624 #fedidev #fediverse #replycontrol #interactionpolicy

Everyday.Human DerekEVDHmn@ecoevo.social
2025-05-04

@Da_Gut
#fediadmin
#fedidev
#protocol

I not sure.๐Ÿค” hopefully these tags help

:neobread: Bolet :neobread:javascript@app.wafrn.net
2025-04-29

Soโ€ฆ I did a thing: https://github.com/juandjara/expo-unified-push
This library will help everybody developing React Native apps to use the Unified Push Android library, so they can have native notifications without depending on Google and Firebase systems.

Next step, integrating it into wafrn


#wafrnDev #fediDev #react-native
:neobread: Bolet :neobread:javascript@app.wafrn.net
2025-04-28

I am cooking something that is a very niche open source feature just for the sake of it, just for the challenge


#React-native #fediDev #foss
Screenshot of my new project, where you can see a test app for the Android library Unified Push with the Expo App Framework. It features the use of different push notification distributors and a button to test notifications
2025-04-26

Hey fedi devss! (Hints & boosts appreciated)

Mastodon API question โ€” which instance/server API says where the URL redirects when there is no signed in user?

For example:
1. social.ayco.io goes to my profile; but
2. fosstodon.org goes to the explore tab

I am looking for the info via REST API

#askMastodon #fedidev

ๆดช ๆฐ‘ๆ†™ (Hong Minhee)hongminhee@hollo.social
2025-04-26

For those skeptical of DMs in #ActivityPub: I'm also considering an alternative verification approach using ActivityPub's Question feature. Instead of sending numeric codes, the system could send a poll with several emoji options, and the user would select the one that matches what's displayed on their login screen. This visual authentication method might offer better security against certain automated attacks while still leveraging federation rather than platform-specific APIs. Would this approach address some of the privacy concerns around DM-based verification?

#fediverse #OTP #fedidev #auth

ๆดช ๆฐ‘ๆ†™ (Hong Minhee)hongminhee@hollo.social
2025-04-26

I'm exploring a new idea called FediOTP (codename): an authentication system that uses #ActivityPub DMs to deliver one-time passwords, allowing any #fediverse account to authenticate with web services. Unlike current solutions that rely on specific APIs (#Mastodon, #Misskey), this would work with any ActivityPub-compatible server, increasing interoperability across the fediverse. Would love to hear your thoughts on potential challenges or use cases for this approach.

#OTP #fedidev #auth

ๆดช ๆฐ‘ๆ†™ (Hong Minhee)hongminhee@hollo.social
2025-04-23

My stance on #ActivityPub's adoption of JSON-LD: Since we've already decided to use JSON-LD, I hope we do it properly. However, if we hadn't used JSON-LD from the beginning, things would have been much less complicated.

#JSONLD #fedidev

Fedify: an ActivityPub server frameworkfedify@hollo.social
2025-04-22

Hey folks! We're excited to share a preview of a new API coming in #Fedify 1.6 that should make structuring larger federated apps much cleaner: FederationBuilder.

As your Fedify applications grow, you might encounter circular dependency issues when registering dispatchers and listeners across multiple files. The new FederationBuilder pattern helps solve this by separating the configuration phase from instantiation.

Instead of this:

// federation.ts
import { createFederation } from "@fedify/fedify";

export const federation = createFederation<AppContext>({
  kv: new DbKvStore(), 
  queue: new RedisMessageQueue(),
  // Other options...
});

// Now we need to import this federation instance in other files
// to register dispatchers and listeners...

You can now do this:

// builder.ts
import { createFederationBuilder } from "@fedify/fedify";

export const builder = createFederationBuilder<AppContext>();

// other files can import and configure this builder...
// actors.ts
import { builder } from "./builder.ts";
import { Person } from "@fedify/fedify";

builder.setActorDispatcher("/users/{handle}", async (ctx, handle) => {
  // Actor implementation
});
// inbox.ts
import { builder } from "./builder.ts";
import { Follow } from "@fedify/fedify";

builder.setInboxListeners("/users/{handle}/inbox", "/inbox")
  .on(Follow, async (ctx, follow) => {
    // Follow handling
  });
// main.ts โ€” Only create the Federation instance at startup
import { builder } from "./builder.ts";

// Build the Federation object with actual dependencies
export const federation = await builder.build({
  kv: new DbKvStore(),
  queue: new RedisMessageQueue(),
  // Other options...
});

This pattern helps avoid circular dependencies and makes your code more modular. Each part of your app can configure the builder without needing the actual Federation instance.

The full documentation will be available when 1.6 is released, but we wanted to share this early with our community. Looking forward to your feedback when it lands!

Want to try it right now? You can install the development version from JSR or npm:

# Deno
deno add jsr:@fedify/fedify@1.6.0-dev.777+1206cb01

# Node.js
npm add @fedify/fedify@1.6.0-dev.777

# Bun
bun add @fedify/fedify@1.6.0-dev.777

#ActivityPub #fedidev

ๆดช ๆฐ‘ๆ†™ (Hong Minhee)hongminhee@hollo.social
2025-04-21

I've been reflecting lately on projects like @fedify, @hollo, and @botkit. Sometimes I wonder if I'm solving problems that very few people actually need solved. How many developers truly want to build their own #ActivityPub server from scratch?

It feels a bit like inventing shoes that let people walk on their hands all day. Would there be a viable market? How many would actually buy them?

That's the sense I get with these projects. They do have users who find them tremendously valuable, but the total user base is inherently limited. The tools serve an important function for a small audience of specialized developers.

There are moments when my motivation wavers. When the user community consists of just a handful of enthusiastic supporters, it's sometimes difficult to maintain momentum and justify the ongoing investment of time and energy.

And yet, there's something meaningful about creating specialized tools that solve complex problems well, even if they're only used by a few. Perhaps that's enough.

#fedidev

@reiver โŠผ (Charles) :batman:reiver
2025-04-21

A HEALTH-CHECK URL would, for example, make sure:

โ€ข the web-server is up,
โ€ข the database connection is fine,
โ€ข maybe query one or more important tables to make sure that still works,
โ€ข make sure any 3rd party APIs are working,
โ€ข etc.

If any of those things has a problem, then it would return "500 Internal Server Error".

Else (if everything was fine then) it would return "200 OK".

@reiver โŠผ (Charles) :batman:reiver
2025-04-21

A lot of Fediverse software has a HEALTH-CHECK URL.

But not all Fediverse does.

It would be better if ALL Fediverse software had a HEALTH-CHECK URL.

...

A HEALTH-CHECK URL is a special URL that tell others if the system is running properly.

It would return "200 OK" if everything is fine. And return "500 Internal Server Error" if there is a problem

...

A HEALTH-CHECK URL is important to those who actual run and administrate Fediverse servers

BotKit by Fedify :botkit:botkit@hollo.social
2025-04-21

BotKit 0.2.0ใฎใƒชใƒชใƒผใ‚น

BotKit 0.2.0ใ‚’ใƒชใƒชใƒผใ‚นใ—ใพใ—ใŸ๏ผBotKitใ‚’ๅˆใ‚ใฆ็Ÿฅใ‚‹ๆ–นใฎใŸใ‚ใซ็ฐกๅ˜ใซ่ชฌๆ˜Žใ™ใ‚‹ใจใ€BotKitใฏTypeScriptใง้–‹็™บใ•ใ‚ŒใŸใ‚นใ‚ฟใƒณใƒ‰ใ‚ขใƒญใƒณใฎActivityPubใƒœใƒƒใƒˆใƒ•ใƒฌใƒผใƒ ใƒฏใƒผใ‚ฏใงใ™ใ€‚Mastodonใ€Misskeyใชใฉใ•ใพใ–ใพใชใƒ•ใ‚งใƒ‡ใ‚ฃใƒใƒผใ‚น๏ผˆ#fediverse๏ผ‰ใฎใƒ—ใƒฉใƒƒใƒˆใƒ•ใ‚ฉใƒผใƒ ใจ้€ฃๆบใงใใ€ๆ—ขๅญ˜ใƒ—ใƒฉใƒƒใƒˆใƒ•ใ‚ฉใƒผใƒ ใฎๅˆถ็ด„ใชใ—ใซ่‡ช็”ฑใซใƒœใƒƒใƒˆใ‚’ไฝœๆˆใงใใพใ™ใ€‚

ใ“ใฎใƒชใƒชใƒผใ‚นใฏใ€ใƒ•ใ‚งใƒ‡ใ‚ฃใƒใƒผใ‚นใซใŠใ‘ใ‚‹ใƒœใƒƒใƒˆ้–‹็™บใ‚’ใ‚ˆใ‚Š็ฐกๅ˜ใงๅผทๅŠ›ใซใ™ใ‚‹ใŸใ‚ใฎๆ—…ใฎ้‡่ฆใชไธ€ๆญฉใงใ‚ใ‚Šใ€ใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใ‹ใ‚‰่ฆๆœ›ใฎใ‚ใฃใŸๆฉŸ่ƒฝใ‚’ๅคšๆ•ฐๅฐŽๅ…ฅใ—ใฆใ„ใพใ™ใ€‚

ใ‚ˆใ‚Š่‰ฏใ„ใƒœใƒƒใƒˆใ‚คใƒณใ‚ฟใƒฉใ‚ฏใ‚ทใƒงใƒณใธใฎๆ—…

BotKitใฎ้–‹็™บใซใŠใ„ใฆใ€็งใŸใกใฏๅธธใซใƒœใƒƒใƒˆใ‚’ใ‚ˆใ‚Š่กจ็พๅŠ›่ฑŠใ‹ใงใ‚คใƒณใ‚ฟใƒฉใ‚ฏใƒ†ใ‚ฃใƒ–ใซใ™ใ‚‹ใ“ใจใซ็„ฆ็‚นใ‚’ๅฝ“ใฆใฆใใพใ—ใŸใ€‚ใƒใƒผใ‚ธใƒงใƒณ0.2.0ใงใฏใ€ใƒ•ใ‚งใƒ‡ใ‚ฃใƒใƒผใ‚นใฎ็คพไผš็š„ๅด้ขใ‚’ใƒœใƒƒใƒˆใซๅ–ใ‚Šๅ…ฅใ‚Œใ‚‹ใ“ใจใงใ€ใ•ใ‚‰ใซไธ€ๆญฉๅ‰้€ฒใ—ใพใ—ใŸใ€‚

ใ‚ซใ‚นใ‚ฟใƒ ็ตตๆ–‡ๅญ—ใงใƒœใƒƒใƒˆใฎๅ€‹ๆ€งใ‚’่กจ็พ

ๆœ€ใ‚‚่ฆๆœ›ใฎๅคšใ‹ใฃใŸๆฉŸ่ƒฝใฎไธ€ใคใŒใ‚ซใ‚นใ‚ฟใƒ ็ตตๆ–‡ๅญ—ใฎใ‚ตใƒใƒผใƒˆใงใ™ใ€‚ใ“ใ‚Œใซใ‚ˆใ‚Šใ€ใƒœใƒƒใƒˆใฏ็‹ฌ่‡ชใฎ่ฆ–่ฆš่ฆ็ด ใงใƒกใƒƒใ‚ปใƒผใ‚ธใ‚’็›ฎ็ซ‹ใŸใ›ใ€่‡ชๅˆ†ใ ใ‘ใฎๅ€‹ๆ€งใ‚’่กจ็พใงใใ‚‹ใ‚ˆใ†ใซใชใ‚Šใพใ—ใŸใ€‚

// ใƒœใƒƒใƒˆ็”จใฎใ‚ซใ‚นใ‚ฟใƒ ็ตตๆ–‡ๅญ—ใ‚’ๅฎš็พฉ
const emojis = bot.addCustomEmojis({
  botkit: { 
    file: `${import.meta.dirname}/images/botkit.png`, 
    type: "image/png" 
  },
  fedify: { 
    url: "https://fedify.dev/logo.png", 
    type: "image/png" 
  }
});

// ใƒกใƒƒใ‚ปใƒผใ‚ธใซใ‚ซใ‚นใ‚ฟใƒ ็ตตๆ–‡ๅญ—ใ‚’ไฝฟ็”จ
await session.publish(
  text`BotKit ${customEmoji(emojis.botkit)}ใฏใ€Fedify ${customEmoji(emojis.fedify)}ใซใ‚ˆใฃใฆๆ”ฏใˆใ‚‰ใ‚Œใฆใ„ใพใ™`
);

ใ“ใฎๆ–ฐใ—ใ„APIใงใฏใ€ๆฌกใฎใ“ใจใŒๅฏ่ƒฝใซใชใ‚Šใพใ—ใŸใ€‚

ใƒชใ‚ขใ‚ฏใ‚ทใƒงใƒณใซใ‚ˆใ‚‹ใ‚ณใƒŸใƒฅใƒ‹ใ‚ฑใƒผใ‚ทใƒงใƒณ

ใ‚ณใƒŸใƒฅใƒ‹ใ‚ฑใƒผใ‚ทใƒงใƒณใฏๅ˜ใซใƒกใƒƒใ‚ปใƒผใ‚ธใ‚’ๆŠ•็จฟใ™ใ‚‹ใ ใ‘ใงใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚ไป–ใฎไบบใฎใƒกใƒƒใ‚ปใƒผใ‚ธใซๅๅฟœใ™ใ‚‹ใ“ใจใ‚‚้‡่ฆใงใ™ใ€‚ๆ–ฐใ—ใ„ใƒชใ‚ขใ‚ฏใ‚ทใƒงใƒณใ‚ทใ‚นใƒ†ใƒ ใฏใ€ใƒœใƒƒใƒˆใจใƒ•ใ‚ฉใƒญใƒฏใƒผใฎ้–“ใซ่‡ช็„ถใชไบคๆตใƒใ‚คใƒณใƒˆใ‚’ไฝœใ‚Šๅ‡บใ—ใพใ™ใ€‚

// ๆจ™ๆบ–ใฎUnicode็ตตๆ–‡ๅญ—ใงใƒกใƒƒใ‚ปใƒผใ‚ธใซใƒชใ‚ขใ‚ฏใ‚ทใƒงใƒณ
await message.react(emoji`๐Ÿ‘`);

// ใพใŸใฏๅฎš็พฉใ—ใŸใ‚ซใ‚นใ‚ฟใƒ ็ตตๆ–‡ๅญ—ใงใƒชใ‚ขใ‚ฏใ‚ทใƒงใƒณ
await message.react(emojis.botkit);

// ใƒชใ‚ขใ‚ฏใ‚ทใƒงใƒณใ‚’่ช่ญ˜ใ—ใฆๅฟœ็ญ”ใ™ใ‚‹ใƒœใƒƒใƒˆใ‚’ไฝœๆˆ
bot.onReact = async (session, reaction) => {
  await session.publish(
    text`${reaction.actor}ใ•ใ‚“ใ€็งใฎใƒกใƒƒใ‚ปใƒผใ‚ธใซ${reaction.emoji}ใงใƒชใ‚ขใ‚ฏใ‚ทใƒงใƒณใ—ใฆใใ‚Œใฆใ‚ใ‚ŠใŒใจใ†ใ”ใ–ใ„ใพใ™๏ผ`,
    { visibility: "direct" }
  );
};

ใ“ใฎๆฉŸ่ƒฝใซใ‚ˆใ‚Šใ€ใƒœใƒƒใƒˆใฏๆฌกใฎใ“ใจใŒใงใใ‚‹ใ‚ˆใ†ใซใชใ‚Šใพใ—ใŸใ€‚

  • Message.react()ใ‚’ไฝฟ็”จใ—ใฆUnicode็ตตๆ–‡ๅญ—ใงใƒกใƒƒใ‚ปใƒผใ‚ธใซใƒชใ‚ขใ‚ฏใ‚ทใƒงใƒณ
  • ๅฎš็พฉใ—ใŸใ‚ซใ‚นใ‚ฟใƒ ็ตตๆ–‡ๅญ—ใงใƒชใ‚ขใ‚ฏใ‚ทใƒงใƒณ
  • Bot.onReactใจBot.onUnreactใƒใƒณใƒ‰ใƒฉใƒผใงใƒชใ‚ขใ‚ฏใ‚ทใƒงใƒณใ‚คใƒ™ใƒณใƒˆใ‚’ๅ‡ฆ็†

ๅผ•็”จใซใ‚ˆใ‚‹ไผš่ฉฑ

่ญฐ่ซ–ใงใฏใ€ไป–ใฎไบบใŒ่จ€ใฃใŸใ“ใจใ‚’ๅ‚็…งใ™ใ‚‹ๅฟ…่ฆใŒใ—ใฐใ—ใฐใ‚ใ‚Šใพใ™ใ€‚ๆ–ฐใ—ใ„ๅผ•็”จๆฉŸ่ƒฝใซใ‚ˆใ‚Šใ€ใ‚ˆใ‚Š็ตๆŸๅŠ›ใฎใ‚ใ‚‹ไผš่ฉฑใ‚นใƒฌใƒƒใƒ‰ใ‚’ไฝœๆˆใงใใพใ™ใ€‚

// ใƒœใƒƒใƒˆใฎๆŠ•็จฟใงไป–ใฎใƒกใƒƒใ‚ปใƒผใ‚ธใ‚’ๅผ•็”จ
await session.publish(
  text`ใ“ใฎ่ˆˆๅ‘ณๆทฑใ„่ฆ–็‚นใซใคใ„ใฆ็ญ”ใˆใพใ™...`,
  { quoteTarget: originalMessage }
);

// ใƒฆใƒผใ‚ถใƒผใŒใƒœใƒƒใƒˆใฎใƒกใƒƒใ‚ปใƒผใ‚ธใ‚’ๅผ•็”จใ—ใŸๅ ดๅˆใฎๅ‡ฆ็†
bot.onQuote = async (session, quoteMessage) => {
  await session.publish(
    text`${quoteMessage.actor}ใ•ใ‚“ใ€็งใฎ่€ƒใˆใ‚’ๅ…ฑๆœ‰ใ—ใฆใใ‚Œใฆใ‚ใ‚ŠใŒใจใ†ใ”ใ–ใ„ใพใ™๏ผ`,
    { visibility: "direct" }
  );
};

ๅผ•็”จๆฉŸ่ƒฝใซใ‚ˆใ‚Šใ€ใƒœใƒƒใƒˆใฏๆฌกใฎใ“ใจใŒใงใใ‚‹ใ‚ˆใ†ใซใชใ‚Šใพใ—ใŸใ€‚

  • quoteTargetใ‚ชใƒ—ใ‚ทใƒงใƒณใงใƒกใƒƒใ‚ปใƒผใ‚ธใ‚’ๅผ•็”จ
  • Message.quoteTargetใ‚’้€šใ˜ใฆๅผ•็”จใ•ใ‚ŒใŸใƒกใƒƒใ‚ปใƒผใ‚ธใซใ‚ขใ‚ฏใ‚ปใ‚น
  • ๆ–ฐใ—ใ„Bot.onQuoteใ‚คใƒ™ใƒณใƒˆใƒใƒณใƒ‰ใƒฉใƒผใงๅผ•็”จใ‚คใƒ™ใƒณใƒˆใ‚’ๅ‡ฆ็†

่ฆ–่ฆš็š„ใชๆ”นๅ–„

ใ‚ณใƒŸใƒฅใƒ‹ใ‚ฑใƒผใ‚ทใƒงใƒณใซใฏ่ฆ–่ฆš็š„่ฆ็ด ใ‚‚้‡่ฆใชใŸใ‚ใ€ใƒœใƒƒใƒˆใฎ่กจ็พๆ–นๆณ•ใ‚’ๆ”นๅ–„ใ—ใพใ—ใŸใ€‚

  • ใ‚ฆใ‚งใƒ–ใ‚คใƒณใ‚ฟใƒผใƒ•ใ‚งใƒผใ‚นใง็”ปๅƒๆทปไป˜ใƒ•ใ‚กใ‚คใƒซใŒๆญฃใ—ใ่กจ็คบใ•ใ‚Œใ‚‹ใ‚ˆใ†ใซใชใ‚Šใพใ—ใŸ
  • ใƒœใƒƒใƒˆใฎใ‚ณใƒณใƒ†ใƒณใƒ„ใŒใ‚ˆใ‚Š่ฆ‹ใ‚„ใ™ใใชใ‚Šใ€่ฑŠใ‹ใชไฝ“้จ“ใ‚’ๆไพ›ใ—ใพใ™

ๅ†…้ƒจๆ”นๅ–„๏ผšๆดปๅ‹•ใฎไผๆ’ญใฎๅผทๅŒ–

ใƒ•ใ‚งใƒ‡ใ‚ฃใƒใƒผใ‚นใงใฎๆดปๅ‹•ใŒไผๆ’ญใ™ใ‚‹ๆ–นๆณ•ใ‚‚ๆ”นๅ–„ใ•ใ‚Œใพใ—ใŸใ€‚

  • ่ฟ”ไฟกใ€ๅ…ฑๆœ‰ใ€ๆ›ดๆ–ฐใ€ๅ‰Š้™คใฎใ‚ˆใ‚Šๆญฃ็ขบใชไผๆ’ญ
  • ๅ…ƒใฎใƒกใƒƒใ‚ปใƒผใ‚ธไฝœๆˆ่€…ใซๆดปๅ‹•ใŒ้ฉๅˆ‡ใซ้€ไฟกใ•ใ‚Œใพใ™

ใ“ใ‚Œใ‚‰ใฎๆ”นๅ–„ใซใ‚ˆใ‚Šใ€ๆง˜ใ€…ใชใƒ•ใ‚งใƒ‡ใ‚ฃใƒใƒผใ‚นใƒ—ใƒฉใƒƒใƒˆใƒ•ใ‚ฉใƒผใƒ ใงใฎใƒœใƒƒใƒˆใฎ็›ธไบ’ไฝœ็”จใŒไธ€่ฒซๆ€งใจไฟก้ ผๆ€งใ‚’ๆŒใคใ‚ˆใ†ใซใชใ‚Šใพใ™ใ€‚

BotKit 0.2.0ใงๆœ€ๅˆใฎไธ€ๆญฉใ‚’่ธใฟๅ‡บใ™

ใ“ใ‚Œใ‚‰ใฎๆ–ฐๆฉŸ่ƒฝใ‚’ไฝ“้จ“ใ—ใฆใฟใŸใ„ใงใ™ใ‹๏ผŸBotKit 0.2.0ใฏJSRใงๅˆฉ็”จๅฏ่ƒฝใงใ€็ฐกๅ˜ใชใ‚ณใƒžใƒณใƒ‰ใงใ‚คใƒณใ‚นใƒˆใƒผใƒซใงใใพใ™ใ€‚

deno add jsr:@fedify/botkit@0.2.0

BotKitใฏTemporal API๏ผˆJavaScriptใงใฏใพใ ่ฉฆ้จ“็š„ใชๆฉŸ่ƒฝ๏ผ‰ใ‚’ไฝฟ็”จใ™ใ‚‹ใŸใ‚ใ€deno.jsonใงใ“ใ‚Œใ‚’ๆœ‰ๅŠนใซใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚

{
  "imports": {
    "@fedify/botkit": "jsr:@fedify/botkit@0.2.0"
  },
  "unstable": ["temporal"]
}

ใ“ใ‚Œใ‚‰ใฎ็ฐกๅ˜ใชใ‚นใƒ†ใƒƒใƒ—ใงใ€ๆœ€ๆ–ฐๆฉŸ่ƒฝใ‚’ไฝฟใฃใฆใƒ•ใ‚งใƒ‡ใ‚ฃใƒใƒผใ‚นใƒœใƒƒใƒˆใ‚’ไฝœๆˆใพใŸใฏใ‚ขใƒƒใƒ—ใ‚ฐใƒฌใƒผใƒ‰ใ™ใ‚‹ๆบ–ๅ‚™ใŒๆ•ดใ„ใพใ—ใŸใ€‚

ไปŠๅพŒใฎๅฑ•ๆœ›

#BotKit 0.2.0ใฏใ€ใƒ•ใ‚งใƒ‡ใ‚ฃใƒใƒผใ‚นใƒœใƒƒใƒˆ้–‹็™บใ‚’ใ‚ขใ‚ฏใ‚ปใ‚นใ—ใ‚„ใ™ใใ€ๅผทๅŠ›ใ‹ใคๆฅฝใ—ใ„ใ‚‚ใฎใซใ™ใ‚‹ใŸใ‚ใฎ็งใŸใกใฎ็ถ™็ถš็š„ใชๅ–ใ‚Š็ต„ใฟใ‚’็คบใ—ใฆใ„ใพใ™ใ€‚ใ“ใ‚Œใ‚‰ใฎๆ–ฐๆฉŸ่ƒฝใŒใ€็š†ใ•ใ‚“ใฎใƒœใƒƒใƒˆใ‚’ใƒ•ใ‚งใƒ‡ใ‚ฃใƒใƒผใ‚นใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใงใ‚ˆใ‚Š้ญ…ๅŠ›็š„ใงใ‚คใƒณใ‚ฟใƒฉใ‚ฏใƒ†ใ‚ฃใƒ–ใชใƒกใƒณใƒใƒผใซใ™ใ‚‹ใฎใซๅฝน็ซ‹ใคใจไฟกใ˜ใฆใ„ใพใ™ใ€‚

ๅฎŒๅ…จใชใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใจ่ฉณ็ดฐใชไพ‹ใซใคใ„ใฆใฏใ€็งใŸใกใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใ‚ตใ‚คใƒˆใ‚’ใ”่ฆงใใ ใ•ใ„ใ€‚

ใƒ•ใ‚ฃใƒผใƒ‰ใƒใƒƒใ‚ฏใ€ๆฉŸ่ƒฝใƒชใ‚ฏใ‚จใ‚นใƒˆใ€ใ‚ณใƒผใƒ‰่ฒข็Œฎใ‚’้€šใ˜ใฆใ“ใฎใƒชใƒชใƒผใ‚นใซ่ฒข็Œฎใ—ใฆใใ ใ•ใฃใŸใ™ในใฆใฎๆ–นใ€…ใซๆ„Ÿ่ฌใ—ใพใ™ใ€‚BotKitใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใฏๆˆ้•ทใ‚’็ถšใ‘ใฆใŠใ‚Šใ€็š†ใ•ใ‚“ใŒไฝœๆˆใ™ใ‚‹ใ‚‚ใฎใ‚’ๆฅฝใ—ใฟใซใ—ใฆใ„ใพใ™๏ผ

BotKitใฏใ€ActivityPubใ‚ตใƒผใƒใƒผใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใ‚’ไฝœๆˆใ™ใ‚‹ใŸใ‚ใฎไฝŽใƒฌใƒ™ใƒซใƒ•ใƒฌใƒผใƒ ใƒฏใƒผใ‚ฏFedifyใซใ‚ˆใฃใฆๆ”ฏใˆใ‚‰ใ‚Œใฆใ„ใพใ™ใ€‚

#fedidev #ใƒ•ใ‚งใƒ‡ใ‚ฃใƒใƒผใ‚น #ใ‚ซใ‚นใ‚ฟใƒ ็ตตๆ–‡ๅญ— #็ตตๆ–‡ๅญ—ใƒชใ‚ขใ‚ฏใ‚ทใƒงใƒณ #็ตตๆ–‡ๅญ—ๅๅฟœ #ๅผ•็”จ

BotKit by Fedify :botkit:botkit@hollo.social
2025-04-21

BotKit 0.2.0 ๋ฆด๋ฆฌ์Šค

BotKit 0.2.0 ๋ฒ„์ „์ด ๋ฆด๋ฆฌ์Šค๋˜์—ˆ์Šต๋‹ˆ๋‹ค! BotKit์„ ์ฒ˜์Œ ์ ‘ํ•˜์‹œ๋Š” ๋ถ„๋“ค์„ ์œ„ํ•ด ๊ฐ„๋‹จํžˆ ์†Œ๊ฐœํ•˜์ž๋ฉด, BotKit์€ TypeScript๋กœ ๊ฐœ๋ฐœ๋œ ๋…๋ฆฝํ˜• #ActivityPub ๋ด‡ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. Mastodon, Misskey ๋“ฑ ๋‹ค์–‘ํ•œ #์—ฐํ•ฉ์šฐ์ฃผ(#fediverse) ํ”Œ๋žซํผ๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ธฐ์กด ํ”Œ๋žซํผ์˜ ์ œ์•ฝ์—์„œ ๋ฒ—์–ด๋‚˜ ์ž์œ ๋กญ๊ฒŒ ๋ด‡์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ๋ฆด๋ฆฌ์Šค๋Š” ์—ฐํ•ฉ์šฐ์ฃผ ๋ด‡ ๊ฐœ๋ฐœ์„ ๋” ์‰ฝ๊ณ  ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์—ฌ์ •์—์„œ ์ค‘์š”ํ•œ ๋ฐœ๊ฑธ์Œ์ž…๋‹ˆ๋‹ค. ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์š”์ฒญํ•ด ์™”๋˜ ์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ๋“ค์„ ์ƒˆ๋กญ๊ฒŒ ์„ ๋ณด์ž…๋‹ˆ๋‹ค.

๋” ๋‚˜์€ ๋ด‡ ์ƒํ˜ธ์ž‘์šฉ์„ ์œ„ํ•œ ์—ฌ์ •

BotKit์„ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ์šฐ๋ฆฌ๋Š” ํ•ญ์ƒ ๋ด‡์ด ๋” ํ‘œํ˜„๋ ฅ ์žˆ๊ณ  ์ƒํ˜ธ์ž‘์šฉ์ด ํ’๋ถ€ํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ๋ฐ ์ง‘์ค‘ํ•ด ์™”์Šต๋‹ˆ๋‹ค. 0.2.0 ๋ฒ„์ „์—์„œ๋Š” ์—ฐํ•ฉ์šฐ์ฃผ์˜ ์‚ฌํšŒ์  ์ธก๋ฉด์„ ๋ด‡์— ์ ‘๋ชฉ์‹œ์ผœ ํ•œ ๋‹จ๊ณ„ ๋” ๋ฐœ์ „์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

์ปค์Šคํ…€ ์—๋ชจ์ง€๋กœ ๋ด‡์˜ ๊ฐœ์„ฑ ํ‘œํ˜„ํ•˜๊ธฐ

๊ฐ€์žฅ ๋งŽ์ด ์š”์ฒญ๋ฐ›์•˜๋˜ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๊ฐ€ #์ปค์Šคํ…€_์—๋ชจ์ง€ ์ง€์›์ž…๋‹ˆ๋‹ค. ์ด์ œ ๋ด‡์€ ๋…ํŠนํ•œ ์‹œ๊ฐ์  ์š”์†Œ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋‹๋ณด์ด๊ฒŒ ํ•˜๋ฉฐ ์ž์‹ ๋งŒ์˜ ๊ฐœ์„ฑ์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ๋ด‡์˜ ์ปค์Šคํ…€ ์—๋ชจ์ง€ ์ •์˜ํ•˜๊ธฐ
const emojis = bot.addCustomEmojis({
  botkit: { 
    file: `${import.meta.dirname}/images/botkit.png`, 
    type: "image/png" 
  },
  fedify: { 
    url: "https://fedify.dev/logo.png", 
    type: "image/png" 
  }
});

// ๋ฉ”์‹œ์ง€์— ์ปค์Šคํ…€ ์—๋ชจ์ง€ ์‚ฌ์šฉํ•˜๊ธฐ
await session.publish(
  text`BotKit ${customEmoji(emojis.botkit)}์€ Fedify ${customEmoji(emojis.fedify)}์˜ ์ง€์›์„ ๋ฐ›์Šต๋‹ˆ๋‹ค`
);

์ด ์ƒˆ๋กœ์šด API๋ฅผ ํ†ตํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘์„ ํ†ตํ•œ ์†Œํ†ต

์†Œํ†ต์€ ๋‹จ์ˆœํžˆ ๋ฉ”์‹œ์ง€๋ฅผ ๊ฒŒ์‹œํ•˜๋Š” ๊ฒƒ๋งŒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๋ฉ”์‹œ์ง€์— ๋ฐ˜์‘ํ•˜๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ฐ˜์‘ ์‹œ์Šคํ…œ์€ ๋ด‡๊ณผ ํŒ”๋กœ์›Œ ์‚ฌ์ด์— ์ž์—ฐ์Šค๋Ÿฌ์šด ์ƒํ˜ธ์ž‘์šฉ ์ง€์ ์„ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

// ํ‘œ์ค€ ์œ ๋‹ˆ์ฝ”๋“œ ์—๋ชจ์ง€๋กœ ๋ฉ”์‹œ์ง€์— ๋ฐ˜์‘ํ•˜๊ธฐ
await message.react(emoji`๐Ÿ‘`);

// ๋˜๋Š” ์ •์˜ํ•œ ์ปค์Šคํ…€ ์—๋ชจ์ง€๋กœ ๋ฐ˜์‘ํ•˜๊ธฐ
await message.react(emojis.botkit);

// ๋ฐ˜์‘์„ ์ธ์‹ํ•˜๊ณ  ์‘๋‹ตํ•˜๋Š” ๋ด‡ ๋งŒ๋“ค๊ธฐ
bot.onReact = async (session, reaction) => {
  await session.publish(
    text`${reaction.actor}๋‹˜, ์ œ ๋ฉ”์‹œ์ง€์— ${reaction.emoji} ๋ฐ˜์‘์„ ๋‚จ๊ฒจ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!`,
    { visibility: "direct" }
  );
};

์ด ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๋ด‡์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Message.react()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์œ ๋‹ˆ์ฝ”๋“œ ์—๋ชจ์ง€๋กœ ๋ฉ”์‹œ์ง€์— ๋ฐ˜์‘ํ•˜๊ธฐ
  • ์ •์˜ํ•œ ์ปค์Šคํ…€ ์—๋ชจ์ง€๋กœ ๋ฐ˜์‘ํ•˜๊ธฐ
  • Bot.onReact์™€ Bot.onUnreact ํ•ธ๋“ค๋Ÿฌ๋กœ ๋ฐ˜์‘ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌํ•˜๊ธฐ

์ธ์šฉ์„ ํ†ตํ•œ ๋Œ€ํ™”

ํ† ๋ก ์—์„œ๋Š” ์ข…์ข… ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๋งํ•œ ๋‚ด์šฉ์„ ์ฐธ์กฐํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด #์ธ์šฉ ๊ธฐ๋Šฅ์€ ๋” ์‘์ง‘๋ ฅ ์žˆ๋Š” ๋Œ€ํ™” ์Šค๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

// ๋ด‡์˜ ๊ฒŒ์‹œ๋ฌผ์—์„œ ๋‹ค๋ฅธ ๋ฉ”์‹œ์ง€ ์ธ์šฉํ•˜๊ธฐ
await session.publish(
  text`์ด ํฅ๋ฏธ๋กœ์šด ๊ด€์ ์— ๋Œ€ํ•œ ๋‹ต๋ณ€์ž…๋‹ˆ๋‹ค...`,
  { quoteTarget: originalMessage }
);

// ์‚ฌ์šฉ์ž๊ฐ€ ๋ด‡์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ธ์šฉํ•  ๋•Œ ์ฒ˜๋ฆฌํ•˜๊ธฐ
bot.onQuote = async (session, quoteMessage) => {
  await session.publish(
    text`${quoteMessage.actor}๋‹˜, ์ œ ์ƒ๊ฐ์„ ๊ณต์œ ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!`,
    { visibility: "direct" }
  );
};

์ธ์šฉ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๋ด‡์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • quoteTarget ์˜ต์…˜์œผ๋กœ ๋ฉ”์‹œ์ง€ ์ธ์šฉํ•˜๊ธฐ
  • Message.quoteTarget์„ ํ†ตํ•ด ์ธ์šฉ๋œ ๋ฉ”์‹œ์ง€์— ์ ‘๊ทผํ•˜๊ธฐ
  • ์ƒˆ๋กœ์šด Bot.onQuote ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋กœ ์ธ์šฉ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌํ•˜๊ธฐ

์‹œ๊ฐ์  ๊ฐœ์„ 

์†Œํ†ต์€ ์‹œ๊ฐ์ ์ธ ์š”์†Œ๋„ ์ค‘์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ด‡์˜ ํ‘œํ˜„ ๋ฐฉ์‹์„ ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์›น ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์ด๋ฏธ์ง€ ์ฒจ๋ถ€ํŒŒ์ผ์ด ์ œ๋Œ€๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค
  • ๋ด‡์˜ ์ฝ˜ํ…์ธ ๊ฐ€ ๋” ๋ณด๊ธฐ ์ข‹์•„์ง€๊ณ  ํ’๋ถ€ํ•œ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค

๋‚ด๋ถ€ ๊ฐœ์„ : ํ–ฅ์ƒ๋œ ์•กํ‹ฐ๋น„ํ‹ฐ ์ „ํŒŒ

์—ฐํ•ฉ์šฐ์ฃผ์—์„œ ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์ „ํŒŒ๋˜๋Š” ๋ฐฉ์‹๋„ ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๋‹ต๊ธ€, ๊ณต์œ , ์—…๋ฐ์ดํŠธ, ์‚ญ์ œ์˜ ๋” ์ •ํ™•ํ•œ ์ „ํŒŒ
  • ์›๋ณธ ๋ฉ”์‹œ์ง€ ์ž‘์„ฑ์ž์—๊ฒŒ ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์ œ๋Œ€๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค

์ด๋Ÿฌํ•œ ๊ฐœ์„  ์‚ฌํ•ญ์€ ๋‹ค์–‘ํ•œ ์—ฐํ•ฉ์šฐ์ฃผ ํ”Œ๋žซํผ์—์„œ ๋ด‡์˜ ์ƒํ˜ธ์ž‘์šฉ์ด ์ผ๊ด€๋˜๊ณ  ์•ˆ์ •์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

BotKit 0.2.0์œผ๋กœ ์ฒซ ๊ฑธ์Œ ๋–ผ๊ธฐ

์ด๋Ÿฌํ•œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๊ฒฝํ—˜ํ•ด ๋ณด๊ณ  ์‹ถ์œผ์‹ ๊ฐ€์š”? BotKit 0.2.0์€ JSR์—์„œ ๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ฐ„๋‹จํ•œ ๋ช…๋ น์–ด๋กœ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

deno add jsr:@fedify/botkit@0.2.0

BotKit์€ Temporal API(JavaScript์—์„œ ์•„์ง ์‹œ๋ฒ”์ ์ธ ๊ธฐ๋Šฅ)๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ deno.json์—์„œ ์ด๋ฅผ ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

{
  "imports": {
    "@fedify/botkit": "jsr:@fedify/botkit@0.2.0"
  },
  "unstable": ["temporal"]
}

์ด ๊ฐ„๋‹จํ•œ ๋‹จ๊ณ„๋ฅผ ํ†ตํ•ด ์ตœ์‹  ๊ธฐ๋Šฅ์œผ๋กœ ์—ฐํ•ฉ์šฐ์ฃผ ๋ด‡์„ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์—…๊ทธ๋ ˆ์ด๋“œํ•  ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์•ž์œผ๋กœ์˜ ์ „๋ง

BotKit 0.2.0์€ ์—ฐํ•ฉ์šฐ์ฃผ ๋ด‡ ๊ฐœ๋ฐœ์„ ์ ‘๊ทผํ•˜๊ธฐ ์‰ฝ๊ณ , ๊ฐ•๋ ฅํ•˜๋ฉฐ, ์ฆ๊ฒ๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์šฐ๋ฆฌ์˜ ์ง€์†์ ์ธ ๋…ธ๋ ฅ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ๋“ค์ด ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ด‡์ด ์—ฐํ•ฉ์šฐ์ฃผ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๋” ๋งค๋ ฅ์ ์ด๊ณ  ์ƒํ˜ธ์ž‘์šฉ์ด ํ’๋ถ€ํ•œ ๊ตฌ์„ฑ์›์ด ๋˜๋Š” ๋ฐ ๋„์›€์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค.

์ „์ฒด ๋ฌธ์„œ์™€ ๋” ๋งŽ์€ ์˜ˆ์ œ๋Š” ์ €ํฌ ๋ฌธ์„œ ์‚ฌ์ดํŠธ์—์„œ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”ผ๋“œ๋ฐฑ, ๊ธฐ๋Šฅ ์š”์ฒญ, ์ฝ”๋“œ ๊ธฐ์—ฌ๋ฅผ ํ†ตํ•ด ์ด๋ฒˆ ๋ฆด๋ฆฌ์Šค์— ๋„์›€์„ ์ฃผ์‹  ๋ชจ๋“  ๋ถ„๋“ค๊ป˜ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. BotKit ์ปค๋ฎค๋‹ˆํ‹ฐ๋Š” ๊ณ„์† ์„ฑ์žฅํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์—ฌ๋Ÿฌ๋ถ„์ด ๋งŒ๋“ค์–ด๋‚ผ ์ž‘ํ’ˆ๋“ค์„ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค!

BotKit์€ ActivityPub ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ํ•˜์œ„ ๋ ˆ๋ฒจ ํ”„๋ ˆ์ž„์›Œํฌ์ธ Fedify์˜ ์ง€์›์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

#fedidev #์ปค๋ชจ์ง€ #์ปค์Šคํ…€_์ด๋ชจ์ง€ #์—๋ชจ์ง€_๋ฐ˜์‘ #์ด๋ชจ์ง€_๋ฐ˜์‘ #์—๋ชจ์ง€_๋ฆฌ์•ก์…˜ #์ด๋ชจ์ง€_๋ฆฌ์•ก์…˜

BotKit by Fedify :botkit:botkit@hollo.social
2025-04-21

BotKit 0.2.0 Released

We're pleased to announce the release of BotKit 0.2.0! For those new to our project, #BotKit is a #TypeScript framework for creating standalone #ActivityPub bots that can interact with Mastodon, Misskey, and other #fediverse platforms without the constraints of these existing platforms.

This release marks an important step in our journey to make fediverse bot development more accessible and powerful, introducing several features that our community has been requesting.

The Journey to Better Bot Interactions

In building BotKit, we've always focused on making bots more expressive and interactive. With version 0.2.0, we're taking this to the next level by bringing the social aspects of the fediverse to your bots.

Expressing Your Bot's Personality with Custom Emojis

One of the most requested features has been #custom_emoji support. Now your bots can truly express their personality with unique visuals that make their messages stand out.

// Define custom emojis for your bot
const emojis = bot.addCustomEmojis({
  botkit: { 
    file: `${import.meta.dirname}/images/botkit.png`, 
    type: "image/png" 
  },
  fedify: { 
    url: "https://fedify.dev/logo.png", 
    type: "image/png" 
  }
});

// Use these custom emojis in your messages
await session.publish(
  text`BotKit ${customEmoji(emojis.botkit)} is powered by Fedify ${customEmoji(emojis.fedify)}`
);

With this new API, you can:

Engaging Through Reactions

Communication isn't just about posting messagesโ€”it's also about responding to others. The new reaction system creates natural interaction points between your bot and its followers:

// React to a message with a standard Unicode emoji
await message.react(emoji`๐Ÿ‘`);

// Or use one of your custom emojis as a reaction
await message.react(emojis.botkit);

// Create a responsive bot that acknowledges reactions
bot.onReact = async (session, reaction) => {
  await session.publish(
    text`Thanks for reacting with ${reaction.emoji} to my message, ${reaction.actor}!`,
    { visibility: "direct" }
  );
};

This feature allows your bot to:

Conversations Through Quotes

Discussions often involve referencing what others have said. Our new #quote support enables more cohesive conversation threads:

// Quote another message in your bot's post
await session.publish(
  text`Responding to this interesting point...`,
  { quoteTarget: originalMessage }
);

// Handle when users quote your bot's messages
bot.onQuote = async (session, quoteMessage) => {
  await session.publish(
    text`Thanks for sharing my thoughts, ${quoteMessage.actor}!`,
    { visibility: "direct" }
  );
};

With quote support, your bot can:

Visual Enhancements

Because communication is visual too, we've improved how your bot presents itself:

  • Image attachments now properly display in the web interface
  • Your bot's content looks better and provides a richer experience

Behind the Scenes: Enhanced Activity Propagation

We've also improved how activities propagate through the fediverse:

  • More precise propagation of replies, shares, updates, and deletes
  • Activities are now properly sent to the original message authors

These improvements ensure your bot's interactions are consistent and reliable across different fediverse platforms.

Taking Your First Steps with BotKit 0.2.0

Ready to experience these new features? BotKit 0.2.0 is available on JSR and can be installed with a simple command:

deno add jsr:@fedify/botkit@0.2.0

Since BotKit uses the Temporal API (which is still evolving in JavaScript), remember to enable it in your deno.json:

{
  "imports": {
    "@fedify/botkit": "jsr:@fedify/botkit@0.2.0"
  },
  "unstable": ["temporal"]
}

With these simple steps, you're ready to create or upgrade your fediverse bot with our latest features.

Looking Forward

BotKit 0.2.0 represents our ongoing commitment to making fediverse bot development accessible, powerful, and enjoyable. We believe these new features will help your bots become more engaging and interactive members of the fediverse community.

For complete docs and more examples, visit our docs site.

Thank you to everyone who contributed to this release through feedback, feature requests, and code contributions. The BotKit community continues to grow, and we're excited to see what you'll create!

BotKit is powered by Fedify, a lower-level framework for creating ActivityPub server applications.

#fedidev #emoji_reaction

BotKit by Fedify :botkit:botkit@hollo.social
2025-04-21

Coming soon in #BotKit 0.2.0: Native #quote post support!

We're excited to share a preview of the upcoming quoting features in BotKit 0.2.0. This update will make it easier for your bots to engage with quoted content across the fediverse.

The quoting feature set includes:

Here's a quick example of how you can use the quote detection:

bot.onQuote = async (session, quote) => {
  // The quote parameter is a Message object representing the post that quoted your bot
  await quote.reply(text`Thanks for quoting my post, ${quote.actor}!`);
  
  // You can access the original quoted message
  const originalPost = quote.quoteTarget;
  console.log(`Original message: ${originalPost?.text}`);
};

And creating quote posts is just as simple:

// Quote in a new post
await session.publish(
  text`I'm quoting this interesting message!`,
  { quoteTarget: someMessage }
);

// Or quote in a reply
await message.reply(
  text`Interesting point! I'm quoting another relevant post here.`,
  { quoteTarget: anotherMessage }
);

Remember that quoting behavior may vary across different #ActivityPub implementationsโ€”some platforms like Misskey display quotes prominently, while others like Mastodon might implement them differently.

Want to try these features right now? You can install the development version from JSR:

deno add jsr:@fedify/botkit@0.2.0-dev.90+d6ab4bdc

We're looking forward to seeing how you use these quoting capabilities in your bots!

#fedidev

BotKit by Fedify :botkit:botkit@hollo.social
2025-04-20

We're excited to introduce emoji reactions in the upcoming #BotKit 0.2.0 release!

With the new Message.react() method, your bot can now react to messages using standard Unicode #emojis:

await message.react(emoji`๐Ÿ‘`);

#Custom_emoji support is also included, allowing your bot to react with server-specific emojis:

const emojis = bot.addCustomEmojis({
  // Use a remote image URL:
  yesBlob: {
    url: "https://cdn3.emoji.gg/emojis/68238-yesblob.png",
    mediaType: "image/png",
  },
  // Use a local image file:
  noBlob: {
    file: `${import.meta.dirname}/emojis/no_blob.png`,
    mediaType: "image/webp",
  },
});

await message.react(emojis.yesBlob);

Reactions can be removed using the AuthorizedReaction.unreact() method:

const reaction = await message.react(emoji`โค๏ธ`);
await reaction.unreact();

Want to try these features now? You can install the development version from JSR today:

deno add jsr:@fedify/botkit@0.2.0-dev.84+c997c6a6

We're looking forward to seeing how your bots express themselves with this new feature!

#emoji_reaction #fedidev #ActivityPub

BotKit by Fedify :botkit:botkit@hollo.social
2025-04-20

We're excited to announce that #BotKit 0.2.0 will introduce custom emoji support! This feature allows your bots to express themselves with more personality and engagement.

What's included:

  • Add custom emojis to your bot with Bot.addCustomEmojis()
  • Use emoji in messages with the customEmoji() function
  • Support for both local image files and remote URLs as emoji sources
  • Full integration with BotKit's text formatting system

Simple example:

// Define custom emojis
const emojis = bot.addCustomEmojis({
  botkit: { file: "./botkit.png", type: "image/png" },
  fedify: { url: "https://fedify.dev/logo.png", type: "image/png" }
});

// Use in messages
await session.publish(
  text`Hello world! ${customEmoji(emojis.botkit)}`
);

Want to try it early? You can install the development version from JSR today:

deno add jsr:@fedify/botkit@0.2.0-dev.82+8a0438e6

#ActivityPub #fedidev #custom_emoji

Client Info

Server: https://mastodon.social
Version: 2025.04
Repository: https://github.com/cyevgeniy/lmst