@fedify/botkit 0.4.0-dev.181 → 0.4.0-dev.182

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/bot-impl.d.ts +8 -8
  2. package/dist/bot-impl.d.ts.map +1 -1
  3. package/dist/bot-impl.js +6 -5
  4. package/dist/bot-impl.js.map +1 -1
  5. package/dist/bot-impl.test.js +23 -9
  6. package/dist/bot-impl.test.js.map +1 -1
  7. package/dist/bot.d.ts +3 -3
  8. package/dist/bot.d.ts.map +1 -1
  9. package/dist/bot.js +2 -3
  10. package/dist/bot.js.map +1 -1
  11. package/dist/bot.test.js.map +1 -1
  12. package/dist/components/FollowButton.d.ts +2 -2
  13. package/dist/components/Follower.d.ts +1 -1
  14. package/dist/components/Follower.js +1 -1
  15. package/dist/components/Follower.js.map +1 -1
  16. package/dist/components/Message.d.ts.map +1 -1
  17. package/dist/components/Message.js +3 -3
  18. package/dist/components/Message.js.map +1 -1
  19. package/dist/deno.js +3 -2
  20. package/dist/deno.js.map +1 -1
  21. package/dist/emoji.d.ts +1 -1
  22. package/dist/emoji.js.map +1 -1
  23. package/dist/events.d.ts +1 -1
  24. package/dist/follow-impl.d.ts +1 -1
  25. package/dist/follow-impl.js +1 -1
  26. package/dist/follow-impl.js.map +1 -1
  27. package/dist/follow-impl.test.js +4 -5
  28. package/dist/follow-impl.test.js.map +1 -1
  29. package/dist/follow.d.ts +1 -1
  30. package/dist/message-impl.d.ts +2 -3
  31. package/dist/message-impl.d.ts.map +1 -1
  32. package/dist/message-impl.js +3 -3
  33. package/dist/message-impl.js.map +1 -1
  34. package/dist/message-impl.test.js +1 -1
  35. package/dist/message-impl.test.js.map +1 -1
  36. package/dist/message.d.ts +3 -4
  37. package/dist/message.d.ts.map +1 -1
  38. package/dist/message.js +2 -3
  39. package/dist/mod.d.ts +3 -3
  40. package/dist/mod.js +3 -3
  41. package/dist/pages.d.ts +2 -2
  42. package/dist/pages.js +1 -1
  43. package/dist/pages.js.map +1 -1
  44. package/dist/poll.d.ts +1 -1
  45. package/dist/reaction.d.ts +1 -1
  46. package/dist/reaction.js +1 -1
  47. package/dist/repository.d.ts +1 -1
  48. package/dist/repository.js +1 -1
  49. package/dist/repository.js.map +1 -1
  50. package/dist/repository.test.js +1 -1
  51. package/dist/repository.test.js.map +1 -1
  52. package/dist/session-impl.d.ts +2 -1
  53. package/dist/session-impl.d.ts.map +1 -1
  54. package/dist/session-impl.js +14 -14
  55. package/dist/session-impl.js.map +1 -1
  56. package/dist/session-impl.test.d.ts +1 -1
  57. package/dist/session-impl.test.js +1 -1
  58. package/dist/session-impl.test.js.map +1 -1
  59. package/dist/session.d.ts +3 -3
  60. package/dist/session.d.ts.map +1 -1
  61. package/dist/text.d.ts +1 -1
  62. package/dist/text.js +15 -16
  63. package/dist/text.js.map +1 -1
  64. package/dist/text.test.js +22 -19
  65. package/dist/text.test.js.map +1 -1
  66. package/package.json +4 -3
package/dist/bot.d.ts CHANGED
@@ -6,8 +6,8 @@ import { CustomEmoji, DeferredCustomEmoji } from "./emoji.js";
6
6
  import { AcceptEventHandler, FollowEventHandler, LikeEventHandler, MentionEventHandler, MessageEventHandler, QuoteEventHandler, ReactionEventHandler, RejectEventHandler, ReplyEventHandler, SharedMessageEventHandler, UndoneReactionEventHandler, UnfollowEventHandler, UnlikeEventHandler, VoteEventHandler } from "./events.js";
7
7
  import { Repository } from "./repository.js";
8
8
  import { Context, Federation, KvStore, MessageQueue } from "@fedify/fedify/federation";
9
- import { Application, Application as Application$1, Image, Image as Image$1, Service, Service as Service$1 } from "@fedify/fedify/vocab";
10
- import { SemVer, Software, Software as Software$1, parseSemVer } from "@fedify/fedify/nodeinfo";
9
+ import { Application, Application as Application$1, Image, Image as Image$1, Service, Service as Service$1 } from "@fedify/vocab";
10
+ import { Software, Software as Software$1 } from "@fedify/fedify/nodeinfo";
11
11
 
12
12
  //#region src/bot.d.ts
13
13
  /**
@@ -280,5 +280,5 @@ interface PagesOptions {
280
280
  declare function createBot<TContextData = void>(options: CreateBotOptions<TContextData>): TContextData extends void ? BotWithVoidContextData : Bot<TContextData>;
281
281
  //# sourceMappingURL=bot.d.ts.map
282
282
  //#endregion
283
- export { Application, Bot, BotWithVoidContextData, CreateBotOptions, Image, PagesOptions, SemVer, Service, Software, createBot, parseSemVer };
283
+ export { Application, Bot, BotWithVoidContextData, CreateBotOptions, Image, PagesOptions, Service, Software, createBot };
284
284
  //# sourceMappingURL=bot.d.ts.map
package/dist/bot.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bot.d.ts","names":[],"sources":["../src/bot.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;UAsDiB;EAAA;;;;EAKgB,SAgBZ,UAAA,EAhBE,UAgBF,CAhBa,YAgBb,CAAA;EAAG;;;EAEZ,SAOkB,UAAA,EAAA,MAAA;EAAY;;;;;;;;EAwBJ,UAAE,CAAA,MAAA,EAAA,MAAA,GAjCnB,GAiCmB,EAAA,WAAA,EAhCvB,YAgCuB,CAAA,EA/BnC,OA+BmC,CA/B3B,YA+B2B,CAAA;EAAW;;;;;EACC,UAAtC,CAAA,OAAA,EAzBQ,OAyBR,CAzBgB,YAyBhB,CAAA,CAAA,EAzBgC,OAyBhC,CAzBwC,YAyBxC,CAAA;EAAM;;;;;;;EAeiB,KAKC,CAAA,OAAA,EApCrB,OAoCqB,EAAA,WAAA,EApCC,YAoCD,CAAA,EApCgB,OAoChB,CApCwB,QAoCxB,CAAA;EAAY;;;;;;;;;;;;EAiCV,eAA7B,CAAA,mBAAA,MAAA,CAAA,CAAA,MAAA,EAtDC,QAsDD,CAtDU,MAsDV,CAtDiB,UAsDjB,EAtD6B,WAsD7B,CAAA,CAAA,CAAA,EArDN,QAqDM,CArDG,MAqDH,CArDU,UAqDV,EArDsB,mBAqDtB,CArD0C,YAqD1C,CAAA,CAAA,CAAA;EAAgB;;;EAWkB,QAAjC,CAAA,EA3DC,kBA2DD,CA3DoB,YA2DpB,CAAA;EAAoB;;;EAqBQ,UAA7B,CAAA,EA3EI,oBA2EJ,CA3EyB,YA2EzB,CAAA;EAAgB;AAM3B;;EAAwC,cAUnB,CAAA,EAtFF,kBAsFE,CAtFiB,YAsFjB,CAAA;EAAG;;;EASqB,cAQf,CAAA,EAlGX,kBAkGW,CAlGQ,YAkGR,CAAA;EAAG;;;EAQU,SAAhB,CAAA,EArGb,mBAqGa,CArGO,YAqGP,CAAA;EAAO;AAnCiB;AAyCnD;EAAiC,OAAA,CAAA,EAtGrB,iBAsGqB,CAtGH,YAsGG,CAAA;EAAA;;;;EAgCR,OAKP,CAAA,EArIN,iBAqIM,CArIY,YAqIZ,CAAA;EAAG;;;;EAYuD,SAArC,CAAA,EA3IzB,mBA2IyB,CA3IL,YA2IK,CAAA;EAAI;;;;EA8BZ,eAMT,CAAA,EAzKF,yBAyKE,CAzKwB,YAyKxB,CAAA;EAAQ;AAeC;AAM/B;EAwCgB,MAAA,CAAA,EAjOL,gBAiOc,CAjOG,YAiOH,CAAA;EAAA;;;EACE,QACxB,CAAA,EA9NU,kBA8NV,CA9N6B,YA8N7B,CAAA;EAAY;;;AAA4C;YAxN/C,qBAAqB;;;;;cAMnB,2BAA2B;;;;;;;;;;;;;;WAe9B,iBAAiB;;;;;UAMX,sBAAA,SAA+B;;;;;;;;;8BAU3B,yBAEhB;;;;;;sBAOiB,gBAAgB;;;;;;;8BAQR,MAAM;;;;;;;iBAQnB,UAAU,QAAQ;;;;;UAMlB;;;;;;;;;;;;;;;0BAgBS,mBAAiB;;;;;;;;;;;;;qBAgBtB,cAAc;;;;kBAKjB,MAAM;;;;;mBAML,MAAM;;;;;wBAMD,eAAe,yBAAyB;;;;;;;;;;;;;;;eAiBjD;;;;;wBAMS;;;;;;mBAOL;;;;;sBAMG;;;;;;;;;;;;;mBAeH;;;;;UAMF,YAAA;;;;;;;;;;;;;;;;;;iBAwCD,wCACL,iBAAiB,gBACzB,4BAA4B,yBAAyB,IAAI"}
1
+ {"version":3,"file":"bot.d.ts","names":[],"sources":["../src/bot.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;UAkDiB;EAAA;;;;EAKgB,SAgBZ,UAAA,EAhBE,UAgBF,CAhBa,YAgBb,CAAA;EAAG;;;EAEZ,SAOkB,UAAA,EAAA,MAAA;EAAY;;;;;;;;EAwBJ,UAAE,CAAA,MAAA,EAAA,MAAA,GAjCnB,GAiCmB,EAAA,WAAA,EAhCvB,YAgCuB,CAAA,EA/BnC,OA+BmC,CA/B3B,YA+B2B,CAAA;EAAW;;;;;EACC,UAAtC,CAAA,OAAA,EAzBQ,OAyBR,CAzBgB,YAyBhB,CAAA,CAAA,EAzBgC,OAyBhC,CAzBwC,YAyBxC,CAAA;EAAM;;;;;;;EAeiB,KAKC,CAAA,OAAA,EApCrB,OAoCqB,EAAA,WAAA,EApCC,YAoCD,CAAA,EApCgB,OAoChB,CApCwB,QAoCxB,CAAA;EAAY;;;;;;;;;;;;EAiCV,eAA7B,CAAA,mBAAA,MAAA,CAAA,CAAA,MAAA,EAtDC,QAsDD,CAtDU,MAsDV,CAtDiB,UAsDjB,EAtD6B,WAsD7B,CAAA,CAAA,CAAA,EArDN,QAqDM,CArDG,MAqDH,CArDU,UAqDV,EArDsB,mBAqDtB,CArD0C,YAqD1C,CAAA,CAAA,CAAA;EAAgB;;;EAWkB,QAAjC,CAAA,EA3DC,kBA2DD,CA3DoB,YA2DpB,CAAA;EAAoB;;;EAqBQ,UAA7B,CAAA,EA3EI,oBA2EJ,CA3EyB,YA2EzB,CAAA;EAAgB;AAM3B;;EAAwC,cAUnB,CAAA,EAtFF,kBAsFE,CAtFiB,YAsFjB,CAAA;EAAG;;;EASqB,cAQf,CAAA,EAlGX,kBAkGW,CAlGQ,YAkGR,CAAA;EAAG;;;EAQU,SAAhB,CAAA,EArGb,mBAqGa,CArGO,YAqGP,CAAA;EAAO;AAnCiB;AAyCnD;EAAiC,OAAA,CAAA,EAtGrB,iBAsGqB,CAtGH,YAsGG,CAAA;EAAA;;;;EAgCR,OAKP,CAAA,EArIN,iBAqIM,CArIY,YAqIZ,CAAA;EAAG;;;;EAYuD,SAArC,CAAA,EA3IzB,mBA2IyB,CA3IL,YA2IK,CAAA;EAAI;;;;EA8BZ,eAMT,CAAA,EAzKF,yBAyKE,CAzKwB,YAyKxB,CAAA;EAAQ;AAeC;AAM/B;EAwCgB,MAAA,CAAA,EAjOL,gBAiOc,CAjOG,YAiOH,CAAA;EAAA;;;EACE,QACxB,CAAA,EA9NU,kBA8NV,CA9N6B,YA8N7B,CAAA;EAAY;;;AAA4C;YAxN/C,qBAAqB;;;;;cAMnB,2BAA2B;;;;;;;;;;;;;;WAe9B,iBAAiB;;;;;UAMX,sBAAA,SAA+B;;;;;;;;;8BAU3B,yBAEhB;;;;;;sBAOiB,gBAAgB;;;;;;;8BAQR,MAAM;;;;;;;iBAQnB,UAAU,QAAQ;;;;;UAMlB;;;;;;;;;;;;;;;0BAgBS,mBAAiB;;;;;;;;;;;;;qBAgBtB,cAAc;;;;kBAKjB,MAAM;;;;;mBAML,MAAM;;;;;wBAMD,eAAe,yBAAyB;;;;;;;;;;;;;;;eAiBjD;;;;;wBAMS;;;;;;mBAOL;;;;;sBAMG;;;;;;;;;;;;;mBAeH;;;;;UAMF,YAAA;;;;;;;;;;;;;;;;;;iBAwCD,wCACL,iBAAiB,gBACzB,4BAA4B,yBAAyB,IAAI"}
package/dist/bot.js CHANGED
@@ -3,8 +3,7 @@
3
3
  Date.prototype.toTemporalInstant = toTemporalInstant;
4
4
 
5
5
  import { BotImpl } from "./bot-impl.js";
6
- import { Application, Image, Service } from "@fedify/fedify/vocab";
7
- import { parseSemVer } from "@fedify/fedify/nodeinfo";
6
+ import { Application, Image, Service } from "@fedify/vocab";
8
7
 
9
8
  //#region src/bot.ts
10
9
  /**
@@ -120,5 +119,5 @@ function createBot(options) {
120
119
  }
121
120
 
122
121
  //#endregion
123
- export { Application, Image, Service, createBot, parseSemVer };
122
+ export { Application, Image, Service, createBot };
124
123
  //# sourceMappingURL=bot.js.map
package/dist/bot.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bot.js","names":["options: CreateBotOptions<TContextData>","b?","emojis: Readonly<Record<TEmojiName, CustomEmoji>>"],"sources":["../src/bot.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport type {\n Context,\n Federation,\n KvStore,\n MessageQueue,\n} from \"@fedify/fedify/federation\";\nimport type { Software } from \"@fedify/fedify/nodeinfo\";\nimport type { Application, Image, Service } from \"@fedify/fedify/vocab\";\nimport { BotImpl } from \"./bot-impl.ts\";\nimport type { CustomEmoji, DeferredCustomEmoji } from \"./emoji.ts\";\nimport type {\n AcceptEventHandler,\n FollowEventHandler,\n LikeEventHandler,\n MentionEventHandler,\n MessageEventHandler,\n QuoteEventHandler,\n ReactionEventHandler,\n RejectEventHandler,\n ReplyEventHandler,\n SharedMessageEventHandler,\n UndoneReactionEventHandler,\n UnfollowEventHandler,\n UnlikeEventHandler,\n VoteEventHandler,\n} from \"./events.ts\";\nimport type { Repository } from \"./repository.ts\";\nimport type { Session } from \"./session.ts\";\nimport type { Text } from \"./text.ts\";\nexport {\n parseSemVer,\n type SemVer,\n type Software,\n} from \"@fedify/fedify/nodeinfo\";\nexport { Application, Image, Service } from \"@fedify/fedify/vocab\";\n\n/**\n * A bot that can interact with the ActivityPub network.\n */\nexport interface Bot<TContextData> {\n /**\n * An internal Fedify federation instance. Normally you don't need to access\n * this directly.\n */\n readonly federation: Federation<TContextData>;\n\n /**\n * The internal identifier for the bot actor. It is used for the actor URI.\n */\n readonly identifier: string;\n\n /**\n * Gets a new session to control the bot for a specific origin and context\n * data.\n * @param origin The origin of the session. Even if a URL with some path or\n * query is passed, only the origin part will be used.\n * @param contextData The context data to pass to the federation.\n * @returns The session for the origin and context data.\n */\n getSession(\n origin: string | URL,\n contextData: TContextData,\n ): Session<TContextData>;\n\n /**\n * Gets a new session to control bot for a specific Fedify context.\n * @param context The Fedify context of the session.\n * @returns The session for the Fedify context.\n */\n getSession(context: Context<TContextData>): Session<TContextData>;\n\n /**\n * The fetch API for handling HTTP requests. You can pass this to an HTTP\n * server (e.g., `Deno.serve()`, `Bun.serve()`) to handle incoming requests.\n * @param request The request to handle.\n * @param contextData The context data to pass to the federation.\n * @returns The response to the request.\n */\n fetch(request: Request, contextData: TContextData): Promise<Response>;\n\n /**\n * Defines custom emojis for the bot. The custom emojis are used for\n * rendering the bot's profile and posts. The custom emojis are defined\n * by their names, and the names are used as the keys of the emojis.\n * @param emojis The custom emojis to define. The keys are the names of\n * the emojis, and the values are the custom emoji definitions.\n * @returns The defined emojis. The keys are the names of the emojis, and\n * the values are the emoji objects, which are used for passing\n * to the {@link customEmoji} function.\n * @throws {TypeError} If any emoji name is invalid or duplicate.\n * @since 0.2.0\n */\n addCustomEmojis<TEmojiName extends string>(\n emojis: Readonly<Record<TEmojiName, CustomEmoji>>,\n ): Readonly<Record<TEmojiName, DeferredCustomEmoji<TContextData>>>;\n\n /**\n * An event handler for a follow request to the bot.\n */\n onFollow?: FollowEventHandler<TContextData>;\n\n /**\n * An event handler for an unfollow event from the bot.\n */\n onUnfollow?: UnfollowEventHandler<TContextData>;\n\n /**\n * An event handler invoked when a follow request the bot sent is accepted.\n */\n onAcceptFollow?: AcceptEventHandler<TContextData>;\n\n /**\n * An event handler invoked when a follow request the bot sent is rejected.\n */\n onRejectFollow?: RejectEventHandler<TContextData>;\n\n /**\n * An event handler for a message mentioned to the bot.\n */\n onMention?: MentionEventHandler<TContextData>;\n\n /**\n * An event handler for a reply to the bot.\n */\n onReply?: ReplyEventHandler<TContextData>;\n\n /**\n * An event handler for a quote of the bot's message.\n * @since 0.2.0\n */\n onQuote?: QuoteEventHandler<TContextData>;\n\n /**\n * An event handler for a message shown to the bot's timeline. To listen\n * to this event, your bot needs to follow others first.\n */\n onMessage?: MessageEventHandler<TContextData>;\n\n /**\n * An event handler for a message shared to the bot. To listen to this event,\n * your bot needs to follow others first.\n */\n onSharedMessage?: SharedMessageEventHandler<TContextData>;\n\n /**\n * An event handler for a like of a message.\n */\n onLike?: LikeEventHandler<TContextData>;\n\n /**\n * An event handler for an undoing of a like of a message.\n */\n onUnlike?: UnlikeEventHandler<TContextData>;\n\n /**\n * An event handler for an emoji reaction to a message.\n * @since 0.2.0\n */\n onReact?: ReactionEventHandler<TContextData>;\n\n /**\n * An event handler for an undoing of an emoji reaction to a message.\n * @since 0.2.0\n */\n onUnreact?: UndoneReactionEventHandler<TContextData>;\n\n /**\n * An event handler for a vote in a poll. This event is only triggered when\n * the bot is the author of the poll, and the vote is made by another actor.\n * If the poll allows multiple selections, this event is triggered multiple\n * times, once for each option selected by the actor.\n *\n * Note that this event can be triggered even if the voter vote an option\n * multiple times or multiple options for a poll that disallows multiple\n * selections. You should validate the vote in the event handler by storing\n * the votes in a persistent store, and checking if the vote is valid.\n * (This behavior can subject to change in the future.)\n * @since 0.3.0\n */\n onVote?: VoteEventHandler<TContextData>;\n}\n\n/**\n * A specialized {@link Bot} tpe that doesn't require context data.\n */\nexport interface BotWithVoidContextData extends Bot<void> {\n /**\n * Gets a new session to control the bot for a specific origin and context\n * data.\n * @param origin The origin of the session. Even if a URL with some path or\n * query is passed, only the origin part will be used.\n * @param contextData The context data to pass to the federation.\n * @returns The session for the origin and context data.\n */\n getSession(\n origin: string | URL,\n contextData: void,\n ): Session<void>;\n\n /**\n * Gets a new session to control bot for a specific Fedify context.\n * @param context The Fedify context of the session.\n * @returns The session for the Fedify context.\n */\n getSession(context: Context<void>): Session<void>;\n\n /**\n * Gets a new session to control the bot for a specific origin and context\n * data.\n * @param origin The origin of the session. Even if a URL with some path or\n * query is passed, only the origin part will be used.\n */\n getSession(origin: string | URL): Session<void>;\n\n /**\n * The fetch API for handling HTTP requests. You can pass this to an HTTP\n * server (e.g., `Deno.serve()`, `Bun.serve()`) to handle incoming requests.\n * @param request The request to handle.\n * @returns The response to the request.\n */\n fetch(request: Request): Promise<Response>;\n}\n\n/**\n * Options for creating a bot.\n */\nexport interface CreateBotOptions<TContextData> {\n /**\n * The internal identifier of the bot. Since it is used for the actor URI,\n * it *should not* be changed after the bot is federated.\n *\n * If omitted, `\"bot\"` will be used.\n * @default `\"bot\"`\n */\n readonly identifier?: string;\n\n /**\n * The type of the bot actor. It should be either `Service` or `Application`.\n *\n * If omitted, `Service` will be used.\n * @default `Service`\n */\n readonly class?: typeof Service | typeof Application;\n\n /**\n * The username of the bot. It will be a part of the fediverse handle.\n * It can be changed after the bot is federated.\n */\n readonly username: string;\n\n /**\n * The display name of the bot. It can be changed after the bot is federated.\n */\n readonly name?: string;\n\n /**\n * The description of the bot. It can be changed after the bot is federated.\n */\n readonly summary?: Text<\"block\", TContextData>;\n\n /**\n * The avatar URL of the bot. It can be changed after the bot is federated.\n */\n readonly icon?: URL | Image;\n\n /**\n * The header image URL of the bot. It can be changed after the bot is\n * federated.\n */\n readonly image?: URL | Image;\n\n /**\n * The custom properties of the bot. It can be changed after the bot is\n * federated.\n */\n readonly properties?: Record<string, Text<\"block\" | \"inline\", TContextData>>;\n\n /**\n * How to handle incoming follow requests. Note that this behavior can be\n * overridden by manually invoking {@link FollowRequest.accept} or\n * {@link FollowRequest.reject} in the {@link Bot.onFollow} event handler.\n *\n * - `\"accept\"` (default): Automatically accept all incoming follow requests.\n * - `\"reject\"`: Automatically reject all incoming follow requests.\n * - `\"manual\"`: Require manual handling of incoming follow requests.\n * @default `\"accept\"`\n */\n readonly followerPolicy?: \"accept\" | \"reject\" | \"manual\";\n\n /**\n * The underlying key-value store to use for storing data.\n */\n readonly kv: KvStore;\n\n /**\n * The underlying repository to use for storing data. If omitted,\n * {@link KvRepository} will be used.\n */\n readonly repository?: Repository;\n\n /**\n * The underlying message queue to use for handling incoming and outgoing\n * activities. If omitted, incoming activities are processed immediately,\n * and outgoing activities are sent immediately.\n */\n readonly queue?: MessageQueue;\n\n /**\n * The software information of the bot. If omitted, the NodeInfo protocol\n * will be unimplemented.\n */\n readonly software?: Software;\n\n /**\n * Whether to trust `X-Forwarded-*` headers. If your bot application is\n * behind an L7 reverse proxy, turn it on.\n *\n * Turned off by default.\n * @default `false`\n */\n readonly behindProxy?: boolean;\n\n /**\n * The options for the web pages of the bot. If omitted, the default options\n * will be used.\n */\n readonly pages?: PagesOptions;\n}\n\n/**\n * Options for the web pages of the bot.\n */\nexport interface PagesOptions {\n /**\n * The color of the theme. It will be used for the theme color of the web\n * pages. The default color is `\"green\"`.\n * @default `\"green\"`\n */\n readonly color?:\n | \"amber\"\n | \"azure\"\n | \"blue\"\n | \"cyan\"\n | \"fuchsia\"\n | \"green\"\n | \"grey\"\n | \"indigo\"\n | \"jade\"\n | \"lime\"\n | \"orange\"\n | \"pink\"\n | \"pumpkin\"\n | \"purple\"\n | \"red\"\n | \"sand\"\n | \"slate\"\n | \"violet\"\n | \"yellow\"\n | \"zinc\";\n\n /**\n * The CSS code for the bot. It will be used for the custom CSS of the web\n * pages.\n */\n readonly css?: string;\n}\n\n/**\n * Creates a {@link Bot} instance.\n * @param options The options for creating the bot.\n * @returns The created bot instance.\n */\nexport function createBot<TContextData = void>(\n options: CreateBotOptions<TContextData>,\n): TContextData extends void ? BotWithVoidContextData : Bot<TContextData> {\n const bot = new BotImpl<TContextData>(options);\n // Since `deno serve` does not recognize a class instance having fetch(),\n // we wrap a BotImpl instance with a plain object.\n // See also https://github.com/denoland/deno/issues/24062\n const wrapper = {\n impl: bot,\n get federation() {\n return bot.federation;\n },\n get identifier() {\n return bot.identifier;\n },\n getSession(a, b?) {\n // @ts-ignore: BotImpl.getSession() implements Bot.getSession()\n return bot.getSession(a, b);\n },\n fetch(request, contextData) {\n return bot.fetch(request, contextData);\n },\n addCustomEmojis<TEmojiName extends string>(\n emojis: Readonly<Record<TEmojiName, CustomEmoji>>,\n ): Readonly<Record<TEmojiName, DeferredCustomEmoji<TContextData>>> {\n return bot.addCustomEmojis(emojis);\n },\n get onFollow() {\n return bot.onFollow;\n },\n set onFollow(value) {\n bot.onFollow = value;\n },\n get onUnfollow() {\n return bot.onUnfollow;\n },\n set onUnfollow(value) {\n bot.onUnfollow = value;\n },\n get onAcceptFollow() {\n return bot.onAcceptFollow;\n },\n set onAcceptFollow(value) {\n bot.onAcceptFollow = value;\n },\n get onRejectFollow() {\n return bot.onRejectFollow;\n },\n set onRejectFollow(value) {\n bot.onRejectFollow = value;\n },\n get onMention() {\n return bot.onMention;\n },\n set onMention(value) {\n bot.onMention = value;\n },\n get onReply() {\n return bot.onReply;\n },\n set onReply(value) {\n bot.onReply = value;\n },\n get onQuote() {\n return bot.onQuote;\n },\n set onQuote(value) {\n bot.onQuote = value;\n },\n get onMessage() {\n return bot.onMessage;\n },\n set onMessage(value) {\n bot.onMessage = value;\n },\n get onSharedMessage() {\n return bot.onSharedMessage;\n },\n set onSharedMessage(value) {\n bot.onSharedMessage = value;\n },\n get onLike() {\n return bot.onLike;\n },\n set onLike(value) {\n bot.onLike = value;\n },\n get onUnlike() {\n return bot.onUnlike;\n },\n set onUnlike(value) {\n bot.onUnlike = value;\n },\n get onReact() {\n return bot.onReact;\n },\n set onReact(value) {\n bot.onReact = value;\n },\n get onUnreact() {\n return bot.onUnreact;\n },\n set onUnreact(value) {\n bot.onUnreact = value;\n },\n get onVote() {\n return bot.onVote;\n },\n set onVote(value) {\n bot.onVote = value;\n },\n } satisfies Bot<TContextData> & { impl: BotImpl<TContextData> };\n // @ts-ignore: the wrapper implements BotWithVoidContextData\n return wrapper;\n}\n"],"mappings":";;;;;;;;;;;;;;AAmYA,SAAgB,UACdA,SACwE;CACxE,MAAM,MAAM,IAAI,QAAsB;CAItC,MAAM,UAAU;EACd,MAAM;EACN,IAAI,aAAa;AACf,UAAO,IAAI;EACZ;EACD,IAAI,aAAa;AACf,UAAO,IAAI;EACZ;EACD,WAAW,GAAGC,GAAI;AAEhB,UAAO,IAAI,WAAW,GAAG,EAAE;EAC5B;EACD,MAAM,SAAS,aAAa;AAC1B,UAAO,IAAI,MAAM,SAAS,YAAY;EACvC;EACD,gBACEC,QACiE;AACjE,UAAO,IAAI,gBAAgB,OAAO;EACnC;EACD,IAAI,WAAW;AACb,UAAO,IAAI;EACZ;EACD,IAAI,SAAS,OAAO;AAClB,OAAI,WAAW;EAChB;EACD,IAAI,aAAa;AACf,UAAO,IAAI;EACZ;EACD,IAAI,WAAW,OAAO;AACpB,OAAI,aAAa;EAClB;EACD,IAAI,iBAAiB;AACnB,UAAO,IAAI;EACZ;EACD,IAAI,eAAe,OAAO;AACxB,OAAI,iBAAiB;EACtB;EACD,IAAI,iBAAiB;AACnB,UAAO,IAAI;EACZ;EACD,IAAI,eAAe,OAAO;AACxB,OAAI,iBAAiB;EACtB;EACD,IAAI,YAAY;AACd,UAAO,IAAI;EACZ;EACD,IAAI,UAAU,OAAO;AACnB,OAAI,YAAY;EACjB;EACD,IAAI,UAAU;AACZ,UAAO,IAAI;EACZ;EACD,IAAI,QAAQ,OAAO;AACjB,OAAI,UAAU;EACf;EACD,IAAI,UAAU;AACZ,UAAO,IAAI;EACZ;EACD,IAAI,QAAQ,OAAO;AACjB,OAAI,UAAU;EACf;EACD,IAAI,YAAY;AACd,UAAO,IAAI;EACZ;EACD,IAAI,UAAU,OAAO;AACnB,OAAI,YAAY;EACjB;EACD,IAAI,kBAAkB;AACpB,UAAO,IAAI;EACZ;EACD,IAAI,gBAAgB,OAAO;AACzB,OAAI,kBAAkB;EACvB;EACD,IAAI,SAAS;AACX,UAAO,IAAI;EACZ;EACD,IAAI,OAAO,OAAO;AAChB,OAAI,SAAS;EACd;EACD,IAAI,WAAW;AACb,UAAO,IAAI;EACZ;EACD,IAAI,SAAS,OAAO;AAClB,OAAI,WAAW;EAChB;EACD,IAAI,UAAU;AACZ,UAAO,IAAI;EACZ;EACD,IAAI,QAAQ,OAAO;AACjB,OAAI,UAAU;EACf;EACD,IAAI,YAAY;AACd,UAAO,IAAI;EACZ;EACD,IAAI,UAAU,OAAO;AACnB,OAAI,YAAY;EACjB;EACD,IAAI,SAAS;AACX,UAAO,IAAI;EACZ;EACD,IAAI,OAAO,OAAO;AAChB,OAAI,SAAS;EACd;CACF;AAED,QAAO;AACR"}
1
+ {"version":3,"file":"bot.js","names":["options: CreateBotOptions<TContextData>","b?","emojis: Readonly<Record<TEmojiName, CustomEmoji>>"],"sources":["../src/bot.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport type {\n Context,\n Federation,\n KvStore,\n MessageQueue,\n} from \"@fedify/fedify/federation\";\nimport type { Software } from \"@fedify/fedify/nodeinfo\";\nimport type { Application, Image, Service } from \"@fedify/vocab\";\nimport { BotImpl } from \"./bot-impl.ts\";\nimport type { CustomEmoji, DeferredCustomEmoji } from \"./emoji.ts\";\nimport type {\n AcceptEventHandler,\n FollowEventHandler,\n LikeEventHandler,\n MentionEventHandler,\n MessageEventHandler,\n QuoteEventHandler,\n ReactionEventHandler,\n RejectEventHandler,\n ReplyEventHandler,\n SharedMessageEventHandler,\n UndoneReactionEventHandler,\n UnfollowEventHandler,\n UnlikeEventHandler,\n VoteEventHandler,\n} from \"./events.ts\";\nimport type { Repository } from \"./repository.ts\";\nimport type { Session } from \"./session.ts\";\nimport type { Text } from \"./text.ts\";\nexport { type Software } from \"@fedify/fedify/nodeinfo\";\nexport { Application, Image, Service } from \"@fedify/vocab\";\n\n/**\n * A bot that can interact with the ActivityPub network.\n */\nexport interface Bot<TContextData> {\n /**\n * An internal Fedify federation instance. Normally you don't need to access\n * this directly.\n */\n readonly federation: Federation<TContextData>;\n\n /**\n * The internal identifier for the bot actor. It is used for the actor URI.\n */\n readonly identifier: string;\n\n /**\n * Gets a new session to control the bot for a specific origin and context\n * data.\n * @param origin The origin of the session. Even if a URL with some path or\n * query is passed, only the origin part will be used.\n * @param contextData The context data to pass to the federation.\n * @returns The session for the origin and context data.\n */\n getSession(\n origin: string | URL,\n contextData: TContextData,\n ): Session<TContextData>;\n\n /**\n * Gets a new session to control bot for a specific Fedify context.\n * @param context The Fedify context of the session.\n * @returns The session for the Fedify context.\n */\n getSession(context: Context<TContextData>): Session<TContextData>;\n\n /**\n * The fetch API for handling HTTP requests. You can pass this to an HTTP\n * server (e.g., `Deno.serve()`, `Bun.serve()`) to handle incoming requests.\n * @param request The request to handle.\n * @param contextData The context data to pass to the federation.\n * @returns The response to the request.\n */\n fetch(request: Request, contextData: TContextData): Promise<Response>;\n\n /**\n * Defines custom emojis for the bot. The custom emojis are used for\n * rendering the bot's profile and posts. The custom emojis are defined\n * by their names, and the names are used as the keys of the emojis.\n * @param emojis The custom emojis to define. The keys are the names of\n * the emojis, and the values are the custom emoji definitions.\n * @returns The defined emojis. The keys are the names of the emojis, and\n * the values are the emoji objects, which are used for passing\n * to the {@link customEmoji} function.\n * @throws {TypeError} If any emoji name is invalid or duplicate.\n * @since 0.2.0\n */\n addCustomEmojis<TEmojiName extends string>(\n emojis: Readonly<Record<TEmojiName, CustomEmoji>>,\n ): Readonly<Record<TEmojiName, DeferredCustomEmoji<TContextData>>>;\n\n /**\n * An event handler for a follow request to the bot.\n */\n onFollow?: FollowEventHandler<TContextData>;\n\n /**\n * An event handler for an unfollow event from the bot.\n */\n onUnfollow?: UnfollowEventHandler<TContextData>;\n\n /**\n * An event handler invoked when a follow request the bot sent is accepted.\n */\n onAcceptFollow?: AcceptEventHandler<TContextData>;\n\n /**\n * An event handler invoked when a follow request the bot sent is rejected.\n */\n onRejectFollow?: RejectEventHandler<TContextData>;\n\n /**\n * An event handler for a message mentioned to the bot.\n */\n onMention?: MentionEventHandler<TContextData>;\n\n /**\n * An event handler for a reply to the bot.\n */\n onReply?: ReplyEventHandler<TContextData>;\n\n /**\n * An event handler for a quote of the bot's message.\n * @since 0.2.0\n */\n onQuote?: QuoteEventHandler<TContextData>;\n\n /**\n * An event handler for a message shown to the bot's timeline. To listen\n * to this event, your bot needs to follow others first.\n */\n onMessage?: MessageEventHandler<TContextData>;\n\n /**\n * An event handler for a message shared to the bot. To listen to this event,\n * your bot needs to follow others first.\n */\n onSharedMessage?: SharedMessageEventHandler<TContextData>;\n\n /**\n * An event handler for a like of a message.\n */\n onLike?: LikeEventHandler<TContextData>;\n\n /**\n * An event handler for an undoing of a like of a message.\n */\n onUnlike?: UnlikeEventHandler<TContextData>;\n\n /**\n * An event handler for an emoji reaction to a message.\n * @since 0.2.0\n */\n onReact?: ReactionEventHandler<TContextData>;\n\n /**\n * An event handler for an undoing of an emoji reaction to a message.\n * @since 0.2.0\n */\n onUnreact?: UndoneReactionEventHandler<TContextData>;\n\n /**\n * An event handler for a vote in a poll. This event is only triggered when\n * the bot is the author of the poll, and the vote is made by another actor.\n * If the poll allows multiple selections, this event is triggered multiple\n * times, once for each option selected by the actor.\n *\n * Note that this event can be triggered even if the voter vote an option\n * multiple times or multiple options for a poll that disallows multiple\n * selections. You should validate the vote in the event handler by storing\n * the votes in a persistent store, and checking if the vote is valid.\n * (This behavior can subject to change in the future.)\n * @since 0.3.0\n */\n onVote?: VoteEventHandler<TContextData>;\n}\n\n/**\n * A specialized {@link Bot} tpe that doesn't require context data.\n */\nexport interface BotWithVoidContextData extends Bot<void> {\n /**\n * Gets a new session to control the bot for a specific origin and context\n * data.\n * @param origin The origin of the session. Even if a URL with some path or\n * query is passed, only the origin part will be used.\n * @param contextData The context data to pass to the federation.\n * @returns The session for the origin and context data.\n */\n getSession(\n origin: string | URL,\n contextData: void,\n ): Session<void>;\n\n /**\n * Gets a new session to control bot for a specific Fedify context.\n * @param context The Fedify context of the session.\n * @returns The session for the Fedify context.\n */\n getSession(context: Context<void>): Session<void>;\n\n /**\n * Gets a new session to control the bot for a specific origin and context\n * data.\n * @param origin The origin of the session. Even if a URL with some path or\n * query is passed, only the origin part will be used.\n */\n getSession(origin: string | URL): Session<void>;\n\n /**\n * The fetch API for handling HTTP requests. You can pass this to an HTTP\n * server (e.g., `Deno.serve()`, `Bun.serve()`) to handle incoming requests.\n * @param request The request to handle.\n * @returns The response to the request.\n */\n fetch(request: Request): Promise<Response>;\n}\n\n/**\n * Options for creating a bot.\n */\nexport interface CreateBotOptions<TContextData> {\n /**\n * The internal identifier of the bot. Since it is used for the actor URI,\n * it *should not* be changed after the bot is federated.\n *\n * If omitted, `\"bot\"` will be used.\n * @default `\"bot\"`\n */\n readonly identifier?: string;\n\n /**\n * The type of the bot actor. It should be either `Service` or `Application`.\n *\n * If omitted, `Service` will be used.\n * @default `Service`\n */\n readonly class?: typeof Service | typeof Application;\n\n /**\n * The username of the bot. It will be a part of the fediverse handle.\n * It can be changed after the bot is federated.\n */\n readonly username: string;\n\n /**\n * The display name of the bot. It can be changed after the bot is federated.\n */\n readonly name?: string;\n\n /**\n * The description of the bot. It can be changed after the bot is federated.\n */\n readonly summary?: Text<\"block\", TContextData>;\n\n /**\n * The avatar URL of the bot. It can be changed after the bot is federated.\n */\n readonly icon?: URL | Image;\n\n /**\n * The header image URL of the bot. It can be changed after the bot is\n * federated.\n */\n readonly image?: URL | Image;\n\n /**\n * The custom properties of the bot. It can be changed after the bot is\n * federated.\n */\n readonly properties?: Record<string, Text<\"block\" | \"inline\", TContextData>>;\n\n /**\n * How to handle incoming follow requests. Note that this behavior can be\n * overridden by manually invoking {@link FollowRequest.accept} or\n * {@link FollowRequest.reject} in the {@link Bot.onFollow} event handler.\n *\n * - `\"accept\"` (default): Automatically accept all incoming follow requests.\n * - `\"reject\"`: Automatically reject all incoming follow requests.\n * - `\"manual\"`: Require manual handling of incoming follow requests.\n * @default `\"accept\"`\n */\n readonly followerPolicy?: \"accept\" | \"reject\" | \"manual\";\n\n /**\n * The underlying key-value store to use for storing data.\n */\n readonly kv: KvStore;\n\n /**\n * The underlying repository to use for storing data. If omitted,\n * {@link KvRepository} will be used.\n */\n readonly repository?: Repository;\n\n /**\n * The underlying message queue to use for handling incoming and outgoing\n * activities. If omitted, incoming activities are processed immediately,\n * and outgoing activities are sent immediately.\n */\n readonly queue?: MessageQueue;\n\n /**\n * The software information of the bot. If omitted, the NodeInfo protocol\n * will be unimplemented.\n */\n readonly software?: Software;\n\n /**\n * Whether to trust `X-Forwarded-*` headers. If your bot application is\n * behind an L7 reverse proxy, turn it on.\n *\n * Turned off by default.\n * @default `false`\n */\n readonly behindProxy?: boolean;\n\n /**\n * The options for the web pages of the bot. If omitted, the default options\n * will be used.\n */\n readonly pages?: PagesOptions;\n}\n\n/**\n * Options for the web pages of the bot.\n */\nexport interface PagesOptions {\n /**\n * The color of the theme. It will be used for the theme color of the web\n * pages. The default color is `\"green\"`.\n * @default `\"green\"`\n */\n readonly color?:\n | \"amber\"\n | \"azure\"\n | \"blue\"\n | \"cyan\"\n | \"fuchsia\"\n | \"green\"\n | \"grey\"\n | \"indigo\"\n | \"jade\"\n | \"lime\"\n | \"orange\"\n | \"pink\"\n | \"pumpkin\"\n | \"purple\"\n | \"red\"\n | \"sand\"\n | \"slate\"\n | \"violet\"\n | \"yellow\"\n | \"zinc\";\n\n /**\n * The CSS code for the bot. It will be used for the custom CSS of the web\n * pages.\n */\n readonly css?: string;\n}\n\n/**\n * Creates a {@link Bot} instance.\n * @param options The options for creating the bot.\n * @returns The created bot instance.\n */\nexport function createBot<TContextData = void>(\n options: CreateBotOptions<TContextData>,\n): TContextData extends void ? BotWithVoidContextData : Bot<TContextData> {\n const bot = new BotImpl<TContextData>(options);\n // Since `deno serve` does not recognize a class instance having fetch(),\n // we wrap a BotImpl instance with a plain object.\n // See also https://github.com/denoland/deno/issues/24062\n const wrapper = {\n impl: bot,\n get federation() {\n return bot.federation;\n },\n get identifier() {\n return bot.identifier;\n },\n getSession(a, b?) {\n // @ts-ignore: BotImpl.getSession() implements Bot.getSession()\n return bot.getSession(a, b);\n },\n fetch(request, contextData) {\n return bot.fetch(request, contextData);\n },\n addCustomEmojis<TEmojiName extends string>(\n emojis: Readonly<Record<TEmojiName, CustomEmoji>>,\n ): Readonly<Record<TEmojiName, DeferredCustomEmoji<TContextData>>> {\n return bot.addCustomEmojis(emojis);\n },\n get onFollow() {\n return bot.onFollow;\n },\n set onFollow(value) {\n bot.onFollow = value;\n },\n get onUnfollow() {\n return bot.onUnfollow;\n },\n set onUnfollow(value) {\n bot.onUnfollow = value;\n },\n get onAcceptFollow() {\n return bot.onAcceptFollow;\n },\n set onAcceptFollow(value) {\n bot.onAcceptFollow = value;\n },\n get onRejectFollow() {\n return bot.onRejectFollow;\n },\n set onRejectFollow(value) {\n bot.onRejectFollow = value;\n },\n get onMention() {\n return bot.onMention;\n },\n set onMention(value) {\n bot.onMention = value;\n },\n get onReply() {\n return bot.onReply;\n },\n set onReply(value) {\n bot.onReply = value;\n },\n get onQuote() {\n return bot.onQuote;\n },\n set onQuote(value) {\n bot.onQuote = value;\n },\n get onMessage() {\n return bot.onMessage;\n },\n set onMessage(value) {\n bot.onMessage = value;\n },\n get onSharedMessage() {\n return bot.onSharedMessage;\n },\n set onSharedMessage(value) {\n bot.onSharedMessage = value;\n },\n get onLike() {\n return bot.onLike;\n },\n set onLike(value) {\n bot.onLike = value;\n },\n get onUnlike() {\n return bot.onUnlike;\n },\n set onUnlike(value) {\n bot.onUnlike = value;\n },\n get onReact() {\n return bot.onReact;\n },\n set onReact(value) {\n bot.onReact = value;\n },\n get onUnreact() {\n return bot.onUnreact;\n },\n set onUnreact(value) {\n bot.onUnreact = value;\n },\n get onVote() {\n return bot.onVote;\n },\n set onVote(value) {\n bot.onVote = value;\n },\n } satisfies Bot<TContextData> & { impl: BotImpl<TContextData> };\n // @ts-ignore: the wrapper implements BotWithVoidContextData\n return wrapper;\n}\n"],"mappings":";;;;;;;;;;;;;AA+XA,SAAgB,UACdA,SACwE;CACxE,MAAM,MAAM,IAAI,QAAsB;CAItC,MAAM,UAAU;EACd,MAAM;EACN,IAAI,aAAa;AACf,UAAO,IAAI;EACZ;EACD,IAAI,aAAa;AACf,UAAO,IAAI;EACZ;EACD,WAAW,GAAGC,GAAI;AAEhB,UAAO,IAAI,WAAW,GAAG,EAAE;EAC5B;EACD,MAAM,SAAS,aAAa;AAC1B,UAAO,IAAI,MAAM,SAAS,YAAY;EACvC;EACD,gBACEC,QACiE;AACjE,UAAO,IAAI,gBAAgB,OAAO;EACnC;EACD,IAAI,WAAW;AACb,UAAO,IAAI;EACZ;EACD,IAAI,SAAS,OAAO;AAClB,OAAI,WAAW;EAChB;EACD,IAAI,aAAa;AACf,UAAO,IAAI;EACZ;EACD,IAAI,WAAW,OAAO;AACpB,OAAI,aAAa;EAClB;EACD,IAAI,iBAAiB;AACnB,UAAO,IAAI;EACZ;EACD,IAAI,eAAe,OAAO;AACxB,OAAI,iBAAiB;EACtB;EACD,IAAI,iBAAiB;AACnB,UAAO,IAAI;EACZ;EACD,IAAI,eAAe,OAAO;AACxB,OAAI,iBAAiB;EACtB;EACD,IAAI,YAAY;AACd,UAAO,IAAI;EACZ;EACD,IAAI,UAAU,OAAO;AACnB,OAAI,YAAY;EACjB;EACD,IAAI,UAAU;AACZ,UAAO,IAAI;EACZ;EACD,IAAI,QAAQ,OAAO;AACjB,OAAI,UAAU;EACf;EACD,IAAI,UAAU;AACZ,UAAO,IAAI;EACZ;EACD,IAAI,QAAQ,OAAO;AACjB,OAAI,UAAU;EACf;EACD,IAAI,YAAY;AACd,UAAO,IAAI;EACZ;EACD,IAAI,UAAU,OAAO;AACnB,OAAI,YAAY;EACjB;EACD,IAAI,kBAAkB;AACpB,UAAO,IAAI;EACZ;EACD,IAAI,gBAAgB,OAAO;AACzB,OAAI,kBAAkB;EACvB;EACD,IAAI,SAAS;AACX,UAAO,IAAI;EACZ;EACD,IAAI,OAAO,OAAO;AAChB,OAAI,SAAS;EACd;EACD,IAAI,WAAW;AACb,UAAO,IAAI;EACZ;EACD,IAAI,SAAS,OAAO;AAClB,OAAI,WAAW;EAChB;EACD,IAAI,UAAU;AACZ,UAAO,IAAI;EACZ;EACD,IAAI,QAAQ,OAAO;AACjB,OAAI,UAAU;EACf;EACD,IAAI,YAAY;AACd,UAAO,IAAI;EACZ;EACD,IAAI,UAAU,OAAO;AACnB,OAAI,YAAY;EACjB;EACD,IAAI,SAAS;AACX,UAAO,IAAI;EACZ;EACD,IAAI,OAAO,OAAO;AAChB,OAAI,SAAS;EACd;CACF;AAED,QAAO;AACR"}
@@ -1 +1 @@
1
- {"version":3,"file":"bot.test.js","names":["_session: Session<void>","_followRequest: FollowRequest","_follower: Actor","_accepter: Actor","_rejecter: Actor","_message: Message<MessageClass, void>","_message: SharedMessage<MessageClass, void>","_like: Like<void>"],"sources":["../src/bot.test.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { MemoryKvStore } from \"@fedify/fedify/federation\";\nimport type { Actor } from \"@fedify/fedify/vocab\";\nimport assert from \"node:assert\";\nimport { test } from \"node:test\";\nimport type { BotImpl } from \"./bot-impl.ts\";\nimport { createBot } from \"./bot.ts\";\nimport type { FollowRequest } from \"./follow.ts\";\nimport type { Message, MessageClass, SharedMessage } from \"./message.ts\";\nimport type { Like } from \"./reaction.ts\";\nimport type { Session } from \"./session.ts\";\n\ntest(\"createBot()\", async () => {\n const kv = new MemoryKvStore();\n const bot = createBot<void>({ kv, identifier: \"bot-id\", username: \"bot\" });\n const { impl } = bot as unknown as { impl: BotImpl<void> };\n const _federation = bot.federation;\n assert.strictEqual(bot.identifier, \"bot-id\");\n const session = bot.getSession(\"https://example.com\");\n assert.strictEqual(session.actorHandle, \"@bot@example.com\");\n\n function onFollow(_session: Session<void>, _followRequest: FollowRequest) {}\n bot.onFollow = onFollow;\n assert.strictEqual(bot.onFollow, onFollow);\n assert.strictEqual(impl.onFollow, onFollow);\n\n function onUnfollow(_session: Session<void>, _follower: Actor) {}\n bot.onUnfollow = onUnfollow;\n assert.strictEqual(bot.onUnfollow, onUnfollow);\n assert.strictEqual(impl.onUnfollow, onUnfollow);\n\n function onAcceptFollow(_session: Session<void>, _accepter: Actor) {}\n bot.onAcceptFollow = onAcceptFollow;\n assert.strictEqual(bot.onAcceptFollow, onAcceptFollow);\n assert.strictEqual(impl.onAcceptFollow, onAcceptFollow);\n\n function onRejectFollow(_session: Session<void>, _rejecter: Actor) {}\n bot.onRejectFollow = onRejectFollow;\n assert.strictEqual(bot.onRejectFollow, onRejectFollow);\n assert.strictEqual(impl.onRejectFollow, onRejectFollow);\n\n function onMention(\n _session: Session<void>,\n _message: Message<MessageClass, void>,\n ) {}\n bot.onMention = onMention;\n assert.strictEqual(bot.onMention, onMention);\n assert.strictEqual(impl.onMention, onMention);\n\n function onReply(\n _session: Session<void>,\n _message: Message<MessageClass, void>,\n ) {}\n bot.onReply = onReply;\n assert.strictEqual(bot.onReply, onReply);\n assert.strictEqual(impl.onReply, onReply);\n\n function onMessage(\n _session: Session<void>,\n _message: Message<MessageClass, void>,\n ) {}\n bot.onMessage = onMessage;\n assert.strictEqual(bot.onMessage, onMessage);\n assert.strictEqual(impl.onMessage, onMessage);\n\n function onSharedMessage(\n _session: Session<void>,\n _message: SharedMessage<MessageClass, void>,\n ) {}\n bot.onSharedMessage = onSharedMessage;\n assert.strictEqual(bot.onSharedMessage, onSharedMessage);\n assert.strictEqual(impl.onSharedMessage, onSharedMessage);\n\n function onLike(_session: Session<void>, _like: Like<void>) {}\n bot.onLike = onLike;\n assert.strictEqual(bot.onLike, onLike);\n assert.strictEqual(impl.onLike, onLike);\n\n function onUnlike(_session: Session<void>, _like: Like<void>) {}\n bot.onUnlike = onUnlike;\n assert.strictEqual(bot.onUnlike, onUnlike);\n assert.strictEqual(impl.onUnlike, onUnlike);\n\n const response = await bot.fetch(\n new Request(\n \"https://example.com/.well-known/webfinger?resource=acct:bot@example.com\",\n ),\n );\n assert.strictEqual(response.status, 200);\n assert.deepStrictEqual(await response.json(), {\n aliases: [\n \"https://example.com/ap/actor/bot-id\",\n ],\n links: [\n {\n href: \"https://example.com/ap/actor/bot-id\",\n rel: \"self\",\n type: \"application/activity+json\",\n },\n {\n href: \"https://example.com/\",\n rel: \"http://webfinger.net/rel/profile-page\",\n },\n ],\n subject: \"acct:bot@example.com\",\n });\n});\n"],"mappings":";;;;;;;;;;AA0BA,KAAK,eAAe,YAAY;CAC9B,MAAM,KAAK,IAAI;CACf,MAAM,MAAM,UAAgB;EAAE;EAAI,YAAY;EAAU,UAAU;CAAO,EAAC;CAC1E,MAAM,EAAE,MAAM,GAAG;CACjB,MAAM,cAAc,IAAI;AACxB,QAAO,YAAY,IAAI,YAAY,SAAS;CAC5C,MAAM,UAAU,IAAI,WAAW,sBAAsB;AACrD,QAAO,YAAY,QAAQ,aAAa,mBAAmB;CAE3D,SAAS,SAASA,UAAyBC,gBAA+B,CAAE;AAC5E,KAAI,WAAW;AACf,QAAO,YAAY,IAAI,UAAU,SAAS;AAC1C,QAAO,YAAY,KAAK,UAAU,SAAS;CAE3C,SAAS,WAAWD,UAAyBE,WAAkB,CAAE;AACjE,KAAI,aAAa;AACjB,QAAO,YAAY,IAAI,YAAY,WAAW;AAC9C,QAAO,YAAY,KAAK,YAAY,WAAW;CAE/C,SAAS,eAAeF,UAAyBG,WAAkB,CAAE;AACrE,KAAI,iBAAiB;AACrB,QAAO,YAAY,IAAI,gBAAgB,eAAe;AACtD,QAAO,YAAY,KAAK,gBAAgB,eAAe;CAEvD,SAAS,eAAeH,UAAyBI,WAAkB,CAAE;AACrE,KAAI,iBAAiB;AACrB,QAAO,YAAY,IAAI,gBAAgB,eAAe;AACtD,QAAO,YAAY,KAAK,gBAAgB,eAAe;CAEvD,SAAS,UACPJ,UACAK,UACA,CAAE;AACJ,KAAI,YAAY;AAChB,QAAO,YAAY,IAAI,WAAW,UAAU;AAC5C,QAAO,YAAY,KAAK,WAAW,UAAU;CAE7C,SAAS,QACPL,UACAK,UACA,CAAE;AACJ,KAAI,UAAU;AACd,QAAO,YAAY,IAAI,SAAS,QAAQ;AACxC,QAAO,YAAY,KAAK,SAAS,QAAQ;CAEzC,SAAS,UACPL,UACAK,UACA,CAAE;AACJ,KAAI,YAAY;AAChB,QAAO,YAAY,IAAI,WAAW,UAAU;AAC5C,QAAO,YAAY,KAAK,WAAW,UAAU;CAE7C,SAAS,gBACPL,UACAM,UACA,CAAE;AACJ,KAAI,kBAAkB;AACtB,QAAO,YAAY,IAAI,iBAAiB,gBAAgB;AACxD,QAAO,YAAY,KAAK,iBAAiB,gBAAgB;CAEzD,SAAS,OAAON,UAAyBO,OAAmB,CAAE;AAC9D,KAAI,SAAS;AACb,QAAO,YAAY,IAAI,QAAQ,OAAO;AACtC,QAAO,YAAY,KAAK,QAAQ,OAAO;CAEvC,SAAS,SAASP,UAAyBO,OAAmB,CAAE;AAChE,KAAI,WAAW;AACf,QAAO,YAAY,IAAI,UAAU,SAAS;AAC1C,QAAO,YAAY,KAAK,UAAU,SAAS;CAE3C,MAAM,WAAW,MAAM,IAAI,MACzB,IAAI,QACF,2EAEH;AACD,QAAO,YAAY,SAAS,QAAQ,IAAI;AACxC,QAAO,gBAAgB,MAAM,SAAS,MAAM,EAAE;EAC5C,SAAS,CACP,qCACD;EACD,OAAO,CACL;GACE,MAAM;GACN,KAAK;GACL,MAAM;EACP,GACD;GACE,MAAM;GACN,KAAK;EACN,CACF;EACD,SAAS;CACV,EAAC;AACH,EAAC"}
1
+ {"version":3,"file":"bot.test.js","names":["_session: Session<void>","_followRequest: FollowRequest","_follower: Actor","_accepter: Actor","_rejecter: Actor","_message: Message<MessageClass, void>","_message: SharedMessage<MessageClass, void>","_like: Like<void>"],"sources":["../src/bot.test.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { MemoryKvStore } from \"@fedify/fedify/federation\";\nimport type { Actor } from \"@fedify/vocab\";\nimport assert from \"node:assert\";\nimport { test } from \"node:test\";\nimport type { BotImpl } from \"./bot-impl.ts\";\nimport { createBot } from \"./bot.ts\";\nimport type { FollowRequest } from \"./follow.ts\";\nimport type { Message, MessageClass, SharedMessage } from \"./message.ts\";\nimport type { Like } from \"./reaction.ts\";\nimport type { Session } from \"./session.ts\";\n\ntest(\"createBot()\", async () => {\n const kv = new MemoryKvStore();\n const bot = createBot<void>({ kv, identifier: \"bot-id\", username: \"bot\" });\n const { impl } = bot as unknown as { impl: BotImpl<void> };\n const _federation = bot.federation;\n assert.strictEqual(bot.identifier, \"bot-id\");\n const session = bot.getSession(\"https://example.com\");\n assert.strictEqual(session.actorHandle, \"@bot@example.com\");\n\n function onFollow(_session: Session<void>, _followRequest: FollowRequest) {}\n bot.onFollow = onFollow;\n assert.strictEqual(bot.onFollow, onFollow);\n assert.strictEqual(impl.onFollow, onFollow);\n\n function onUnfollow(_session: Session<void>, _follower: Actor) {}\n bot.onUnfollow = onUnfollow;\n assert.strictEqual(bot.onUnfollow, onUnfollow);\n assert.strictEqual(impl.onUnfollow, onUnfollow);\n\n function onAcceptFollow(_session: Session<void>, _accepter: Actor) {}\n bot.onAcceptFollow = onAcceptFollow;\n assert.strictEqual(bot.onAcceptFollow, onAcceptFollow);\n assert.strictEqual(impl.onAcceptFollow, onAcceptFollow);\n\n function onRejectFollow(_session: Session<void>, _rejecter: Actor) {}\n bot.onRejectFollow = onRejectFollow;\n assert.strictEqual(bot.onRejectFollow, onRejectFollow);\n assert.strictEqual(impl.onRejectFollow, onRejectFollow);\n\n function onMention(\n _session: Session<void>,\n _message: Message<MessageClass, void>,\n ) {}\n bot.onMention = onMention;\n assert.strictEqual(bot.onMention, onMention);\n assert.strictEqual(impl.onMention, onMention);\n\n function onReply(\n _session: Session<void>,\n _message: Message<MessageClass, void>,\n ) {}\n bot.onReply = onReply;\n assert.strictEqual(bot.onReply, onReply);\n assert.strictEqual(impl.onReply, onReply);\n\n function onMessage(\n _session: Session<void>,\n _message: Message<MessageClass, void>,\n ) {}\n bot.onMessage = onMessage;\n assert.strictEqual(bot.onMessage, onMessage);\n assert.strictEqual(impl.onMessage, onMessage);\n\n function onSharedMessage(\n _session: Session<void>,\n _message: SharedMessage<MessageClass, void>,\n ) {}\n bot.onSharedMessage = onSharedMessage;\n assert.strictEqual(bot.onSharedMessage, onSharedMessage);\n assert.strictEqual(impl.onSharedMessage, onSharedMessage);\n\n function onLike(_session: Session<void>, _like: Like<void>) {}\n bot.onLike = onLike;\n assert.strictEqual(bot.onLike, onLike);\n assert.strictEqual(impl.onLike, onLike);\n\n function onUnlike(_session: Session<void>, _like: Like<void>) {}\n bot.onUnlike = onUnlike;\n assert.strictEqual(bot.onUnlike, onUnlike);\n assert.strictEqual(impl.onUnlike, onUnlike);\n\n const response = await bot.fetch(\n new Request(\n \"https://example.com/.well-known/webfinger?resource=acct:bot@example.com\",\n ),\n );\n assert.strictEqual(response.status, 200);\n assert.deepStrictEqual(await response.json(), {\n aliases: [\n \"https://example.com/ap/actor/bot-id\",\n ],\n links: [\n {\n href: \"https://example.com/ap/actor/bot-id\",\n rel: \"self\",\n type: \"application/activity+json\",\n },\n {\n href: \"https://example.com/\",\n rel: \"http://webfinger.net/rel/profile-page\",\n },\n ],\n subject: \"acct:bot@example.com\",\n });\n});\n"],"mappings":";;;;;;;;;;AA0BA,KAAK,eAAe,YAAY;CAC9B,MAAM,KAAK,IAAI;CACf,MAAM,MAAM,UAAgB;EAAE;EAAI,YAAY;EAAU,UAAU;CAAO,EAAC;CAC1E,MAAM,EAAE,MAAM,GAAG;CACjB,MAAM,cAAc,IAAI;AACxB,QAAO,YAAY,IAAI,YAAY,SAAS;CAC5C,MAAM,UAAU,IAAI,WAAW,sBAAsB;AACrD,QAAO,YAAY,QAAQ,aAAa,mBAAmB;CAE3D,SAAS,SAASA,UAAyBC,gBAA+B,CAAE;AAC5E,KAAI,WAAW;AACf,QAAO,YAAY,IAAI,UAAU,SAAS;AAC1C,QAAO,YAAY,KAAK,UAAU,SAAS;CAE3C,SAAS,WAAWD,UAAyBE,WAAkB,CAAE;AACjE,KAAI,aAAa;AACjB,QAAO,YAAY,IAAI,YAAY,WAAW;AAC9C,QAAO,YAAY,KAAK,YAAY,WAAW;CAE/C,SAAS,eAAeF,UAAyBG,WAAkB,CAAE;AACrE,KAAI,iBAAiB;AACrB,QAAO,YAAY,IAAI,gBAAgB,eAAe;AACtD,QAAO,YAAY,KAAK,gBAAgB,eAAe;CAEvD,SAAS,eAAeH,UAAyBI,WAAkB,CAAE;AACrE,KAAI,iBAAiB;AACrB,QAAO,YAAY,IAAI,gBAAgB,eAAe;AACtD,QAAO,YAAY,KAAK,gBAAgB,eAAe;CAEvD,SAAS,UACPJ,UACAK,UACA,CAAE;AACJ,KAAI,YAAY;AAChB,QAAO,YAAY,IAAI,WAAW,UAAU;AAC5C,QAAO,YAAY,KAAK,WAAW,UAAU;CAE7C,SAAS,QACPL,UACAK,UACA,CAAE;AACJ,KAAI,UAAU;AACd,QAAO,YAAY,IAAI,SAAS,QAAQ;AACxC,QAAO,YAAY,KAAK,SAAS,QAAQ;CAEzC,SAAS,UACPL,UACAK,UACA,CAAE;AACJ,KAAI,YAAY;AAChB,QAAO,YAAY,IAAI,WAAW,UAAU;AAC5C,QAAO,YAAY,KAAK,WAAW,UAAU;CAE7C,SAAS,gBACPL,UACAM,UACA,CAAE;AACJ,KAAI,kBAAkB;AACtB,QAAO,YAAY,IAAI,iBAAiB,gBAAgB;AACxD,QAAO,YAAY,KAAK,iBAAiB,gBAAgB;CAEzD,SAAS,OAAON,UAAyBO,OAAmB,CAAE;AAC9D,KAAI,SAAS;AACb,QAAO,YAAY,IAAI,QAAQ,OAAO;AACtC,QAAO,YAAY,KAAK,QAAQ,OAAO;CAEvC,SAAS,SAASP,UAAyBO,OAAmB,CAAE;AAChE,KAAI,WAAW;AACf,QAAO,YAAY,IAAI,UAAU,SAAS;AAC1C,QAAO,YAAY,KAAK,UAAU,SAAS;CAE3C,MAAM,WAAW,MAAM,IAAI,MACzB,IAAI,QACF,2EAEH;AACD,QAAO,YAAY,SAAS,QAAQ,IAAI;AACxC,QAAO,gBAAgB,MAAM,SAAS,MAAM,EAAE;EAC5C,SAAS,CACP,qCACD;EACD,OAAO,CACL;GACE,MAAM;GACN,KAAK;GACL,MAAM;EACP,GACD;GACE,MAAM;GACN,KAAK;EACN,CACF;EACD,SAAS;CACV,EAAC;AACH,EAAC"}
@@ -1,7 +1,7 @@
1
1
  import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
2
2
  Date.prototype.toTemporalInstant = toTemporalInstant;
3
3
  import { BotImpl } from "../bot-impl.js";
4
- import * as hono_jsx_jsx_dev_runtime3 from "hono/jsx/jsx-dev-runtime";
4
+ import * as hono_jsx_jsx_dev_runtime0 from "hono/jsx/jsx-dev-runtime";
5
5
 
6
6
  //#region src/components/FollowButton.d.ts
7
7
  interface FollowButtonProps {
@@ -9,7 +9,7 @@ interface FollowButtonProps {
9
9
  }
10
10
  declare function FollowButton({
11
11
  bot
12
- }: FollowButtonProps): hono_jsx_jsx_dev_runtime3.JSX.Element;
12
+ }: FollowButtonProps): hono_jsx_jsx_dev_runtime0.JSX.Element;
13
13
  //# sourceMappingURL=FollowButton.d.ts.map
14
14
 
15
15
  //#endregion
@@ -1,7 +1,7 @@
1
1
  import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
2
2
  Date.prototype.toTemporalInstant = toTemporalInstant;
3
3
  import { Session } from "../session.js";
4
- import { Actor } from "@fedify/fedify/vocab";
4
+ import { Actor } from "@fedify/vocab";
5
5
  import * as hono_utils_html1 from "hono/utils/html";
6
6
 
7
7
  //#region src/components/Follower.d.ts
@@ -2,7 +2,7 @@
2
2
  import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
3
3
  Date.prototype.toTemporalInstant = toTemporalInstant;
4
4
 
5
- import { Link, getActorHandle } from "@fedify/fedify/vocab";
5
+ import { Link, getActorHandle } from "@fedify/vocab";
6
6
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
7
7
 
8
8
  //#region src/components/Follower.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"Follower.js","names":[],"sources":["../../src/components/Follower.tsx"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\n/** @jsx react-jsx */\n/** @jsxImportSource hono/jsx */\nimport { type Actor, getActorHandle, Link } from \"@fedify/fedify/vocab\";\nimport type { Session } from \"../session.ts\";\n\nexport interface FollowerProps {\n readonly actor: Actor;\n readonly session: Session<unknown>;\n}\n\nexport async function Follower({ actor, session }: FollowerProps) {\n const { context } = session;\n const author = actor;\n const authorIcon = await actor?.getIcon({\n documentLoader: context.documentLoader,\n contextLoader: context.contextLoader,\n suppressError: true,\n });\n const authorHandle = await getActorHandle(author);\n\n return (\n <article>\n <header>\n {author?.id\n ? (\n <hgroup>\n {authorIcon?.url && (\n <img\n src={authorIcon.url instanceof Link\n ? authorIcon.url.href?.href\n : authorIcon.url.href}\n width={authorIcon.width ?? undefined}\n height={authorIcon.height ?? undefined}\n alt={authorIcon.name?.toString() ?? undefined}\n style=\"float: left; margin-right: 1em; height: 64px;\"\n />\n )}\n <h3>\n <a href={author.url?.href?.toString() ?? author.id.href}>\n {author.name}\n </a>\n </h3>{\" \"}\n <p>\n <span style=\"user-select: all;\">{authorHandle}</span>\n </p>\n </hgroup>\n )\n : <em>(Deleted account)</em>}\n </header>\n </article>\n );\n}\n"],"mappings":";;;;;;;;AAyBA,eAAsB,SAAS,EAAE,OAAO,SAAwB,EAAE;CAChE,MAAM,EAAE,SAAS,GAAG;CACpB,MAAM,SAAS;CACf,MAAM,aAAa,MAAM,OAAO,QAAQ;EACtC,gBAAgB,QAAQ;EACxB,eAAe,QAAQ;EACvB,eAAe;CAChB,EAAC;CACF,MAAM,eAAe,MAAM,eAAe,OAAO;AAEjD,wBACE,IAAC,uCACC,IAAC,sBACE,QAAQ,qBAEL,KAAC;EACE,YAAY,uBACX,IAAC;GACC,KAAK,WAAW,eAAe,OAC3B,WAAW,IAAI,MAAM,OACrB,WAAW,IAAI;GACnB,OAAO,WAAW;GAClB,QAAQ,WAAW;GACnB,KAAK,WAAW,MAAM,UAAU;GAChC,OAAM;IACN;kBAEJ,IAAC,kCACC,IAAC;GAAE,MAAM,OAAO,KAAK,MAAM,UAAU,IAAI,OAAO,GAAG;aAChD,OAAO;IACN,GACD;EAAC;kBACN,IAAC,iCACC,IAAC;GAAK,OAAM;aAAqB;IAAoB,GACnD;KACG,mBAET,IAAC,kBAAG,sBAAsB,GACvB,GACD;AAEb"}
1
+ {"version":3,"file":"Follower.js","names":[],"sources":["../../src/components/Follower.tsx"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\n/** @jsx react-jsx */\n/** @jsxImportSource hono/jsx */\nimport { type Actor, getActorHandle, Link } from \"@fedify/vocab\";\nimport type { Session } from \"../session.ts\";\n\nexport interface FollowerProps {\n readonly actor: Actor;\n readonly session: Session<unknown>;\n}\n\nexport async function Follower({ actor, session }: FollowerProps) {\n const { context } = session;\n const author = actor;\n const authorIcon = await actor?.getIcon({\n documentLoader: context.documentLoader,\n contextLoader: context.contextLoader,\n suppressError: true,\n });\n const authorHandle = await getActorHandle(author);\n\n return (\n <article>\n <header>\n {author?.id\n ? (\n <hgroup>\n {authorIcon?.url && (\n <img\n src={authorIcon.url instanceof Link\n ? authorIcon.url.href?.href\n : authorIcon.url.href}\n width={authorIcon.width ?? undefined}\n height={authorIcon.height ?? undefined}\n alt={authorIcon.name?.toString() ?? undefined}\n style=\"float: left; margin-right: 1em; height: 64px;\"\n />\n )}\n <h3>\n <a href={author.url?.href?.toString() ?? author.id.href}>\n {author.name}\n </a>\n </h3>{\" \"}\n <p>\n <span style=\"user-select: all;\">{authorHandle}</span>\n </p>\n </hgroup>\n )\n : <em>(Deleted account)</em>}\n </header>\n </article>\n );\n}\n"],"mappings":";;;;;;;;AAyBA,eAAsB,SAAS,EAAE,OAAO,SAAwB,EAAE;CAChE,MAAM,EAAE,SAAS,GAAG;CACpB,MAAM,SAAS;CACf,MAAM,aAAa,MAAM,OAAO,QAAQ;EACtC,gBAAgB,QAAQ;EACxB,eAAe,QAAQ;EACvB,eAAe;CAChB,EAAC;CACF,MAAM,eAAe,MAAM,eAAe,OAAO;AAEjD,wBACE,IAAC,uCACC,IAAC,sBACE,QAAQ,qBAEL,KAAC;EACE,YAAY,uBACX,IAAC;GACC,KAAK,WAAW,eAAe,OAC3B,WAAW,IAAI,MAAM,OACrB,WAAW,IAAI;GACnB,OAAO,WAAW;GAClB,QAAQ,WAAW;GACnB,KAAK,WAAW,MAAM,UAAU;GAChC,OAAM;IACN;kBAEJ,IAAC,kCACC,IAAC;GAAE,MAAM,OAAO,KAAK,MAAM,UAAU,IAAI,OAAO,GAAG;aAChD,OAAO;IACN,GACD;EAAC;kBACN,IAAC,iCACC,IAAC;GAAK,OAAM;aAAqB;IAAoB,GACnD;KACG,mBAET,IAAC,kBAAG,sBAAsB,GACvB,GACD;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"Message.d.ts","names":[],"sources":["../../src/components/Message.tsx"],"sourcesContent":[],"mappings":";;;;;;;UA4BiB,YAAA;oBACG;oBACA;;iBAGE,OAAA;;;GAA8B,eAAY,QAAA,gBAAA,CAAA,iBAAA;iBAwGhD,kBAAA,uBAEN"}
1
+ {"version":3,"file":"Message.d.ts","names":[],"sources":["../../src/components/Message.tsx"],"sourcesContent":[],"mappings":";;;;;;;UAsBiB,YAAA;oBACG;oBACA;;iBAGE,OAAA;;;GAA8B,eAAY,QAAA,gBAAA,CAAA,iBAAA;iBAwGhD,kBAAA,uBAEN"}
@@ -2,8 +2,8 @@
2
2
  import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
3
3
  Date.prototype.toTemporalInstant = toTemporalInstant;
4
4
 
5
- import { Document, Emoji, Image, Link, getActorHandle } from "@fedify/fedify/vocab";
6
- import { LanguageString } from "@fedify/fedify/runtime";
5
+ import { Document, Emoji, Image, Link, getActorHandle } from "@fedify/vocab";
6
+ import { LanguageString } from "@fedify/vocab-runtime";
7
7
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
8
8
 
9
9
  //#region src/components/Message.tsx
@@ -52,7 +52,7 @@ async function Message({ session, message }) {
52
52
  ] }) : /* @__PURE__ */ jsx("em", { children: "(Deleted account)" }) }),
53
53
  /* @__PURE__ */ jsx("div", {
54
54
  dangerouslySetInnerHTML: { __html: renderCustomEmojis(`${message.content}`, customEmojis) },
55
- lang: message.content instanceof LanguageString ? message.content.language.compact() : void 0
55
+ lang: message.content instanceof LanguageString ? message.content.locale.toString() : void 0
56
56
  }),
57
57
  attachments.length > 0 && /* @__PURE__ */ jsx("div", { children: attachments.filter((a) => a instanceof Image || a instanceof Document).filter((a) => a.mediaType?.startsWith("image/") && a.url != null).map((a) => /* @__PURE__ */ jsxs("figure", { children: [/* @__PURE__ */ jsx("img", {
58
58
  src: a.url instanceof Link ? a.url.href?.href : a.url.href,
@@ -1 +1 @@
1
- {"version":3,"file":"Message.js","names":["customEmojis: Record<string, string>","html: string","emojis: Record<string, string>"],"sources":["../../src/components/Message.tsx"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\n/** @jsx react-jsx */\n/** @jsxImportSource hono/jsx */\nimport { LanguageString } from \"@fedify/fedify/runtime\";\nimport {\n Document,\n Emoji,\n getActorHandle,\n Image,\n Link,\n} from \"@fedify/fedify/vocab\";\nimport type { MessageClass } from \"../message.ts\";\nimport type { Session } from \"../session.ts\";\n\nexport interface MessageProps {\n readonly message: MessageClass;\n readonly session: Session<unknown>;\n}\n\nexport async function Message({ session, message }: MessageProps) {\n const { context } = session;\n const author = message.attributionId?.href === session.actorId?.href\n ? await session.getActor()\n : await message.getAttribution({\n documentLoader: context.documentLoader,\n contextLoader: context.contextLoader,\n suppressError: true,\n });\n const authorIcon = await author?.getIcon({\n documentLoader: context.documentLoader,\n contextLoader: context.contextLoader,\n suppressError: true,\n });\n const authorHandle = author == null ? null : await getActorHandle(author);\n const attachments = await Array.fromAsync(message.getAttachments());\n const tags = await Array.fromAsync(message.getTags());\n const customEmojis: Record<string, string> = {};\n for (const tag of tags) {\n if (!(tag instanceof Emoji) || tag.name == null) continue;\n const icon = await tag.getIcon();\n if (icon?.url == null) continue;\n const url = icon.url instanceof Link ? icon.url.href?.href : icon.url.href;\n if (url == null) continue;\n customEmojis[tag.name.toString()] = url;\n }\n return (\n <article>\n <header>\n {author?.id\n ? (\n <hgroup>\n {authorIcon?.url && (\n <img\n src={authorIcon.url instanceof Link\n ? authorIcon.url.href?.href\n : authorIcon.url.href}\n width={authorIcon.width ?? undefined}\n height={authorIcon.height ?? undefined}\n alt={authorIcon.name?.toString() ?? undefined}\n style=\"float: left; margin-right: 1em; height: 64px;\"\n />\n )}\n <h3>\n <a href={author.url?.href?.toString() ?? author.id.href}>\n {author.name}\n </a>\n </h3>{\" \"}\n <p>\n <span style=\"user-select: all;\">{authorHandle}</span>\n </p>\n </hgroup>\n )\n : <em>(Deleted account)</em>}\n </header>\n <div\n dangerouslySetInnerHTML={{\n __html: renderCustomEmojis(`${message.content}`, customEmojis),\n }}\n lang={message.content instanceof LanguageString\n ? message.content.language.compact()\n : undefined}\n />\n {attachments.length > 0 && (\n <div>\n {attachments.filter((a) =>\n a instanceof Image || a instanceof Document\n ).filter((a) => a.mediaType?.startsWith(\"image/\") && a.url != null)\n .map((a) => (\n <figure>\n <img\n src={a.url instanceof Link ? a.url.href?.href : a.url!.href}\n width={a.width ?? undefined}\n height={a.height ?? undefined}\n alt={a.name?.toString() ?? undefined}\n style=\"max-width: 75%;\"\n />\n <figcaption>{a.name?.toString()}</figcaption>\n </figure>\n ))}\n </div>\n )}\n <footer>\n {message.published &&\n (\n <a href={message.url?.href?.toString() ?? message.id?.href}>\n <small>\n <time dateTime={message.published.toString()}>\n {message.published.toLocaleString(\"en\", {\n dateStyle: \"full\",\n timeStyle: \"short\",\n })}\n </time>\n </small>\n </a>\n )}\n </footer>\n </article>\n );\n}\n\nconst HTML_ELEMENT_REGEXP = /<\\/?[^>]+>/g;\nconst CUSTOM_EMOJI_REGEXP = /:([a-z0-9_-]+):/gi;\n\nexport function renderCustomEmojis(\n html: string,\n emojis: Record<string, string>,\n): string {\n let result = \"\";\n let index = 0;\n for (const match of html.matchAll(HTML_ELEMENT_REGEXP)) {\n result += replaceEmojis(html.substring(index, match.index));\n result += match[0];\n index = match.index + match[0].length;\n }\n result += replaceEmojis(html.substring(index));\n return result;\n\n function replaceEmojis(html: string): string {\n return html.replaceAll(CUSTOM_EMOJI_REGEXP, (match) => {\n const emoji = emojis[match] ?? emojis[match.replace(/^:|:$/g, \"\")];\n if (emoji == null) return match;\n return `<img src=\"${emoji}\" alt=\"${match}\" style=\"height: 1em\">`;\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Message.js","names":["customEmojis: Record<string, string>","html: string","emojis: Record<string, string>"],"sources":["../../src/components/Message.tsx"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\n/** @jsx react-jsx */\n/** @jsxImportSource hono/jsx */\nimport { LanguageString } from \"@fedify/vocab-runtime\";\nimport { Document, Emoji, getActorHandle, Image, Link } from \"@fedify/vocab\";\nimport type { MessageClass } from \"../message.ts\";\nimport type { Session } from \"../session.ts\";\n\nexport interface MessageProps {\n readonly message: MessageClass;\n readonly session: Session<unknown>;\n}\n\nexport async function Message({ session, message }: MessageProps) {\n const { context } = session;\n const author = message.attributionId?.href === session.actorId?.href\n ? await session.getActor()\n : await message.getAttribution({\n documentLoader: context.documentLoader,\n contextLoader: context.contextLoader,\n suppressError: true,\n });\n const authorIcon = await author?.getIcon({\n documentLoader: context.documentLoader,\n contextLoader: context.contextLoader,\n suppressError: true,\n });\n const authorHandle = author == null ? null : await getActorHandle(author);\n const attachments = await Array.fromAsync(message.getAttachments());\n const tags = await Array.fromAsync(message.getTags());\n const customEmojis: Record<string, string> = {};\n for (const tag of tags) {\n if (!(tag instanceof Emoji) || tag.name == null) continue;\n const icon = await tag.getIcon();\n if (icon?.url == null) continue;\n const url = icon.url instanceof Link ? icon.url.href?.href : icon.url.href;\n if (url == null) continue;\n customEmojis[tag.name.toString()] = url;\n }\n return (\n <article>\n <header>\n {author?.id\n ? (\n <hgroup>\n {authorIcon?.url && (\n <img\n src={authorIcon.url instanceof Link\n ? authorIcon.url.href?.href\n : authorIcon.url.href}\n width={authorIcon.width ?? undefined}\n height={authorIcon.height ?? undefined}\n alt={authorIcon.name?.toString() ?? undefined}\n style=\"float: left; margin-right: 1em; height: 64px;\"\n />\n )}\n <h3>\n <a href={author.url?.href?.toString() ?? author.id.href}>\n {author.name}\n </a>\n </h3>{\" \"}\n <p>\n <span style=\"user-select: all;\">{authorHandle}</span>\n </p>\n </hgroup>\n )\n : <em>(Deleted account)</em>}\n </header>\n <div\n dangerouslySetInnerHTML={{\n __html: renderCustomEmojis(`${message.content}`, customEmojis),\n }}\n lang={message.content instanceof LanguageString\n ? message.content.locale.toString()\n : undefined}\n />\n {attachments.length > 0 && (\n <div>\n {attachments.filter((a) =>\n a instanceof Image || a instanceof Document\n ).filter((a) => a.mediaType?.startsWith(\"image/\") && a.url != null)\n .map((a) => (\n <figure>\n <img\n src={a.url instanceof Link ? a.url.href?.href : a.url!.href}\n width={a.width ?? undefined}\n height={a.height ?? undefined}\n alt={a.name?.toString() ?? undefined}\n style=\"max-width: 75%;\"\n />\n <figcaption>{a.name?.toString()}</figcaption>\n </figure>\n ))}\n </div>\n )}\n <footer>\n {message.published &&\n (\n <a href={message.url?.href?.toString() ?? message.id?.href}>\n <small>\n <time dateTime={message.published.toString()}>\n {message.published.toLocaleString(\"en\", {\n dateStyle: \"full\",\n timeStyle: \"short\",\n })}\n </time>\n </small>\n </a>\n )}\n </footer>\n </article>\n );\n}\n\nconst HTML_ELEMENT_REGEXP = /<\\/?[^>]+>/g;\nconst CUSTOM_EMOJI_REGEXP = /:([a-z0-9_-]+):/gi;\n\nexport function renderCustomEmojis(\n html: string,\n emojis: Record<string, string>,\n): string {\n let result = \"\";\n let index = 0;\n for (const match of html.matchAll(HTML_ELEMENT_REGEXP)) {\n result += replaceEmojis(html.substring(index, match.index));\n result += match[0];\n index = match.index + match[0].length;\n }\n result += replaceEmojis(html.substring(index));\n return result;\n\n function replaceEmojis(html: string): string {\n return html.replaceAll(CUSTOM_EMOJI_REGEXP, (match) => {\n const emoji = emojis[match] ?? emojis[match.replace(/^:|:$/g, \"\")];\n if (emoji == null) return match;\n return `<img src=\"${emoji}\" alt=\"${match}\" style=\"height: 1em\">`;\n });\n }\n}\n"],"mappings":"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"}
package/dist/deno.js CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  //#region deno.json
6
6
  var name = "@fedify/botkit";
7
- var version = "0.4.0-dev.181+7081a0a5";
7
+ var version = "0.4.0-dev.182+4517af34";
8
8
  var license = "AGPL-3.0-only";
9
9
  var exports = {
10
10
  ".": "./src/mod.ts",
@@ -20,9 +20,10 @@ var exports = {
20
20
  "./text": "./src/text.ts"
21
21
  };
22
22
  var imports = {
23
+ "@fedify/vocab": "jsr:@fedify/vocab@^2.0.3",
24
+ "@fedify/vocab-runtime": "jsr:@fedify/vocab-runtime@^2.0.3",
23
25
  "@fedify/markdown-it-hashtag": "jsr:@fedify/markdown-it-hashtag@^0.3.0",
24
26
  "@fedify/markdown-it-mention": "jsr:@fedify/markdown-it-mention@^0.3.0",
25
- "@phensley/language-tag": "npm:@phensley/language-tag@^1.12.2",
26
27
  "html-entities": "npm:html-entities@^2.6.0",
27
28
  "markdown-it": "npm:markdown-it@^14.1.0",
28
29
  "mime-db": "npm:mime-db@^1.54.0",
package/dist/deno.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"deno.js","names":[],"sources":["../deno.json"],"sourcesContent":["{\n \"name\": \"@fedify/botkit\",\n \"version\": \"0.4.0-dev.181+7081a0a5\",\n \"license\": \"AGPL-3.0-only\",\n \"exports\": {\n \".\": \"./src/mod.ts\",\n \"./bot\": \"./src/bot.ts\",\n \"./emoji\": \"./src/emoji.ts\",\n \"./events\": \"./src/events.ts\",\n \"./follow\": \"./src/follow.ts\",\n \"./message\": \"./src/message.ts\",\n \"./poll\": \"./src/poll.ts\",\n \"./reaction\": \"./src/reaction.ts\",\n \"./repository\": \"./src/repository.ts\",\n \"./session\": \"./src/session.ts\",\n \"./text\": \"./src/text.ts\"\n },\n \"imports\": {\n \"@fedify/markdown-it-hashtag\": \"jsr:@fedify/markdown-it-hashtag@^0.3.0\",\n \"@fedify/markdown-it-mention\": \"jsr:@fedify/markdown-it-mention@^0.3.0\",\n \"@phensley/language-tag\": \"npm:@phensley/language-tag@^1.12.2\",\n \"html-entities\": \"npm:html-entities@^2.6.0\",\n \"markdown-it\": \"npm:markdown-it@^14.1.0\",\n \"mime-db\": \"npm:mime-db@^1.54.0\",\n \"tsdown\": \"npm:tsdown@^0.12.8\",\n \"url-template\": \"npm:url-template@^3.1.1\",\n \"uuid\": \"npm:uuid@^11.1.0\",\n \"xss\": \"npm:xss@^1.0.15\"\n },\n \"exclude\": [\n \"dist\",\n \"junit.xml\",\n \"src/css\"\n ],\n \"fmt\": {\n \"exclude\": [\n \"*.md\",\n \"*.yaml\",\n \"*.yml\",\n \"src/static/*.ts\"\n ]\n },\n \"tasks\": {\n \"test\": \"deno test --allow-env=NODE_V8_COVERAGE,JEST_WORKER_ID --allow-net=hollo.social --parallel\",\n \"test:node\": \"pnpm install && pnpm test\",\n \"test-all\": {\n \"dependencies\": [\n \"check\",\n \"test\",\n \"test:node\"\n ]\n },\n \"coverage\": \"deno task test --coverage --clean && deno coverage --html\"\n }\n}\n"],"mappings":";;;;;WACU;cACG;cACA;cACA;CACT,KAAK;CACL,SAAS;CACT,WAAW;CACX,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,UAAU;CACV,cAAc;CACd,gBAAgB;CAChB,aAAa;CACb,UAAU;AACX;cACU;CACT,+BAA+B;CAC/B,+BAA+B;CAC/B,0BAA0B;CAC1B,iBAAiB;CACjB,eAAe;CACf,WAAW;CACX,UAAU;CACV,gBAAgB;CAChB,QAAQ;CACR,OAAO;AACR;cACU;CACT;CACA;CACA;AACD;UACM,EACL,WAAW;CACT;CACA;CACA;CACA;AACD,EACF;YACQ;CACP,QAAQ;CACR,aAAa;CACb,YAAY,EACV,gBAAgB;EACd;EACA;EACA;CACD,EACF;CACD,YAAY;AACb;mBArDH;;;;;;;;;AAsDC"}
1
+ {"version":3,"file":"deno.js","names":[],"sources":["../deno.json"],"sourcesContent":["{\n \"name\": \"@fedify/botkit\",\n \"version\": \"0.4.0-dev.182+4517af34\",\n \"license\": \"AGPL-3.0-only\",\n \"exports\": {\n \".\": \"./src/mod.ts\",\n \"./bot\": \"./src/bot.ts\",\n \"./emoji\": \"./src/emoji.ts\",\n \"./events\": \"./src/events.ts\",\n \"./follow\": \"./src/follow.ts\",\n \"./message\": \"./src/message.ts\",\n \"./poll\": \"./src/poll.ts\",\n \"./reaction\": \"./src/reaction.ts\",\n \"./repository\": \"./src/repository.ts\",\n \"./session\": \"./src/session.ts\",\n \"./text\": \"./src/text.ts\"\n },\n \"imports\": {\n \"@fedify/vocab\": \"jsr:@fedify/vocab@^2.0.3\",\n \"@fedify/vocab-runtime\": \"jsr:@fedify/vocab-runtime@^2.0.3\",\n \"@fedify/markdown-it-hashtag\": \"jsr:@fedify/markdown-it-hashtag@^0.3.0\",\n \"@fedify/markdown-it-mention\": \"jsr:@fedify/markdown-it-mention@^0.3.0\",\n \"html-entities\": \"npm:html-entities@^2.6.0\",\n \"markdown-it\": \"npm:markdown-it@^14.1.0\",\n \"mime-db\": \"npm:mime-db@^1.54.0\",\n \"tsdown\": \"npm:tsdown@^0.12.8\",\n \"url-template\": \"npm:url-template@^3.1.1\",\n \"uuid\": \"npm:uuid@^11.1.0\",\n \"xss\": \"npm:xss@^1.0.15\"\n },\n \"exclude\": [\n \"dist\",\n \"junit.xml\",\n \"src/css\"\n ],\n \"fmt\": {\n \"exclude\": [\n \"*.md\",\n \"*.yaml\",\n \"*.yml\",\n \"src/static/*.ts\"\n ]\n },\n \"tasks\": {\n \"test\": \"deno test --allow-env=NODE_V8_COVERAGE,JEST_WORKER_ID --allow-net=hollo.social --parallel\",\n \"test:node\": \"pnpm install && pnpm test\",\n \"test-all\": {\n \"dependencies\": [\n \"check\",\n \"test\",\n \"test:node\"\n ]\n },\n \"coverage\": \"deno task test --coverage --clean && deno coverage --html\"\n }\n}\n"],"mappings":";;;;;WACU;cACG;cACA;cACA;CACT,KAAK;CACL,SAAS;CACT,WAAW;CACX,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,UAAU;CACV,cAAc;CACd,gBAAgB;CAChB,aAAa;CACb,UAAU;AACX;cACU;CACT,iBAAiB;CACjB,yBAAyB;CACzB,+BAA+B;CAC/B,+BAA+B;CAC/B,iBAAiB;CACjB,eAAe;CACf,WAAW;CACX,UAAU;CACV,gBAAgB;CAChB,QAAQ;CACR,OAAO;AACR;cACU;CACT;CACA;CACA;AACD;UACM,EACL,WAAW;CACT;CACA;CACA;CACA;AACD,EACF;YACQ;CACP,QAAQ;CACR,aAAa;CACb,YAAY,EACV,gBAAgB;EACd;EACA;EACA;CACD,EACF;CACD,YAAY;AACb;mBAtDH;;;;;;;;;AAuDC"}
package/dist/emoji.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
2
2
  Date.prototype.toTemporalInstant = toTemporalInstant;
3
3
  import { Session } from "./session.js";
4
- import { Emoji as Emoji$1 } from "@fedify/fedify/vocab";
4
+ import { Emoji as Emoji$1 } from "@fedify/vocab";
5
5
 
6
6
  //#region src/emoji.d.ts
7
7
 
package/dist/emoji.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"emoji.js","names":["value: unknown","strings: TemplateStringsArray"],"sources":["../src/emoji.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport type { Emoji as EmojiObject } from \"@fedify/fedify/vocab\";\nimport type { Session } from \"./session.ts\";\n\n/**\n * A branded type for a single emoji character (more exactly, a single\n * Unicode grapheme cluster of emoji). This is used to represent a single emoji\n * in a string format. It is not a full-fledged emoji object, but rather a\n * string that is guaranteed to be a single emoji.\n *\n * You can narrow a string to an {@link Emoji} type using the {@link isEmoji}\n * predicate function.\n * @since 0.2.0\n */\nexport type Emoji = string & { readonly __emoji: unique symbol };\n\n/**\n * A type guard that checks if a value is a single emoji character.\n * @param value The value to check.\n * @returns `true` if the value is a single emoji character, `false` otherwise.\n * @since 0.2.0\n */\nexport function isEmoji(value: unknown): value is Emoji {\n if (typeof value !== \"string\") return false;\n\n // First check if we have exactly one grapheme cluster\n const segmenter = new Intl.Segmenter(\"en\", { granularity: \"grapheme\" });\n const segments = [...segmenter.segment(value)];\n if (segments.length !== 1) return false;\n\n // Then check if this grapheme cluster has the emoji property\n return /\\p{Emoji}/u.test(segments[0].segment);\n}\n\n/**\n * A tagged template literal function that creates an {@link Emoji} from\n * a string. It is a simple wrapper around the `String.raw` function,\n * but it also checks if the resulting string is a valid emoji.\n * @param strings The template strings.\n * @param values The values to interpolate into the template strings.\n * @returns The resulting {@link Emoji} value.\n * @throws {TypeError} If the resulting string is not a valid emoji.\n * @since 0.2.0\n */\nexport function emoji(\n strings: TemplateStringsArray,\n ...values: unknown[]\n): Emoji {\n const result = String.raw(strings, ...values);\n if (!isEmoji(result)) {\n throw new TypeError(`Invalid emoji: ${result}`);\n }\n return result;\n}\n\n/**\n * The common interface for defining custom emojis.\n * @since 0.2.0\n */\nexport interface CustomEmojiBase {\n /**\n * The media type of the emoji. It has to start with `image/`.\n */\n readonly type: `image/${string}`;\n}\n\n/**\n * The interface for defining custom emojis from a remote image URL.\n * @since 0.2.0\n */\nexport interface CustomEmojiFromUrl extends CustomEmojiBase {\n /**\n * The URL of the remote image.\n */\n readonly url: string | URL;\n}\n\n/**\n * The interface for defining custom emojis from a local image file.\n * @since 0.2.0\n */\nexport interface CustomEmojiFromFile extends CustomEmojiBase {\n /**\n * The path to the local image file.\n */\n readonly file: string | URL;\n}\n\n/**\n * A definition of a custom emoji. It can be either a remote image URL or\n * a local image file.\n * @since 0.2.0\n */\nexport type CustomEmoji = CustomEmojiFromUrl | CustomEmojiFromFile;\n\n/**\n * A deferred `Emoji` (provided by Fedify), which is a function that\n * takes a {@link Session} and returns an `Emoji`. This is useful for\n * creating emojis that depend on the session data.\n * @since 0.2.0\n * @param TContextData The type of the context data.\n * @return The `Emoji` object.\n */\nexport type DeferredCustomEmoji<TContextData> = (\n session: Session<TContextData>,\n) => EmojiObject;\n"],"mappings":";;;;;;;;;;;AAoCA,SAAgB,QAAQA,OAAgC;AACtD,YAAW,UAAU,SAAU,QAAO;CAGtC,MAAM,YAAY,IAAI,KAAK,UAAU,MAAM,EAAE,aAAa,WAAY;CACtE,MAAM,WAAW,CAAC,GAAG,UAAU,QAAQ,MAAM,AAAC;AAC9C,KAAI,SAAS,WAAW,EAAG,QAAO;AAGlC,QAAO,aAAa,KAAK,SAAS,GAAG,QAAQ;AAC9C;;;;;;;;;;;AAYD,SAAgB,MACdC,SACA,GAAG,QACI;CACP,MAAM,SAAS,OAAO,IAAI,SAAS,GAAG,OAAO;AAC7C,MAAK,QAAQ,OAAO,CAClB,OAAM,IAAI,WAAW,iBAAiB,OAAO;AAE/C,QAAO;AACR"}
1
+ {"version":3,"file":"emoji.js","names":["value: unknown","strings: TemplateStringsArray"],"sources":["../src/emoji.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport type { Emoji as EmojiObject } from \"@fedify/vocab\";\nimport type { Session } from \"./session.ts\";\n\n/**\n * A branded type for a single emoji character (more exactly, a single\n * Unicode grapheme cluster of emoji). This is used to represent a single emoji\n * in a string format. It is not a full-fledged emoji object, but rather a\n * string that is guaranteed to be a single emoji.\n *\n * You can narrow a string to an {@link Emoji} type using the {@link isEmoji}\n * predicate function.\n * @since 0.2.0\n */\nexport type Emoji = string & { readonly __emoji: unique symbol };\n\n/**\n * A type guard that checks if a value is a single emoji character.\n * @param value The value to check.\n * @returns `true` if the value is a single emoji character, `false` otherwise.\n * @since 0.2.0\n */\nexport function isEmoji(value: unknown): value is Emoji {\n if (typeof value !== \"string\") return false;\n\n // First check if we have exactly one grapheme cluster\n const segmenter = new Intl.Segmenter(\"en\", { granularity: \"grapheme\" });\n const segments = [...segmenter.segment(value)];\n if (segments.length !== 1) return false;\n\n // Then check if this grapheme cluster has the emoji property\n return /\\p{Emoji}/u.test(segments[0].segment);\n}\n\n/**\n * A tagged template literal function that creates an {@link Emoji} from\n * a string. It is a simple wrapper around the `String.raw` function,\n * but it also checks if the resulting string is a valid emoji.\n * @param strings The template strings.\n * @param values The values to interpolate into the template strings.\n * @returns The resulting {@link Emoji} value.\n * @throws {TypeError} If the resulting string is not a valid emoji.\n * @since 0.2.0\n */\nexport function emoji(\n strings: TemplateStringsArray,\n ...values: unknown[]\n): Emoji {\n const result = String.raw(strings, ...values);\n if (!isEmoji(result)) {\n throw new TypeError(`Invalid emoji: ${result}`);\n }\n return result;\n}\n\n/**\n * The common interface for defining custom emojis.\n * @since 0.2.0\n */\nexport interface CustomEmojiBase {\n /**\n * The media type of the emoji. It has to start with `image/`.\n */\n readonly type: `image/${string}`;\n}\n\n/**\n * The interface for defining custom emojis from a remote image URL.\n * @since 0.2.0\n */\nexport interface CustomEmojiFromUrl extends CustomEmojiBase {\n /**\n * The URL of the remote image.\n */\n readonly url: string | URL;\n}\n\n/**\n * The interface for defining custom emojis from a local image file.\n * @since 0.2.0\n */\nexport interface CustomEmojiFromFile extends CustomEmojiBase {\n /**\n * The path to the local image file.\n */\n readonly file: string | URL;\n}\n\n/**\n * A definition of a custom emoji. It can be either a remote image URL or\n * a local image file.\n * @since 0.2.0\n */\nexport type CustomEmoji = CustomEmojiFromUrl | CustomEmojiFromFile;\n\n/**\n * A deferred `Emoji` (provided by Fedify), which is a function that\n * takes a {@link Session} and returns an `Emoji`. This is useful for\n * creating emojis that depend on the session data.\n * @since 0.2.0\n * @param TContextData The type of the context data.\n * @return The `Emoji` object.\n */\nexport type DeferredCustomEmoji<TContextData> = (\n session: Session<TContextData>,\n) => EmojiObject;\n"],"mappings":";;;;;;;;;;;AAoCA,SAAgB,QAAQA,OAAgC;AACtD,YAAW,UAAU,SAAU,QAAO;CAGtC,MAAM,YAAY,IAAI,KAAK,UAAU,MAAM,EAAE,aAAa,WAAY;CACtE,MAAM,WAAW,CAAC,GAAG,UAAU,QAAQ,MAAM,AAAC;AAC9C,KAAI,SAAS,WAAW,EAAG,QAAO;AAGlC,QAAO,aAAa,KAAK,SAAS,GAAG,QAAQ;AAC9C;;;;;;;;;;;AAYD,SAAgB,MACdC,SACA,GAAG,QACI;CACP,MAAM,SAAS,OAAO,IAAI,SAAS,GAAG,OAAO;AAC7C,MAAK,QAAQ,OAAO,CAClB,OAAM,IAAI,WAAW,iBAAiB,OAAO;AAE/C,QAAO;AACR"}
package/dist/events.d.ts CHANGED
@@ -5,7 +5,7 @@ import { Message, MessageClass, SharedMessage } from "./message.js";
5
5
  import { Vote } from "./poll.js";
6
6
  import { Session } from "./session.js";
7
7
  import { FollowRequest } from "./follow.js";
8
- import { Actor } from "@fedify/fedify/vocab";
8
+ import { Actor } from "@fedify/vocab";
9
9
 
10
10
  //#region src/events.d.ts
11
11
  /**
@@ -2,7 +2,7 @@ import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
2
2
  Date.prototype.toTemporalInstant = toTemporalInstant;
3
3
  import { FollowRequest } from "./follow.js";
4
4
  import { SessionImpl } from "./session-impl.js";
5
- import { Actor, Follow } from "@fedify/fedify/vocab";
5
+ import { Actor, Follow } from "@fedify/vocab";
6
6
 
7
7
  //#region src/follow-impl.d.ts
8
8
  declare class FollowRequestImpl<TContextData> implements FollowRequest {
@@ -2,7 +2,7 @@
2
2
  import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
3
3
  Date.prototype.toTemporalInstant = toTemporalInstant;
4
4
 
5
- import { Accept, Reject } from "@fedify/fedify/vocab";
5
+ import { Accept, Reject } from "@fedify/vocab";
6
6
 
7
7
  //#region src/follow-impl.ts
8
8
  var FollowRequestImpl = class {
@@ -1 +1 @@
1
- {"version":3,"file":"follow-impl.js","names":["#state","session: SessionImpl<TContextData>","raw: Follow","follower: Actor"],"sources":["../src/follow-impl.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { Accept, type Actor, type Follow, Reject } from \"@fedify/fedify/vocab\";\nimport type { FollowRequest } from \"./follow.ts\";\nimport type { SessionImpl } from \"./session-impl.ts\";\n\nexport class FollowRequestImpl<TContextData> implements FollowRequest {\n readonly session: SessionImpl<TContextData>;\n readonly id: URL;\n readonly raw: Follow;\n readonly follower: Actor;\n #state: \"pending\" | \"accepted\" | \"rejected\";\n\n get state(): \"pending\" | \"accepted\" | \"rejected\" {\n return this.#state;\n }\n\n constructor(\n session: SessionImpl<TContextData>,\n raw: Follow,\n follower: Actor,\n ) {\n if (raw.id == null) {\n throw new TypeError(\"The follow request ID is missing.\");\n } else if (follower.id == null) {\n throw new TypeError(\"The follower ID is missing.\");\n }\n this.session = session;\n this.id = raw.id;\n this.raw = raw;\n this.follower = follower;\n this.#state = \"pending\";\n }\n\n async accept(): Promise<void> {\n if (this.#state !== \"pending\") {\n throw new TypeError(\"The follow request is not pending.\");\n }\n await this.session.context.sendActivity(\n this.session.bot,\n this.follower,\n new Accept({\n id: new URL(`/#accept/${this.id.href}`, this.session.actorId),\n actor: this.session.actorId,\n to: this.follower.id,\n object: this.raw,\n }),\n { excludeBaseUris: [new URL(this.session.context.origin)] },\n );\n await this.session.bot.repository.addFollower(this.id, this.follower);\n this.#state = \"accepted\";\n }\n\n async reject(): Promise<void> {\n if (this.#state !== \"pending\") {\n throw new TypeError(\"The follow request is not pending.\");\n }\n await this.session.context.sendActivity(\n this.session.bot,\n this.follower,\n new Reject({\n id: new URL(`/#accept/${this.id.href}`, this.session.actorId),\n actor: this.session.actorId,\n to: this.follower.id,\n object: this.raw,\n }),\n { excludeBaseUris: [new URL(this.session.context.origin)] },\n );\n this.#state = \"rejected\";\n }\n}\n"],"mappings":";;;;;;;AAmBA,IAAa,oBAAb,MAAsE;CACpE,AAAS;CACT,AAAS;CACT,AAAS;CACT,AAAS;CACT;CAEA,IAAI,QAA6C;AAC/C,SAAO,KAAKA;CACb;CAED,YACEC,SACAC,KACAC,UACA;AACA,MAAI,IAAI,MAAM,KACZ,OAAM,IAAI,UAAU;WACX,SAAS,MAAM,KACxB,OAAM,IAAI,UAAU;AAEtB,OAAK,UAAU;AACf,OAAK,KAAK,IAAI;AACd,OAAK,MAAM;AACX,OAAK,WAAW;AAChB,OAAKH,SAAS;CACf;CAED,MAAM,SAAwB;AAC5B,MAAI,KAAKA,WAAW,UAClB,OAAM,IAAI,UAAU;AAEtB,QAAM,KAAK,QAAQ,QAAQ,aACzB,KAAK,QAAQ,KACb,KAAK,UACL,IAAI,OAAO;GACT,IAAI,IAAI,KAAK,WAAW,KAAK,GAAG,KAAK,GAAG,KAAK,QAAQ;GACrD,OAAO,KAAK,QAAQ;GACpB,IAAI,KAAK,SAAS;GAClB,QAAQ,KAAK;EACd,IACD,EAAE,iBAAiB,CAAC,IAAI,IAAI,KAAK,QAAQ,QAAQ,OAAQ,EAAE,EAC5D;AACD,QAAM,KAAK,QAAQ,IAAI,WAAW,YAAY,KAAK,IAAI,KAAK,SAAS;AACrE,OAAKA,SAAS;CACf;CAED,MAAM,SAAwB;AAC5B,MAAI,KAAKA,WAAW,UAClB,OAAM,IAAI,UAAU;AAEtB,QAAM,KAAK,QAAQ,QAAQ,aACzB,KAAK,QAAQ,KACb,KAAK,UACL,IAAI,OAAO;GACT,IAAI,IAAI,KAAK,WAAW,KAAK,GAAG,KAAK,GAAG,KAAK,QAAQ;GACrD,OAAO,KAAK,QAAQ;GACpB,IAAI,KAAK,SAAS;GAClB,QAAQ,KAAK;EACd,IACD,EAAE,iBAAiB,CAAC,IAAI,IAAI,KAAK,QAAQ,QAAQ,OAAQ,EAAE,EAC5D;AACD,OAAKA,SAAS;CACf;AACF"}
1
+ {"version":3,"file":"follow-impl.js","names":["#state","session: SessionImpl<TContextData>","raw: Follow","follower: Actor"],"sources":["../src/follow-impl.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { Accept, type Actor, type Follow, Reject } from \"@fedify/vocab\";\nimport type { FollowRequest } from \"./follow.ts\";\nimport type { SessionImpl } from \"./session-impl.ts\";\n\nexport class FollowRequestImpl<TContextData> implements FollowRequest {\n readonly session: SessionImpl<TContextData>;\n readonly id: URL;\n readonly raw: Follow;\n readonly follower: Actor;\n #state: \"pending\" | \"accepted\" | \"rejected\";\n\n get state(): \"pending\" | \"accepted\" | \"rejected\" {\n return this.#state;\n }\n\n constructor(\n session: SessionImpl<TContextData>,\n raw: Follow,\n follower: Actor,\n ) {\n if (raw.id == null) {\n throw new TypeError(\"The follow request ID is missing.\");\n } else if (follower.id == null) {\n throw new TypeError(\"The follower ID is missing.\");\n }\n this.session = session;\n this.id = raw.id;\n this.raw = raw;\n this.follower = follower;\n this.#state = \"pending\";\n }\n\n async accept(): Promise<void> {\n if (this.#state !== \"pending\") {\n throw new TypeError(\"The follow request is not pending.\");\n }\n await this.session.context.sendActivity(\n this.session.bot,\n this.follower,\n new Accept({\n id: new URL(`/#accept/${this.id.href}`, this.session.actorId),\n actor: this.session.actorId,\n to: this.follower.id,\n object: this.raw,\n }),\n { excludeBaseUris: [new URL(this.session.context.origin)] },\n );\n await this.session.bot.repository.addFollower(this.id, this.follower);\n this.#state = \"accepted\";\n }\n\n async reject(): Promise<void> {\n if (this.#state !== \"pending\") {\n throw new TypeError(\"The follow request is not pending.\");\n }\n await this.session.context.sendActivity(\n this.session.bot,\n this.follower,\n new Reject({\n id: new URL(`/#accept/${this.id.href}`, this.session.actorId),\n actor: this.session.actorId,\n to: this.follower.id,\n object: this.raw,\n }),\n { excludeBaseUris: [new URL(this.session.context.origin)] },\n );\n this.#state = \"rejected\";\n }\n}\n"],"mappings":";;;;;;;AAmBA,IAAa,oBAAb,MAAsE;CACpE,AAAS;CACT,AAAS;CACT,AAAS;CACT,AAAS;CACT;CAEA,IAAI,QAA6C;AAC/C,SAAO,KAAKA;CACb;CAED,YACEC,SACAC,KACAC,UACA;AACA,MAAI,IAAI,MAAM,KACZ,OAAM,IAAI,UAAU;WACX,SAAS,MAAM,KACxB,OAAM,IAAI,UAAU;AAEtB,OAAK,UAAU;AACf,OAAK,KAAK,IAAI;AACd,OAAK,MAAM;AACX,OAAK,WAAW;AAChB,OAAKH,SAAS;CACf;CAED,MAAM,SAAwB;AAC5B,MAAI,KAAKA,WAAW,UAClB,OAAM,IAAI,UAAU;AAEtB,QAAM,KAAK,QAAQ,QAAQ,aACzB,KAAK,QAAQ,KACb,KAAK,UACL,IAAI,OAAO;GACT,IAAI,IAAI,KAAK,WAAW,KAAK,GAAG,KAAK,GAAG,KAAK,QAAQ;GACrD,OAAO,KAAK,QAAQ;GACpB,IAAI,KAAK,SAAS;GAClB,QAAQ,KAAK;EACd,IACD,EAAE,iBAAiB,CAAC,IAAI,IAAI,KAAK,QAAQ,QAAQ,OAAQ,EAAE,EAC5D;AACD,QAAM,KAAK,QAAQ,IAAI,WAAW,YAAY,KAAK,IAAI,KAAK,SAAS;AACrE,OAAKA,SAAS;CACf;CAED,MAAM,SAAwB;AAC5B,MAAI,KAAKA,WAAW,UAClB,OAAM,IAAI,UAAU;AAEtB,QAAM,KAAK,QAAQ,QAAQ,aACzB,KAAK,QAAQ,KACb,KAAK,UACL,IAAI,OAAO;GACT,IAAI,IAAI,KAAK,WAAW,KAAK,GAAG,KAAK,GAAG,KAAK,QAAQ;GACrD,OAAO,KAAK,QAAQ;GACpB,IAAI,KAAK,SAAS;GAClB,QAAQ,KAAK;EACd,IACD,EAAE,iBAAiB,CAAC,IAAI,IAAI,KAAK,QAAQ,QAAQ,OAAQ,EAAE,EAC5D;AACD,OAAKA,SAAS;CACf;AACF"}
@@ -8,10 +8,9 @@ import { SessionImpl } from "./session-impl.js";
8
8
  import { BotImpl } from "./bot-impl.js";
9
9
  import { createMockContext } from "./session-impl.test.js";
10
10
  import { MemoryKvStore } from "@fedify/fedify/federation";
11
- import { Accept, Follow, Reject } from "@fedify/fedify/vocab";
11
+ import { Accept, Follow, Person, Reject } from "@fedify/vocab";
12
12
  import assert from "node:assert";
13
13
  import { test } from "node:test";
14
- import { Person as Person$1 } from "@fedify/fedify";
15
14
 
16
15
  //#region src/follow-impl.test.ts
17
16
  test("new FollowRequestImpl()", () => {
@@ -21,7 +20,7 @@ test("new FollowRequestImpl()", () => {
21
20
  });
22
21
  const ctx = createMockContext(bot, "https://example.com");
23
22
  const session = new SessionImpl(bot, ctx);
24
- const follower = new Person$1({
23
+ const follower = new Person({
25
24
  id: new URL("https://example.com/ap/actor/john"),
26
25
  preferredUsername: "john"
27
26
  });
@@ -46,7 +45,7 @@ test("FollowRequestImpl.accept()", async () => {
46
45
  });
47
46
  const ctx = createMockContext(bot, "https://example.com");
48
47
  const session = new SessionImpl(bot, ctx);
49
- const follower = new Person$1({
48
+ const follower = new Person({
50
49
  id: new URL("https://example.com/ap/actor/john"),
51
50
  preferredUsername: "john"
52
51
  });
@@ -82,7 +81,7 @@ test("FollowRequestImpl.reject()", async () => {
82
81
  });
83
82
  const ctx = createMockContext(bot, "https://example.com");
84
83
  const session = new SessionImpl(bot, ctx);
85
- const follower = new Person$1({
84
+ const follower = new Person({
86
85
  id: new URL("https://example.com/ap/actor/john"),
87
86
  preferredUsername: "john"
88
87
  });
@@ -1 +1 @@
1
- {"version":3,"file":"follow-impl.test.js","names":["Person"],"sources":["../src/follow-impl.test.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { Person } from \"@fedify/fedify\";\nimport { MemoryKvStore } from \"@fedify/fedify/federation\";\nimport { Accept, Follow, Reject } from \"@fedify/fedify/vocab\";\nimport assert from \"node:assert\";\nimport { test } from \"node:test\";\nimport { BotImpl } from \"./bot-impl.ts\";\nimport { FollowRequestImpl } from \"./follow-impl.ts\";\nimport { MemoryRepository } from \"./repository.ts\";\nimport { createMockContext } from \"./session-impl.test.ts\";\nimport { SessionImpl } from \"./session-impl.ts\";\n\ntest(\"new FollowRequestImpl()\", () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n assert.deepStrictEqual(followRequest.session, session);\n assert.deepStrictEqual(followRequest.id, follow.id);\n assert.deepStrictEqual(followRequest.raw, follow);\n assert.deepStrictEqual(followRequest.follower, follower);\n assert.deepStrictEqual(followRequest.state, \"pending\");\n});\n\ntest(\"FollowRequestImpl.accept()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n await followRequest.accept();\n assert.deepStrictEqual(followRequest.state, \"accepted\");\n assert.ok(\n await repository.hasFollower(new URL(\"https://example.com/ap/actor/john\")),\n );\n const [storedFollower] = await Array.fromAsync(repository.getFollowers());\n assert.ok(storedFollower != null);\n assert.deepStrictEqual(storedFollower.id, follower.id);\n assert.deepStrictEqual(\n storedFollower.preferredUsername,\n follower.preferredUsername,\n );\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [follower]);\n assert.ok(activity instanceof Accept);\n assert.deepStrictEqual(activity.actorId, session.actorId);\n assert.deepStrictEqual(activity.toId, follower.id);\n assert.deepStrictEqual(activity.objectId, follow.id);\n\n assert.rejects(\n () => followRequest.accept(),\n TypeError,\n \"The follow request is not pending.\",\n );\n assert.rejects(\n () => followRequest.reject(),\n TypeError,\n \"The follow request is not pending.\",\n );\n});\n\ntest(\"FollowRequestImpl.reject()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n await followRequest.reject();\n assert.deepStrictEqual(followRequest.state, \"rejected\");\n assert.deepStrictEqual(\n await repository.hasFollower(new URL(\"https://example.com/ap/actor/john\")),\n false,\n );\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [follower]);\n assert.ok(activity instanceof Reject);\n assert.deepStrictEqual(activity.actorId, session.actorId);\n assert.deepStrictEqual(activity.toId, follower.id);\n assert.deepStrictEqual(activity.objectId, follow.id);\n\n assert.rejects(\n () => followRequest.accept(),\n TypeError,\n \"The follow request is not pending.\",\n );\n assert.rejects(\n () => followRequest.reject(),\n TypeError,\n \"The follow request is not pending.\",\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"follow-impl.test.js","names":[],"sources":["../src/follow-impl.test.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { Person } from \"@fedify/vocab\";\nimport { MemoryKvStore } from \"@fedify/fedify/federation\";\nimport { Accept, Follow, Reject } from \"@fedify/vocab\";\nimport assert from \"node:assert\";\nimport { test } from \"node:test\";\nimport { BotImpl } from \"./bot-impl.ts\";\nimport { FollowRequestImpl } from \"./follow-impl.ts\";\nimport { MemoryRepository } from \"./repository.ts\";\nimport { createMockContext } from \"./session-impl.test.ts\";\nimport { SessionImpl } from \"./session-impl.ts\";\n\ntest(\"new FollowRequestImpl()\", () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n assert.deepStrictEqual(followRequest.session, session);\n assert.deepStrictEqual(followRequest.id, follow.id);\n assert.deepStrictEqual(followRequest.raw, follow);\n assert.deepStrictEqual(followRequest.follower, follower);\n assert.deepStrictEqual(followRequest.state, \"pending\");\n});\n\ntest(\"FollowRequestImpl.accept()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n await followRequest.accept();\n assert.deepStrictEqual(followRequest.state, \"accepted\");\n assert.ok(\n await repository.hasFollower(new URL(\"https://example.com/ap/actor/john\")),\n );\n const [storedFollower] = await Array.fromAsync(repository.getFollowers());\n assert.ok(storedFollower != null);\n assert.deepStrictEqual(storedFollower.id, follower.id);\n assert.deepStrictEqual(\n storedFollower.preferredUsername,\n follower.preferredUsername,\n );\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [follower]);\n assert.ok(activity instanceof Accept);\n assert.deepStrictEqual(activity.actorId, session.actorId);\n assert.deepStrictEqual(activity.toId, follower.id);\n assert.deepStrictEqual(activity.objectId, follow.id);\n\n assert.rejects(\n () => followRequest.accept(),\n TypeError,\n \"The follow request is not pending.\",\n );\n assert.rejects(\n () => followRequest.reject(),\n TypeError,\n \"The follow request is not pending.\",\n );\n});\n\ntest(\"FollowRequestImpl.reject()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n await followRequest.reject();\n assert.deepStrictEqual(followRequest.state, \"rejected\");\n assert.deepStrictEqual(\n await repository.hasFollower(new URL(\"https://example.com/ap/actor/john\")),\n false,\n );\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [follower]);\n assert.ok(activity instanceof Reject);\n assert.deepStrictEqual(activity.actorId, session.actorId);\n assert.deepStrictEqual(activity.toId, follower.id);\n assert.deepStrictEqual(activity.objectId, follow.id);\n\n assert.rejects(\n () => followRequest.accept(),\n TypeError,\n \"The follow request is not pending.\",\n );\n assert.rejects(\n () => followRequest.reject(),\n TypeError,\n \"The follow request is not pending.\",\n );\n});\n"],"mappings":"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"}
package/dist/follow.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
2
2
  Date.prototype.toTemporalInstant = toTemporalInstant;
3
- import { Actor, Follow } from "@fedify/fedify/vocab";
3
+ import { Actor, Follow } from "@fedify/vocab";
4
4
 
5
5
  //#region src/follow.d.ts
6
6
  /**
@@ -6,8 +6,7 @@ import { AuthorizedMessage, AuthorizedSharedMessage, Message, MessageClass, Mess
6
6
  import { SessionPublishOptions, SessionPublishOptionsWithClass } from "./session.js";
7
7
  import { DeferredCustomEmoji, Emoji } from "./emoji.js";
8
8
  import { SessionImpl } from "./session-impl.js";
9
- import { Actor, Article, ChatMessage, Document, Emoji as Emoji$1, Hashtag, Link, Note, Object as Object$1, Question } from "@fedify/fedify/vocab";
10
- import { LanguageTag } from "@phensley/language-tag";
9
+ import { Actor, Article, ChatMessage, Document, Emoji as Emoji$1, Hashtag, Link, Note, Object as Object$1, Question } from "@fedify/vocab";
11
10
 
12
11
  //#region src/message-impl.d.ts
13
12
  declare const messageClasses: (typeof Article | typeof ChatMessage | typeof Note | typeof Question)[];
@@ -21,7 +20,7 @@ declare class MessageImpl<T extends MessageClass, TContextData> implements Messa
21
20
  readonly id: URL;
22
21
  readonly actor: Actor;
23
22
  readonly visibility: MessageVisibility;
24
- readonly language?: LanguageTag | undefined;
23
+ readonly language?: Intl.Locale | undefined;
25
24
  text: string;
26
25
  html: string;
27
26
  readonly replyTarget?: Message<MessageClass, TContextData> | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"message-impl.d.ts","names":[],"sources":["../src/message-impl.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"message-impl.d.ts","names":[],"sources":["../src/message-impl.ts"],"sourcesContent":[],"mappings":"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"}
@@ -2,8 +2,8 @@
2
2
  import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
3
3
  Date.prototype.toTemporalInstant = toTemporalInstant;
4
4
 
5
- import { Announce, Article, ChatMessage, Create, Delete, Document, EmojiReact, Hashtag, Like, Link, Mention, Note, PUBLIC_COLLECTION, Question, Tombstone, Undo, Update, isActor } from "@fedify/fedify/vocab";
6
- import { LanguageString } from "@fedify/fedify/runtime";
5
+ import { Announce, Article, ChatMessage, Create, Delete, Document, EmojiReact, Hashtag, Like, Link, Mention, Note, PUBLIC_COLLECTION, Question, Tombstone, Undo, Update, isActor } from "@fedify/vocab";
6
+ import { LanguageString } from "@fedify/vocab-runtime";
7
7
  import { decode } from "html-entities";
8
8
  import { v7 } from "uuid";
9
9
  import xss from "xss";
@@ -402,7 +402,7 @@ async function createMessage(raw, session, cachedObjects, replyTarget, quoteTarg
402
402
  id: raw.id,
403
403
  actor,
404
404
  visibility: getMessageVisibility(raw.toIds, raw.ccIds, actor, mentionedActorIds),
405
- language: raw.content instanceof LanguageString ? raw.content.language : void 0,
405
+ language: raw.content instanceof LanguageString ? raw.content.locale : void 0,
406
406
  text: decode(text),
407
407
  html,
408
408
  replyTarget,