@fedify/botkit 0.3.0-dev.108

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 (94) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +75 -0
  3. package/dist/bot-impl.d.ts +111 -0
  4. package/dist/bot-impl.d.ts.map +1 -0
  5. package/dist/bot-impl.js +602 -0
  6. package/dist/bot-impl.js.map +1 -0
  7. package/dist/bot-impl.test.d.ts +2 -0
  8. package/dist/bot-impl.test.js +1642 -0
  9. package/dist/bot-impl.test.js.map +1 -0
  10. package/dist/bot.d.ts +270 -0
  11. package/dist/bot.d.ts.map +1 -0
  12. package/dist/bot.js +118 -0
  13. package/dist/bot.js.map +1 -0
  14. package/dist/bot.test.d.ts +2 -0
  15. package/dist/bot.test.js +80 -0
  16. package/dist/bot.test.js.map +1 -0
  17. package/dist/components/Layout.d.ts +26 -0
  18. package/dist/components/Layout.d.ts.map +1 -0
  19. package/dist/components/Layout.js +36 -0
  20. package/dist/components/Layout.js.map +1 -0
  21. package/dist/components/Message.d.ts +21 -0
  22. package/dist/components/Message.d.ts.map +1 -0
  23. package/dist/components/Message.js +99 -0
  24. package/dist/components/Message.js.map +1 -0
  25. package/dist/components/Message.test.d.ts +2 -0
  26. package/dist/components/Message.test.js +32 -0
  27. package/dist/components/Message.test.js.map +1 -0
  28. package/dist/deno.js +73 -0
  29. package/dist/deno.js.map +1 -0
  30. package/dist/emoji.d.ts +87 -0
  31. package/dist/emoji.d.ts.map +1 -0
  32. package/dist/emoji.js +37 -0
  33. package/dist/emoji.js.map +1 -0
  34. package/dist/emoji.test.d.ts +2 -0
  35. package/dist/emoji.test.js +109 -0
  36. package/dist/emoji.test.js.map +1 -0
  37. package/dist/events.d.ts +110 -0
  38. package/dist/events.d.ts.map +1 -0
  39. package/dist/events.js +4 -0
  40. package/dist/follow-impl.d.ts +23 -0
  41. package/dist/follow-impl.d.ts.map +1 -0
  42. package/dist/follow-impl.js +51 -0
  43. package/dist/follow-impl.js.map +1 -0
  44. package/dist/follow-impl.test.d.ts +2 -0
  45. package/dist/follow-impl.test.js +110 -0
  46. package/dist/follow-impl.test.js.map +1 -0
  47. package/dist/follow.d.ts +44 -0
  48. package/dist/follow.d.ts.map +1 -0
  49. package/dist/follow.js +4 -0
  50. package/dist/message-impl.d.ts +54 -0
  51. package/dist/message-impl.d.ts.map +1 -0
  52. package/dist/message-impl.js +439 -0
  53. package/dist/message-impl.js.map +1 -0
  54. package/dist/message-impl.test.d.ts +2 -0
  55. package/dist/message-impl.test.js +519 -0
  56. package/dist/message-impl.test.js.map +1 -0
  57. package/dist/message.d.ts +223 -0
  58. package/dist/message.d.ts.map +1 -0
  59. package/dist/message.js +8 -0
  60. package/dist/mod.d.ts +13 -0
  61. package/dist/mod.js +13 -0
  62. package/dist/pages.d.ts +20 -0
  63. package/dist/pages.d.ts.map +1 -0
  64. package/dist/pages.js +361 -0
  65. package/dist/pages.js.map +1 -0
  66. package/dist/reaction.d.ts +90 -0
  67. package/dist/reaction.d.ts.map +1 -0
  68. package/dist/reaction.js +7 -0
  69. package/dist/repository.d.ts +323 -0
  70. package/dist/repository.d.ts.map +1 -0
  71. package/dist/repository.js +483 -0
  72. package/dist/repository.js.map +1 -0
  73. package/dist/repository.test.d.ts +2 -0
  74. package/dist/repository.test.js +336 -0
  75. package/dist/repository.test.js.map +1 -0
  76. package/dist/session-impl.d.ts +32 -0
  77. package/dist/session-impl.d.ts.map +1 -0
  78. package/dist/session-impl.js +195 -0
  79. package/dist/session-impl.js.map +1 -0
  80. package/dist/session-impl.test.d.ts +20 -0
  81. package/dist/session-impl.test.d.ts.map +1 -0
  82. package/dist/session-impl.test.js +464 -0
  83. package/dist/session-impl.test.js.map +1 -0
  84. package/dist/session.d.ts +139 -0
  85. package/dist/session.d.ts.map +1 -0
  86. package/dist/session.js +4 -0
  87. package/dist/text.d.ts +391 -0
  88. package/dist/text.d.ts.map +1 -0
  89. package/dist/text.js +640 -0
  90. package/dist/text.js.map +1 -0
  91. package/dist/text.test.d.ts +2 -0
  92. package/dist/text.test.js +473 -0
  93. package/dist/text.test.js.map +1 -0
  94. package/package.json +137 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot-impl.test.js","names":["followRequests: [Session<void>, FollowRequest][]","unfollowed: [Session<void>, Actor][]","accepted: [Session<void>, Actor][]","rejected: [Session<void>, Actor][]","replied: [Session<void>, Message<MessageClass, void>][]","mentioned: [Session<void>, Message<MessageClass, void>][]","messaged: [Session<void>, Message<MessageClass, void>][]","quoted: [Session<void>, Message<MessageClass, void>][]","session","msg","shares: [Session<void>, SharedMessage<MessageClass, void>][]","sharedMessage","likes: [Session<void>, Like<void>][]","like","RawLike","reactions: [Session<void>, Reaction<void>][]","reaction","emojiData: CustomEmoji","remoteEmojiData: CustomEmoji","localEmojiData: CustomEmoji","localEmojiDataNoExt: CustomEmoji","bot: BotImpl<void>","origin: string | URL","recipient?: string | null"],"sources":["../src/bot-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 { type InboxContext, MemoryKvStore } from \"@fedify/fedify/federation\";\nimport {\n Accept,\n type Activity,\n type Actor,\n Announce,\n Article,\n Create,\n CryptographicKey,\n Emoji,\n EmojiReact,\n Follow,\n Image,\n Like as RawLike,\n Mention,\n Note,\n Person,\n Place,\n PropertyValue,\n PUBLIC_COLLECTION,\n type Recipient,\n Reject,\n Service,\n Undo,\n} from \"@fedify/fedify/vocab\";\nimport assert from \"node:assert\";\nimport { describe, test } from \"node:test\";\nimport { BotImpl } from \"./bot-impl.ts\";\nimport { parseSemVer } from \"./bot.ts\";\nimport type { CustomEmoji } from \"./emoji.ts\";\nimport type { FollowRequest } from \"./follow.ts\";\nimport type { Message, MessageClass, SharedMessage } from \"./message.ts\";\nimport type { Like, Reaction } from \"./reaction.ts\";\nimport { MemoryRepository } from \"./repository.ts\";\nimport { SessionImpl } from \"./session-impl.ts\";\nimport type { Session } from \"./session.ts\";\nimport { mention, strong, text } from \"./text.ts\";\n\ndescribe(\"BotImpl.getActorSummary()\", () => {\n test(\"without summary\", async () => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const session = bot.getSession(\"https://example.com\");\n assert.deepStrictEqual(await bot.getActorSummary(session), null);\n });\n\n test(\"with summary\", async () => {\n const actor = new Person({\n id: new URL(\"https://example.com/actor/john\"),\n preferredUsername: \"john\",\n });\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n summary: text`A summary with a mention: ${actor}.`,\n });\n const session = bot.getSession(\"https://example.com\");\n const expected = {\n tags: [\n new Mention({\n href: new URL(\"https://example.com/actor/john\"),\n name: \"@john@example.com\",\n }),\n ],\n text: \"<p>A summary with a mention: \" +\n '<a href=\"https://example.com/actor/john\" translate=\"no\" ' +\n 'class=\"h-card u-url mention\" target=\"_blank\">@<span>' +\n \"john@example.com</span></a>.</p>\",\n };\n assert.deepStrictEqual(await bot.getActorSummary(session), expected);\n assert.deepStrictEqual(await bot.getActorSummary(session), expected);\n });\n});\n\ntest(\"BotImpl.getActorProperties()\", async () => {\n const actor = new Person({\n id: new URL(\"https://example.com/actor/john\"),\n preferredUsername: \"john\",\n });\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n properties: {\n Foo: strong(\"bar\"),\n Baz: mention(actor),\n Qux: text`quux`,\n },\n });\n const session = bot.getSession(\"https://example.com\");\n const expected = {\n pairs: [\n new PropertyValue({ name: \"Foo\", value: \"<strong>bar</strong>\" }),\n new PropertyValue({\n name: \"Baz\",\n value: '<a href=\"https://example.com/actor/john\" translate=\"no\" ' +\n 'class=\"h-card u-url mention\" target=\"_blank\">@<span>' +\n \"john@example.com</span></a>\",\n }),\n new PropertyValue({ name: \"Qux\", value: \"<p>quux</p>\" }),\n ],\n tags: [\n new Mention({\n href: new URL(\"https://example.com/actor/john\"),\n name: \"@john@example.com\",\n }),\n ],\n };\n assert.deepStrictEqual(await bot.getActorProperties(session), expected);\n assert.deepStrictEqual(await bot.getActorProperties(session), expected);\n});\n\ninterface KeyPair {\n private: JsonWebKey;\n public: JsonWebKey;\n}\n\ntest(\"BotImpl.dispatchActor()\", async () => {\n const mentionActor = new Person({\n id: new URL(\"https://example.com/actor/john\"),\n preferredUsername: \"john\",\n });\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"test\",\n name: \"Test Bot\",\n summary: text`A summary with a mention: ${mentionActor}.`,\n properties: {\n Foo: strong(\"bar\"),\n Baz: mention(mentionActor),\n Qux: text`quux`,\n },\n icon: new URL(\"https://example.com/icon.png\"),\n image: new URL(\"https://example.com/image.png\"),\n });\n const ctx = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n assert.deepStrictEqual(await bot.dispatchActor(ctx, \"non-existent\"), null);\n const actor = await bot.dispatchActor(ctx, \"bot\");\n assert.ok(actor instanceof Service);\n assert.deepStrictEqual(actor.id, new URL(\"https://example.com/ap/actor/bot\"));\n assert.deepStrictEqual(actor.preferredUsername, \"test\");\n assert.deepStrictEqual(actor.name, \"Test Bot\");\n assert.deepStrictEqual(\n actor.summary,\n \"<p>A summary with a mention: \" +\n '<a href=\"https://example.com/actor/john\" translate=\"no\" ' +\n 'class=\"h-card u-url mention\" target=\"_blank\">@<span>john@example.com' +\n \"</span></a>.</p>\",\n );\n const attachments = await Array.fromAsync(actor.getAttachments());\n assert.deepStrictEqual(attachments.length, 3);\n assert.ok(attachments[0] instanceof PropertyValue);\n assert.deepStrictEqual(attachments[0].name, \"Foo\");\n assert.deepStrictEqual(attachments[0].value, \"<strong>bar</strong>\");\n assert.ok(attachments[1] instanceof PropertyValue);\n assert.deepStrictEqual(attachments[1].name, \"Baz\");\n assert.deepStrictEqual(\n attachments[1].value,\n '<a href=\"https://example.com/actor/john\" translate=\"no\" ' +\n 'class=\"h-card u-url mention\" target=\"_blank\">@<span>' +\n \"john@example.com</span></a>\",\n );\n assert.ok(attachments[2] instanceof PropertyValue);\n assert.deepStrictEqual(attachments[2].name, \"Qux\");\n assert.deepStrictEqual(attachments[2].value, \"<p>quux</p>\");\n const tags = await Array.fromAsync(actor.getTags());\n assert.deepStrictEqual(tags.length, 1);\n assert.ok(tags[0] instanceof Mention);\n assert.deepStrictEqual(\n tags[0].href,\n new URL(\"https://example.com/actor/john\"),\n );\n assert.deepStrictEqual(tags[0].name, \"@john@example.com\");\n const icon = await actor.getIcon();\n assert.ok(icon instanceof Image);\n assert.deepStrictEqual(icon.url, new URL(\"https://example.com/icon.png\"));\n const image = await actor.getImage();\n assert.ok(image instanceof Image);\n assert.deepStrictEqual(image.url, new URL(\"https://example.com/image.png\"));\n assert.deepStrictEqual(\n actor.inboxId,\n new URL(\"https://example.com/ap/actor/bot/inbox\"),\n );\n assert.deepStrictEqual(\n actor.endpoints?.sharedInbox,\n new URL(\"https://example.com/ap/inbox\"),\n );\n assert.deepStrictEqual(\n actor.followersId,\n new URL(\"https://example.com/ap/actor/bot/followers\"),\n );\n assert.deepStrictEqual(\n actor.outboxId,\n new URL(\"https://example.com/ap/actor/bot/outbox\"),\n );\n const publicKey = await actor.getPublicKey();\n assert.ok(publicKey != null);\n assert.deepStrictEqual(publicKey.ownerId, actor.id);\n assert.ok(publicKey.publicKey != null);\n const keys = await repository.getKeyPairs();\n assert.ok(keys != null);\n assert.deepStrictEqual(publicKey.publicKey, keys[0].publicKey);\n const assertionMethods = await Array.fromAsync(actor.getAssertionMethods());\n assert.deepStrictEqual(assertionMethods.length, 2);\n assert.deepStrictEqual(\n assertionMethods.map((mk) => mk.controllerId),\n [actor.id, actor.id],\n );\n assert.deepStrictEqual(\n await Promise.all(assertionMethods.map((mk) => mk.publicKey)),\n keys.map((k) => k.publicKey),\n );\n});\n\ntest(\"BotImpl.mapHandle()\", () => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"username\",\n });\n const ctx = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n assert.deepStrictEqual(bot.mapHandle(ctx, \"non-existent\"), null);\n assert.deepStrictEqual(bot.mapHandle(ctx, \"username\"), \"bot\");\n});\n\ntest(\"BotImpl.dispatchActorKeyPairs()\", 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 = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n assert.deepStrictEqual(\n await bot.dispatchActorKeyPairs(ctx, \"non-existent\"),\n [],\n );\n // Generation:\n const keyPairs = await bot.dispatchActorKeyPairs(ctx, \"bot\");\n const storedKeyPairs = await repository.getKeyPairs();\n assert.deepStrictEqual(keyPairs, storedKeyPairs);\n // Retrieval:\n const keyPairs2 = await bot.dispatchActorKeyPairs(ctx, \"bot\");\n assert.deepStrictEqual(keyPairs2, storedKeyPairs);\n});\n\ntest(\"BotImpl.dispatchFollowers()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n collectionWindow: 2,\n });\n const ctx = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n assert.deepStrictEqual(\n await bot.dispatchFollowers(ctx, \"non-existent\", null),\n null,\n );\n assert.deepStrictEqual(\n await bot.dispatchFollowers(ctx, \"non-existent\", \"\"),\n null,\n );\n const empty = await bot.dispatchFollowers(ctx, \"bot\", null);\n assert.deepStrictEqual(empty, { items: [], nextCursor: null });\n\n await repository.addFollower(\n new URL(\"https://example.com/actor/1#follow\"),\n new Person({\n id: new URL(\"https://example.com/actor/1\"),\n preferredUsername: \"john\",\n inbox: new URL(\"https://example.com/actor/1/inbox\"),\n }),\n );\n await repository.addFollower(\n new URL(\"https://example.com/actor/2#follow\"),\n new Person({\n id: new URL(\"https://example.com/actor/2\"),\n preferredUsername: \"jane\",\n inbox: new URL(\"https://example.com/actor/2/inbox\"),\n }),\n );\n await repository.addFollower(\n new URL(\"https://example.com/actor/3#follow\"),\n new Person({\n id: new URL(\"https://example.com/actor/3\"),\n preferredUsername: \"joe\",\n inbox: new URL(\"https://example.com/actor/3/inbox\"),\n }),\n );\n const full = await bot.dispatchFollowers(ctx, \"bot\", null);\n assert.ok(full != null);\n assert.deepStrictEqual(full.nextCursor, null);\n assert.deepStrictEqual(full.items.length, 3);\n const items = full.items.toSorted((a, b) =>\n (a.id?.href ?? \"\").localeCompare(b.id?.href ?? \"\")\n );\n assert.ok(items[0] instanceof Person);\n assert.deepStrictEqual(items[0].id, new URL(\"https://example.com/actor/1\"));\n assert.ok(items[1] instanceof Person);\n assert.deepStrictEqual(items[1].id, new URL(\"https://example.com/actor/2\"));\n assert.ok(items[2] instanceof Person);\n assert.deepStrictEqual(items[2].id, new URL(\"https://example.com/actor/3\"));\n\n const firstPage = await bot.dispatchFollowers(ctx, \"bot\", \"0\");\n assert.ok(firstPage != null);\n assert.deepStrictEqual(firstPage.nextCursor, \"2\");\n assert.deepStrictEqual(firstPage.items.length, 2);\n assert.ok(firstPage.items[0] instanceof Person);\n assert.deepStrictEqual(\n firstPage.items[0].id,\n new URL(\"https://example.com/actor/3\"),\n );\n assert.ok(firstPage.items[1] instanceof Person);\n assert.deepStrictEqual(\n firstPage.items[1].id,\n new URL(\"https://example.com/actor/2\"),\n );\n\n const lastPage = await bot.dispatchFollowers(\n ctx,\n \"bot\",\n \"2\",\n );\n assert.ok(lastPage != null);\n assert.deepStrictEqual(lastPage.nextCursor, null);\n assert.deepStrictEqual(lastPage.items.length, 1);\n assert.ok(lastPage.items[0] instanceof Person);\n assert.deepStrictEqual(\n lastPage.items[0].id,\n new URL(\"https://example.com/actor/1\"),\n );\n});\n\ntest(\"BotImpl.getFollowersFirstCursor()\", () => {\n const kv = new MemoryKvStore();\n const bot = new BotImpl<void>({ kv, username: \"bot\", collectionWindow: 2 });\n const ctx = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n assert.deepStrictEqual(\n bot.getFollowersFirstCursor(ctx, \"non-existent\"),\n null,\n );\n assert.deepStrictEqual(bot.getFollowersFirstCursor(ctx, \"bot\"), \"0\");\n});\n\ntest(\"BotImpl.countFollowers()\", 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 = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n assert.deepStrictEqual(await bot.countFollowers(ctx, \"non-existent\"), null);\n assert.deepStrictEqual(await bot.countFollowers(ctx, \"bot\"), 0);\n await repository.addFollower(\n new URL(\"https://example.com/actor/1#follow\"),\n new Person({\n id: new URL(\"https://example.com/actor/1\"),\n preferredUsername: \"john\",\n inbox: new URL(\"https://example.com/actor/1/inbox\"),\n }),\n );\n await repository.addFollower(\n new URL(\"https://example.com/actor/2#follow\"),\n new Person({\n id: new URL(\"https://example.com/actor/2\"),\n preferredUsername: \"jane\",\n inbox: new URL(\"https://example.com/actor/2/inbox\"),\n }),\n );\n await repository.addFollower(\n new URL(\"https://example.com/actor/3#follow\"),\n new Person({\n id: new URL(\"https://example.com/actor/3\"),\n preferredUsername: \"joe\",\n inbox: new URL(\"https://example.com/actor/3/inbox\"),\n }),\n );\n assert.deepStrictEqual(await bot.countFollowers(ctx, \"non-existent\"), null);\n assert.deepStrictEqual(await bot.countFollowers(ctx, \"bot\"), 3);\n});\n\ntest(\"BotImpl.getPermissionChecker()\", 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 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n const publicPost = new Note({\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n });\n const unlistedPost = new Note({\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\n });\n const followersPost = new Note({\n tos: [\n new URL(\"https://example.com/ap/actor/bot/followers\"),\n new URL(\"https://example.com/ap/actor/mentioned\"),\n ],\n });\n const directPost = new Note({\n to: new URL(\"https://example.com/ap/actor/mentioned\"),\n });\n const anonymous = await bot.getPermissionChecker(ctx);\n assert.deepStrictEqual(anonymous(publicPost), true);\n assert.deepStrictEqual(anonymous(unlistedPost), true);\n assert.deepStrictEqual(anonymous(followersPost), false);\n assert.deepStrictEqual(anonymous(directPost), false);\n\n const actor = new Person({ id: new URL(\"https://example.com/actor/john\") });\n const ctx2 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n ctx2.getSignedKeyOwner = () => Promise.resolve(actor);\n const nonFollower = await bot.getPermissionChecker(ctx2);\n assert.deepStrictEqual(nonFollower(publicPost), true);\n assert.deepStrictEqual(nonFollower(unlistedPost), true);\n assert.deepStrictEqual(nonFollower(followersPost), false);\n assert.deepStrictEqual(nonFollower(directPost), false);\n\n await repository.addFollower(\n new URL(\"https://example.com/actor/john#follow\"),\n new Person({\n id: new URL(\"https://example.com/actor/john\"),\n preferredUsername: \"john\",\n }),\n );\n const ctx3 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n ctx3.getSignedKeyOwner = () => Promise.resolve(actor);\n const follower = await bot.getPermissionChecker(ctx3);\n assert.deepStrictEqual(follower(publicPost), true);\n assert.deepStrictEqual(follower(unlistedPost), true);\n assert.deepStrictEqual(follower(followersPost), true);\n assert.deepStrictEqual(follower(directPost), false);\n\n const mentionedActor = new Person({\n id: new URL(\"https://example.com/ap/actor/mentioned\"),\n });\n const ctx4 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n ctx4.getSignedKeyOwner = () => Promise.resolve(mentionedActor);\n const mentioned = await bot.getPermissionChecker(ctx4);\n assert.deepStrictEqual(mentioned(publicPost), true);\n assert.deepStrictEqual(mentioned(unlistedPost), true);\n assert.deepStrictEqual(mentioned(followersPost), true);\n assert.deepStrictEqual(mentioned(directPost), true);\n});\n\ntest(\"BotImpl.dispatchOutbox()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n collectionWindow: 2,\n });\n const ctx = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n assert.deepStrictEqual(\n await bot.dispatchOutbox(ctx, \"non-existent\", null),\n null,\n );\n assert.deepStrictEqual(\n await bot.dispatchOutbox(ctx, \"non-existent\", \"\"),\n null,\n );\n assert.deepStrictEqual(await bot.dispatchOutbox(ctx, \"bot\", null), {\n items: [],\n nextCursor: null,\n });\n assert.deepStrictEqual(await bot.dispatchOutbox(ctx, \"bot\", \"\"), {\n items: [],\n nextCursor: null,\n });\n\n await repository.addMessage(\n \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n published: Temporal.Instant.from(\"2025-01-01T00:00:00Z\"),\n }),\n published: Temporal.Instant.from(\"2025-01-01T00:00:00Z\"),\n }),\n );\n await repository.addMessage(\n \"46442170-836d-4a0d-9142-f31242abe2f9\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/46442170-836d-4a0d-9142-f31242abe2f9\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/2\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, followers!\",\n published: Temporal.Instant.from(\"2025-01-02T00:00:00Z\"),\n }),\n published: Temporal.Instant.from(\"2025-01-02T00:00:00Z\"),\n }),\n );\n await repository.addMessage(\n \"8386a4c7-06f8-409f-ad72-2bba43e83363\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/8386a4c7-06f8-409f-ad72-2bba43e83363\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/3\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n content: \"Hello, followers!\",\n published: Temporal.Instant.from(\"2025-01-03T00:00:00Z\"),\n }),\n published: Temporal.Instant.from(\"2025-01-03T00:00:00Z\"),\n }),\n );\n assert.deepStrictEqual(\n await bot.dispatchOutbox(ctx, \"non-existent\", null),\n null,\n );\n assert.deepStrictEqual(\n await bot.dispatchOutbox(ctx, \"non-existent\", \"\"),\n null,\n );\n const anonymous1 = await bot.dispatchOutbox(ctx, \"bot\", \"\");\n assert.ok(anonymous1 != null);\n assert.deepStrictEqual(anonymous1.nextCursor, \"2025-01-01T00:00:00Z\");\n assert.deepStrictEqual(anonymous1.items.length, 1);\n assert.ok(anonymous1.items[0] instanceof Create);\n assert.deepStrictEqual(\n anonymous1.items[0].id,\n new URL(\n \"https://example.com/ap/actor/bot/create/46442170-836d-4a0d-9142-f31242abe2f9\",\n ),\n );\n\n const anonymous2 = await bot.dispatchOutbox(\n ctx,\n \"bot\",\n \"2025-01-01T00:00:00Z\",\n );\n assert.ok(anonymous2 != null);\n assert.deepStrictEqual(anonymous2.nextCursor, null);\n assert.deepStrictEqual(anonymous2.items.length, 1);\n assert.ok(anonymous2.items[0] instanceof Create);\n assert.deepStrictEqual(\n anonymous2.items[0].id,\n new URL(\n \"https://example.com/ap/actor/bot/create/78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n ),\n );\n\n const ctx2 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n const actor = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n });\n ctx2.getSignedKeyOwner = () => Promise.resolve(actor);\n const mentioned = await bot.dispatchOutbox(ctx2, \"bot\", null);\n assert.ok(mentioned != null);\n assert.deepStrictEqual(mentioned.nextCursor, null);\n assert.deepStrictEqual(mentioned.items.length, 3);\n assert.ok(mentioned.items[0] instanceof Create);\n assert.deepStrictEqual(\n mentioned.items[0].id,\n new URL(\n \"https://example.com/ap/actor/bot/create/8386a4c7-06f8-409f-ad72-2bba43e83363\",\n ),\n );\n assert.ok(mentioned.items[1] instanceof Create);\n assert.deepStrictEqual(\n mentioned.items[1].id,\n new URL(\n \"https://example.com/ap/actor/bot/create/46442170-836d-4a0d-9142-f31242abe2f9\",\n ),\n );\n assert.ok(mentioned.items[2] instanceof Create);\n assert.deepStrictEqual(\n mentioned.items[2].id,\n new URL(\n \"https://example.com/ap/actor/bot/create/78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n ),\n );\n});\n\ntest(\"BotImpl.getOutboxFirstCursor()\", () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n const ctx = bot.federation.createContext(\n new URL(\"https://example.com/\"),\n undefined,\n );\n assert.deepStrictEqual(bot.getOutboxFirstCursor(ctx, \"non-existent\"), null);\n assert.deepStrictEqual(bot.getOutboxFirstCursor(ctx, \"bot\"), \"\");\n});\n\ntest(\"BotImpl.countOutbox()\", 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 = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n assert.deepStrictEqual(await bot.countOutbox(ctx, \"non-existent\"), null);\n assert.deepStrictEqual(await bot.countOutbox(ctx, \"bot\"), 0);\n\n await repository.addMessage(\n \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n }),\n );\n await repository.addMessage(\n \"46442170-836d-4a0d-9142-f31242abe2f9\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/46442170-836d-4a0d-9142-f31242abe2f9\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/2\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, followers!\",\n }),\n }),\n );\n await repository.addMessage(\n \"8386a4c7-06f8-409f-ad72-2bba43e83363\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/8386a4c7-06f8-409f-ad72-2bba43e83363\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/3\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n content: \"Hello, followers!\",\n }),\n }),\n );\n assert.deepStrictEqual(await bot.countOutbox(ctx, \"non-existent\"), null);\n assert.deepStrictEqual(await bot.countOutbox(ctx, \"bot\"), 3);\n});\n\ntest(\"BotImpl.dispatchFollow()\", 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 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n assert.deepStrictEqual(\n await bot.dispatchFollow(ctx, { id: crypto.randomUUID() }),\n null,\n );\n\n await repository.addSentFollow(\n \"b51f6ca8-53e6-4f7d-ac1f-d039e8c6df5a\",\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/b51f6ca8-53e6-4f7d-ac1f-d039e8c6df5a\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new URL(\"https://example.com/ap/actor/john\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n }),\n );\n const follow = await bot.dispatchFollow(ctx, {\n id: \"b51f6ca8-53e6-4f7d-ac1f-d039e8c6df5a\",\n });\n assert.ok(follow instanceof Follow);\n assert.deepStrictEqual(\n follow.id,\n new URL(\n \"https://example.com/ap/follow/b51f6ca8-53e6-4f7d-ac1f-d039e8c6df5a\",\n ),\n );\n assert.deepStrictEqual(\n follow.actorId,\n new URL(\"https://example.com/ap/actor/bot\"),\n );\n assert.deepStrictEqual(\n follow.objectId,\n new URL(\"https://example.com/ap/actor/john\"),\n );\n assert.deepStrictEqual(\n follow.toId,\n new URL(\"https://example.com/ap/actor/john\"),\n );\n});\n\ntest(\"BotImpl.authorizeFollow()\", 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 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n await repository.addSentFollow(\n \"b51f6ca8-53e6-4f7d-ac1f-d039e8c6df5a\",\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/b51f6ca8-53e6-4f7d-ac1f-d039e8c6df5a\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new URL(\"https://example.com/ap/actor/john\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n }),\n );\n assert.ok(\n await bot.authorizeFollow(\n ctx,\n { id: \"b51f6ca8-53e6-4f7d-ac1f-d039e8c6df5a\" },\n new CryptographicKey({}),\n new Person({ id: new URL(\"https://example.com/ap/actor/john\") }),\n ),\n );\n assert.ok(\n await bot.authorizeFollow(\n ctx,\n { id: \"b51f6ca8-53e6-4f7d-ac1f-d039e8c6df5a\" },\n new CryptographicKey({}),\n await new SessionImpl(bot, ctx).getActor(),\n ),\n );\n assert.deepStrictEqual(\n await bot.authorizeFollow(\n ctx,\n { id: \"b51f6ca8-53e6-4f7d-ac1f-d039e8c6df5a\" },\n new CryptographicKey({}),\n new Person({ id: new URL(\"https://example.com/ap/actor/alice\") }),\n ),\n false,\n );\n assert.deepStrictEqual(\n await bot.authorizeFollow(\n ctx,\n { id: crypto.randomUUID() },\n new CryptographicKey({}),\n new Person({ id: new URL(\"https://example.com/ap/actor/john\") }),\n ),\n false,\n );\n});\n\ntest(\"BotImpl.dispatchCreate()\", 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 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n assert.deepStrictEqual(\n await bot.dispatchCreate(ctx, { id: \"non-existent\" }),\n null,\n );\n\n await repository.addMessage(\n \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n }),\n );\n const create = await bot.dispatchCreate(ctx, {\n id: \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n });\n assert.ok(create instanceof Create);\n assert.deepStrictEqual(\n create.id,\n new URL(\n \"https://example.com/ap/actor/bot/create/78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n ),\n );\n const ctx2 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n const actor = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n });\n ctx2.getSignedKeyOwner = () => Promise.resolve(actor);\n assert.deepStrictEqual(\n await bot.dispatchCreate(ctx2, {\n id: \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n }),\n create,\n );\n\n await repository.addMessage(\n \"8386a4c7-06f8-409f-ad72-2bba43e83363\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/8386a4c7-06f8-409f-ad72-2bba43e83363\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/3\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n content: \"Hello, followers!\",\n }),\n }),\n );\n assert.deepStrictEqual(\n await bot.dispatchCreate(ctx, {\n id: \"8386a4c7-06f8-409f-ad72-2bba43e83363\",\n }),\n null,\n );\n const create2 = await bot.dispatchCreate(ctx2, {\n id: \"8386a4c7-06f8-409f-ad72-2bba43e83363\",\n });\n assert.ok(create2 instanceof Create);\n assert.deepStrictEqual(\n create2.id,\n new URL(\n \"https://example.com/ap/actor/bot/create/8386a4c7-06f8-409f-ad72-2bba43e83363\",\n ),\n );\n\n await repository.addMessage(\n \"ce8081ac-f238-484b-9a70-5d8a4b66d829\",\n new Announce({\n id: new URL(\n \"https://example.com/ap/actor/bot/announce/ce8081ac-f238-484b-9a70-5d8a4b66d829\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new URL(\"https://example.com/ap/actor/bot/note/2\"),\n }),\n );\n assert.deepStrictEqual(\n await bot.dispatchCreate(ctx, {\n id: \"ce8081ac-f238-484b-9a70-5d8a4b66d829\",\n }),\n null,\n );\n});\n\ntest(\"BotImpl.dispatchMessage()\", 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 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n assert.deepStrictEqual(\n await bot.dispatchMessage(Note, ctx, \"non-existent\"),\n null,\n );\n\n await repository.addMessage(\n \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n }),\n );\n const note = await bot.dispatchMessage(\n Note,\n ctx,\n \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n );\n assert.ok(note instanceof Note);\n assert.deepStrictEqual(\n note.id,\n new URL(\"https://example.com/ap/actor/bot/note/1\"),\n );\n\n const ctx2 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n const actor = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n });\n ctx2.getSignedKeyOwner = () => Promise.resolve(actor);\n assert.deepStrictEqual(\n await bot.dispatchMessage(\n Note,\n ctx2,\n \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n ),\n note,\n );\n\n assert.deepStrictEqual(\n await bot.dispatchMessage(\n Article,\n ctx,\n \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n ),\n null,\n );\n\n await repository.addMessage(\n \"8386a4c7-06f8-409f-ad72-2bba43e83363\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/8386a4c7-06f8-409f-ad72-2bba43e83363\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/3\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n content: \"Hello, followers!\",\n }),\n }),\n );\n assert.deepStrictEqual(\n await bot.dispatchMessage(\n Note,\n ctx,\n \"8386a4c7-06f8-409f-ad72-2bba43e83363\",\n ),\n null,\n );\n const note2 = await bot.dispatchMessage(\n Note,\n ctx2,\n \"8386a4c7-06f8-409f-ad72-2bba43e83363\",\n );\n assert.ok(note2 instanceof Note);\n assert.deepStrictEqual(\n note2.id,\n new URL(\"https://example.com/ap/actor/bot/note/3\"),\n );\n\n await repository.addMessage(\n \"ce8081ac-f238-484b-9a70-5d8a4b66d829\",\n new Announce({\n id: new URL(\n \"https://example.com/ap/actor/bot/announce/ce8081ac-f238-484b-9a70-5d8a4b66d829\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new URL(\"https://example.com/ap/actor/bot/note/2\"),\n }),\n );\n assert.deepStrictEqual(\n await bot.dispatchMessage(\n Note,\n ctx,\n \"ce8081ac-f238-484b-9a70-5d8a4b66d829\",\n ),\n null,\n );\n});\n\ntest(\"BotImpl.dispatchAnnounce()\", 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 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n assert.deepStrictEqual(\n await bot.dispatchAnnounce(ctx, { id: \"non-existent\" }),\n null,\n );\n\n await repository.addMessage(\n \"ce8081ac-f238-484b-9a70-5d8a4b66d829\",\n new Announce({\n id: new URL(\n \"https://example.com/ap/actor/bot/announce/ce8081ac-f238-484b-9a70-5d8a4b66d829\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new URL(\"https://example.com/ap/actor/bot/note/2\"),\n }),\n );\n const announce = await bot.dispatchAnnounce(ctx, {\n id: \"ce8081ac-f238-484b-9a70-5d8a4b66d829\",\n });\n assert.ok(announce instanceof Announce);\n assert.deepStrictEqual(\n announce.id,\n new URL(\n \"https://example.com/ap/actor/bot/announce/ce8081ac-f238-484b-9a70-5d8a4b66d829\",\n ),\n );\n\n await repository.addMessage(\n \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n new Create({\n id: new URL(\n \"https://example.com/ap/actor/bot/create/78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n }),\n );\n assert.deepStrictEqual(\n await bot.dispatchAnnounce(ctx, {\n id: \"78acb1ea-4ac6-46b7-bcd4-3a8965d8126e\",\n }),\n null,\n );\n\n await repository.addMessage(\n \"d4a7ef9b-682c-4de9-b23c-87747d6725cb\",\n new Announce({\n id: new URL(\n \"https://example.com/ap/actor/bot/announce/d4a7ef9b-682c-4de9-b23c-87747d6725cb\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(\"https://example.com/ap/actor/bot/note/2\"),\n }),\n );\n assert.deepStrictEqual(\n await bot.dispatchAnnounce(ctx, {\n id: \"d4a7ef9b-682c-4de9-b23c-87747d6725cb\",\n }),\n null,\n );\n const ctx2 = bot.federation.createContext(\n new Request(\"https://example.com/\"),\n undefined,\n );\n const actor = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n });\n ctx2.getSignedKeyOwner = () => Promise.resolve(actor);\n const announce2 = await bot.dispatchAnnounce(ctx2, {\n id: \"d4a7ef9b-682c-4de9-b23c-87747d6725cb\",\n });\n assert.ok(announce2 instanceof Announce);\n assert.deepStrictEqual(\n announce2.id,\n new URL(\n \"https://example.com/ap/actor/bot/announce/d4a7ef9b-682c-4de9-b23c-87747d6725cb\",\n ),\n );\n});\n\ntest(\"BotImpl.dispatchSharedKey()\", () => {\n const identifier = crypto.randomUUID();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n identifier,\n });\n const ctx = bot.federation.createContext(new URL(\"https://example.com\"));\n assert.deepStrictEqual(bot.dispatchSharedKey(ctx), { identifier });\n});\n\nfor (const policy of [\"accept\", \"reject\", \"manual\"] as const) {\n test(`BotImpl.onFollowed() [followerPolicy: ${policy}]`, async (t) => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n followerPolicy: policy,\n });\n const followRequests: [Session<void>, FollowRequest][] = [];\n bot.onFollow = (session, fr) => void (followRequests.push([session, fr]));\n const ctx = createMockInboxContext(bot, \"https://example.com\", \"bot\");\n\n await t.test(\"without actor\", async () => {\n const followWithoutActor = new Follow({\n id: new URL(\"https://example.com/ap/actor/john/follows/bot\"),\n object: new URL(\"https://example.com/ap/actor/bot\"),\n });\n await bot.onFollowed(ctx, followWithoutActor);\n assert.deepStrictEqual(await repository.countFollowers(), 0);\n });\n\n await t.test(\"with wrong actor\", async () => {\n const followWithWrongActor = new Follow({\n id: new URL(\"https://example.com/ap/actor/bot/follows/bot\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new URL(\"https://example.com/ap/actor/bot\"),\n });\n await bot.onFollowed(ctx, followWithWrongActor);\n assert.deepStrictEqual(await repository.countFollowers(), 0);\n });\n\n const actor = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n\n await t.test(\"with wrong recipient\", async () => {\n const followWithWrongRecipient = new Follow({\n id: new URL(\"https://example.com/ap/actor/john/follows/bot\"),\n actor,\n object: new URL(\"https://example.com/ap/actor/non-existent\"),\n });\n await bot.onFollowed(ctx, followWithWrongRecipient);\n assert.deepStrictEqual(await repository.countFollowers(), 0);\n });\n\n await t.test(\"with correct follow\", async () => {\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/actor/john/follows/bot\"),\n actor,\n object: new URL(\"https://example.com/ap/actor/bot\"),\n });\n await bot.onFollowed(ctx, follow);\n if (policy === \"accept\") {\n assert.deepStrictEqual(await repository.countFollowers(), 1);\n assert.ok(\n await repository.hasFollower(\n new URL(\"https://example.com/ap/actor/john\"),\n ),\n );\n const [storedFollower] = await Array.fromAsync(\n repository.getFollowers(),\n );\n assert.ok(storedFollower instanceof Person);\n assert.deepStrictEqual(storedFollower.id, actor.id);\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { activity, recipients } = ctx.sentActivities[0];\n assert.ok(activity instanceof Accept);\n assert.deepStrictEqual(\n activity.actorId,\n new URL(\"https://example.com/ap/actor/bot\"),\n );\n assert.deepStrictEqual(activity.objectId, follow.id);\n assert.deepStrictEqual(recipients.length, 1);\n assert.deepStrictEqual(recipients[0], actor);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n assert.deepStrictEqual(followRequests.length, 1);\n } else {\n assert.deepStrictEqual(await repository.countFollowers(), 0);\n if (policy === \"reject\") {\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { activity, recipients } = ctx.sentActivities[0];\n assert.ok(activity instanceof Reject);\n assert.deepStrictEqual(\n activity.actorId,\n new URL(\"https://example.com/ap/actor/bot\"),\n );\n assert.deepStrictEqual(activity.objectId, follow.id);\n assert.deepStrictEqual(recipients.length, 1);\n assert.deepStrictEqual(recipients[0], actor);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n } else {\n assert.deepStrictEqual(ctx.sentActivities, []);\n }\n }\n const [session, followRequest] = followRequests[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.ok(followRequest.follower instanceof Person);\n assert.deepStrictEqual(followRequest.follower.id, actor.id);\n });\n });\n}\n\ntest(\"BotImpl.onUnfollowed()\", async (t) => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const unfollowed: [Session<void>, Actor][] = [];\n bot.onUnfollow = (session, actor) => void (unfollowed.push([session, actor]));\n const ctx = createMockInboxContext(bot, \"https://example.com\", \"bot\");\n\n await repository.addFollower(\n new URL(\"https://example.com/ap/actor/john/follows/bot\"),\n new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n );\n\n async function assertNoEffect() {\n assert.deepStrictEqual(await repository.countFollowers(), 1);\n const [follower] = await Array.fromAsync(repository.getFollowers());\n assert.ok(follower instanceof Person);\n assert.deepStrictEqual(\n follower.id,\n new URL(\"https://example.com/ap/actor/john\"),\n );\n assert.deepStrictEqual(follower.preferredUsername, \"john\");\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n assert.deepStrictEqual(unfollowed, []);\n }\n\n await t.test(\"without Follow object\", async () => {\n const undo = new Undo({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n });\n await bot.onUnfollowed(ctx, undo);\n await assertNoEffect();\n });\n\n await t.test(\"without Follow.id\", async () => {\n const undo = new Undo({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new Follow({}),\n });\n await bot.onUnfollowed(ctx, undo);\n await assertNoEffect();\n });\n\n await t.test(\"with non-existent Follow.id\", async () => {\n const undo = new Undo({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new Follow({\n id: new URL(\"https://example.com/ap/actor/john/follows/non-existent\"),\n }),\n });\n await bot.onUnfollowed(ctx, undo);\n await assertNoEffect();\n });\n\n await t.test(\"with incorrect Follow.actorId\", async () => {\n const undo = new Undo({\n actor: new URL(\"https://example.com/ap/actor/wrong-actor\"),\n object: new Follow({\n id: new URL(\"https://example.com/ap/actor/john/follows/bot\"),\n }),\n });\n await bot.onUnfollowed(ctx, undo);\n await assertNoEffect();\n });\n\n await t.test(\"with correct Follow object\", async () => {\n const undo = new Undo({\n actor: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n object: new Follow({\n id: new URL(\"https://example.com/ap/actor/john/follows/bot\"),\n }),\n });\n await bot.onUnfollowed(ctx, undo);\n assert.deepStrictEqual(await repository.countFollowers(), 0);\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n assert.deepStrictEqual(unfollowed.length, 1);\n const [session, follower] = unfollowed[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.ok(follower instanceof Person);\n assert.deepStrictEqual(\n follower.id,\n new URL(\"https://example.com/ap/actor/john\"),\n );\n });\n});\n\ntest(\"BotImpl.onFollowAccepted()\", async (t) => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const accepted: [Session<void>, Actor][] = [];\n bot.onAcceptFollow = (session, actor) =>\n void (accepted.push([session, actor]));\n const ctx = createMockInboxContext(bot, \"https://example.com\", \"bot\");\n\n await t.test(\"without object\", async () => {\n await bot.onFollowAccepted(\n ctx,\n new Accept({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n }),\n );\n assert.deepStrictEqual(accepted, []);\n });\n\n await t.test(\"with invalid object URI\", async () => {\n await bot.onFollowAccepted(\n ctx,\n new Accept({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(\"https://example.com/\"),\n }),\n );\n assert.deepStrictEqual(accepted, []);\n });\n\n await t.test(\"with non-existent object\", async () => {\n await bot.onFollowAccepted(\n ctx,\n new Accept({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(`https://example.com/ap/follow/${crypto.randomUUID()}`),\n }),\n );\n assert.deepStrictEqual(accepted, []);\n });\n\n await t.test(\"with non-actor\", async () => {\n await repository.addSentFollow(\n \"2ca58e2a-a34a-43e6-81af-c4f21ffed0c5\",\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/2ca58e2a-a34a-43e6-81af-c4f21ffed0c5\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new Note({}),\n }),\n );\n await bot.onFollowAccepted(\n ctx,\n new Accept({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(\n \"https://example.com/ap/follow/2ca58e2a-a34a-43e6-81af-c4f21ffed0c5\",\n ),\n }),\n );\n assert.deepStrictEqual(accepted, []);\n });\n\n await t.test(\"with actor without URI\", async () => {\n await repository.addSentFollow(\n \"a99ff3bf-72a2-412b-83b9-cba894d38805\",\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/a99ff3bf-72a2-412b-83b9-cba894d38805\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new Person({\n preferredUsername: \"john\",\n }),\n }),\n );\n await bot.onFollowAccepted(\n ctx,\n new Accept({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(\n \"https://example.com/ap/follow/a99ff3bf-72a2-412b-83b9-cba894d38805\",\n ),\n }),\n );\n assert.deepStrictEqual(accepted, []);\n });\n\n await t.test(\"with actor\", async () => {\n await repository.addSentFollow(\n \"3bca0b8e-503a-47ea-ad69-6b7c29369fbd\",\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/3bca0b8e-503a-47ea-ad69-6b7c29369fbd\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n }),\n );\n await bot.onFollowAccepted(\n ctx,\n new Accept({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(\n \"https://example.com/ap/follow/3bca0b8e-503a-47ea-ad69-6b7c29369fbd\",\n ),\n }),\n );\n assert.deepStrictEqual(accepted.length, 1);\n const [session, actor] = accepted[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.ok(actor instanceof Person);\n assert.deepStrictEqual(\n actor.id,\n new URL(\"https://example.com/ap/actor/john\"),\n );\n const follow = await repository.getFollowee(\n new URL(\"https://example.com/ap/actor/john\"),\n );\n assert.ok(follow != null);\n assert.ok(follow instanceof Follow);\n assert.deepStrictEqual(\n follow.id,\n new URL(\n \"https://example.com/ap/follow/3bca0b8e-503a-47ea-ad69-6b7c29369fbd\",\n ),\n );\n assert.deepStrictEqual(follow.objectId, actor.id);\n });\n});\n\ntest(\"BotImpl.onFollowRejected()\", async (t) => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const rejected: [Session<void>, Actor][] = [];\n bot.onRejectFollow = (session, actor) =>\n void (rejected.push([session, actor]));\n const ctx = createMockInboxContext(bot, \"https://example.com\", \"bot\");\n\n await t.test(\"without object\", async () => {\n await bot.onFollowRejected(\n ctx,\n new Reject({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n }),\n );\n assert.deepStrictEqual(rejected, []);\n });\n\n await t.test(\"with invalid object URI\", async () => {\n await bot.onFollowRejected(\n ctx,\n new Reject({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(\"https://example.com/\"),\n }),\n );\n assert.deepStrictEqual(rejected, []);\n });\n\n await t.test(\"with non-existent object\", async () => {\n await bot.onFollowRejected(\n ctx,\n new Reject({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(`https://example.com/ap/follow/${crypto.randomUUID()}`),\n }),\n );\n assert.deepStrictEqual(rejected, []);\n });\n\n await t.test(\"with non-actor\", async () => {\n await repository.addSentFollow(\n \"2ca58e2a-a34a-43e6-81af-c4f21ffed0c5\",\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/2ca58e2a-a34a-43e6-81af-c4f21ffed0c5\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new Note({}),\n }),\n );\n await bot.onFollowRejected(\n ctx,\n new Reject({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(\n \"https://example.com/ap/follow/2ca58e2a-a34a-43e6-81af-c4f21ffed0c5\",\n ),\n }),\n );\n assert.deepStrictEqual(rejected, []);\n });\n\n await t.test(\"with actor without URI\", async () => {\n await repository.addSentFollow(\n \"a99ff3bf-72a2-412b-83b9-cba894d38805\",\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/a99ff3bf-72a2-412b-83b9-cba894d38805\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new Person({\n preferredUsername: \"john\",\n }),\n }),\n );\n await bot.onFollowRejected(\n ctx,\n new Reject({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(\n \"https://example.com/ap/follow/a99ff3bf-72a2-412b-83b9-cba894d38805\",\n ),\n }),\n );\n assert.deepStrictEqual(rejected, []);\n });\n\n await t.test(\"with actor\", async () => {\n await repository.addSentFollow(\n \"3bca0b8e-503a-47ea-ad69-6b7c29369fbd\",\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/3bca0b8e-503a-47ea-ad69-6b7c29369fbd\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n }),\n );\n await bot.onFollowRejected(\n ctx,\n new Reject({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new URL(\n \"https://example.com/ap/follow/3bca0b8e-503a-47ea-ad69-6b7c29369fbd\",\n ),\n }),\n );\n assert.deepStrictEqual(rejected.length, 1);\n const [session, actor] = rejected[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.ok(actor instanceof Person);\n assert.deepStrictEqual(\n actor.id,\n new URL(\"https://example.com/ap/actor/john\"),\n );\n assert.deepStrictEqual(\n await repository.getSentFollow(\"3bca0b8e-503a-47ea-ad69-6b7c29369fbd\"),\n undefined,\n );\n });\n});\n\ntest(\"BotImpl.onCreated()\", async (t) => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n let replied: [Session<void>, Message<MessageClass, void>][] = [];\n bot.onReply = (session, msg) => void (replied.push([session, msg]));\n let mentioned: [Session<void>, Message<MessageClass, void>][] = [];\n bot.onMention = (session, msg) => void (mentioned.push([session, msg]));\n const ctx = createMockInboxContext(bot, \"https://example.com\", \"bot\");\n let messaged: [Session<void>, Message<MessageClass, void>][] = [];\n bot.onMessage = (session, msg) => void (messaged.push([session, msg]));\n\n await t.test(\"without object\", async () => {\n const createWithoutObject = new Create({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n });\n await bot.onCreated(ctx, createWithoutObject);\n assert.deepStrictEqual(replied, []);\n assert.deepStrictEqual(mentioned, []);\n assert.deepStrictEqual(messaged, []);\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n });\n\n await t.test(\"with non-message object\", async () => {\n const createWithNonMessageObject = new Create({\n actor: new URL(\"https://example.com/ap/actor/john\"),\n object: new Place({}),\n });\n await bot.onCreated(ctx, createWithNonMessageObject);\n assert.deepStrictEqual(replied, []);\n assert.deepStrictEqual(mentioned, []);\n assert.deepStrictEqual(messaged, []);\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n });\n\n await repository.addMessage(\n \"a6358f1b-c978-49d3-8065-37a1df6168de\",\n new Create({\n id: new URL(\n \"https://example.com/ap/create/a6358f1b-c978-49d3-8065-37a1df6168de\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new Note({\n id: new URL(\n \"https://example.com/ap/note/a6358f1b-c978-49d3-8065-37a1df6168de\",\n ),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n }),\n );\n\n await t.test(\"on reply\", async () => {\n const create = new Create({\n id: new URL(\n \"https://example.com/ap/create/9cfd7129-4cf0-4505-90d8-3cac2dc42434\",\n ),\n actor: new URL(\"https://example.com/ap/actor/john\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/john/followers\"),\n object: new Note({\n id: new URL(\n \"https://example.com/ap/note/9cfd7129-4cf0-4505-90d8-3cac2dc42434\",\n ),\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/john/followers\"),\n content: \"It's reply!\",\n replyTarget: new URL(\n \"https://example.com/ap/note/a6358f1b-c978-49d3-8065-37a1df6168de\",\n ),\n }),\n });\n await bot.onCreated(ctx, create);\n assert.deepStrictEqual(replied.length, 1);\n const [session, msg] = replied[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.ok(msg.raw instanceof Note);\n assert.deepStrictEqual(msg.raw.id, create.objectId);\n assert.ok(msg.replyTarget != null);\n assert.deepStrictEqual(\n msg.replyTarget.id,\n new URL(\n \"https://example.com/ap/note/a6358f1b-c978-49d3-8065-37a1df6168de\",\n ),\n );\n assert.deepStrictEqual(mentioned, []);\n assert.deepStrictEqual(messaged, replied);\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, [\"followers\"]);\n });\n\n await t.test(\"on mention\", async () => {\n replied = [];\n messaged = [];\n ctx.forwardedRecipients = [];\n\n const create = new Create({\n id: new URL(\n \"https://example.com/ap/create/9cfd7129-4cf0-4505-90d8-3cac2dc42434\",\n ),\n actor: new URL(\"https://example.com/ap/actor/john\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/john/followers\"),\n object: new Note({\n id: new URL(\n \"https://example.com/ap/note/9cfd7129-4cf0-4505-90d8-3cac2dc42434\",\n ),\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/john/followers\"),\n content:\n '<p><a href=\"https://example.com/ap/actor/bot\">@bot</a> Hey!</p>',\n tags: [\n new Mention({\n href: new URL(\"https://example.com/ap/actor/bot\"),\n name: \"@bot\",\n }),\n ],\n }),\n });\n await bot.onCreated(ctx, create);\n assert.deepStrictEqual(replied, []);\n assert.deepStrictEqual(mentioned.length, 1);\n const [session, msg] = mentioned[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.ok(msg.raw instanceof Note);\n assert.deepStrictEqual(msg.raw.id, create.objectId);\n assert.deepStrictEqual(msg.mentions.length, 1);\n assert.deepStrictEqual(\n msg.mentions[0].id,\n new URL(\"https://example.com/ap/actor/bot\"),\n );\n assert.deepStrictEqual(messaged, mentioned);\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n });\n\n await t.test(\"on quote\", async () => {\n mentioned = [];\n messaged = [];\n ctx.forwardedRecipients = [];\n\n const create = new Create({\n id: new URL(\n \"https://example.com/ap/create/9cfd7129-4cf0-4505-90d8-3cac2dc42434\",\n ),\n actor: new URL(\"https://example.com/ap/actor/john\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/john/followers\"),\n object: new Note({\n id: new URL(\n \"https://example.com/ap/note/9cfd7129-4cf0-4505-90d8-3cac2dc42434\",\n ),\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/john/followers\"),\n content: \"It's a quote!\",\n quoteUrl: new URL(\n \"https://example.com/ap/note/a6358f1b-c978-49d3-8065-37a1df6168de\",\n ),\n }),\n });\n let quoted: [Session<void>, Message<MessageClass, void>][] = [];\n bot.onQuote = (session, msg) => void (quoted.push([session, msg]));\n\n await bot.onCreated(ctx, create);\n\n assert.deepStrictEqual(quoted.length, 1);\n const [session, msg] = quoted[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.ok(msg.raw instanceof Note);\n assert.deepStrictEqual(msg.raw.id, create.objectId);\n assert.ok(msg.quoteTarget != null);\n assert.deepStrictEqual(\n msg.quoteTarget.id,\n new URL(\n \"https://example.com/ap/note/a6358f1b-c978-49d3-8065-37a1df6168de\",\n ),\n );\n assert.deepStrictEqual(replied, []);\n assert.deepStrictEqual(mentioned, []);\n assert.deepStrictEqual(messaged, quoted);\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, [\"followers\"]);\n\n quoted = [];\n messaged = [];\n ctx.forwardedRecipients = [];\n });\n\n await t.test(\"on message\", async () => {\n const create = new Create({\n id: new URL(\n \"https://example.com/ap/create/9cfd7129-4cf0-4505-90d8-3cac2dc42434\",\n ),\n actor: new URL(\"https://example.com/ap/actor/john\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/john/followers\"),\n object: new Note({\n id: new URL(\n \"https://example.com/ap/note/9cfd7129-4cf0-4505-90d8-3cac2dc42434\",\n ),\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/john/followers\"),\n content: \"<p>Hello!</p>\",\n }),\n });\n await bot.onCreated(ctx, create);\n assert.deepStrictEqual(replied, []);\n assert.deepStrictEqual(mentioned, []);\n assert.deepStrictEqual(messaged.length, 1);\n const [session, msg] = messaged[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.ok(msg.raw instanceof Note);\n assert.deepStrictEqual(msg.raw.id, create.objectId);\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n });\n\n messaged = [];\n});\n\ntest(\"BotImpl.onAnnounced()\", async () => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const shares: [Session<void>, SharedMessage<MessageClass, void>][] = [];\n bot.onSharedMessage = (session, sharedMessage) =>\n void (shares.push([session, sharedMessage]));\n const ctx = createMockInboxContext(bot, \"https://example.com\", \"bot\");\n const announce = new Announce({\n id: new URL(\"https://example.com/ap/actor/bot/announce/1\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n });\n await bot.onAnnounced(ctx, announce);\n assert.deepStrictEqual(shares.length, 1);\n const [session, sharedMessage] = shares[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.deepStrictEqual(sharedMessage.raw, announce);\n assert.deepStrictEqual(sharedMessage.id, announce.id);\n assert.deepStrictEqual(sharedMessage.actor.id, announce.actorId);\n assert.deepStrictEqual(sharedMessage.visibility, \"public\");\n assert.deepStrictEqual(sharedMessage.original.id, announce.objectId);\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n});\n\ntest(\"BotImpl.onLiked()\", async () => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const likes: [Session<void>, Like<void>][] = [];\n bot.onLike = (session, like) => void (likes.push([session, like]));\n const ctx = createMockInboxContext(bot, \"https://example.com\", \"bot\");\n const rawLike = new RawLike({\n id: new URL(\"https://example.com/ap/actor/bot/like/1\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n });\n await bot.onLiked(ctx, rawLike);\n assert.deepStrictEqual(likes.length, 1);\n const [session, like] = likes[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.deepStrictEqual(like.raw, rawLike);\n assert.deepStrictEqual(like.id, rawLike.id);\n assert.deepStrictEqual(like.actor.id, rawLike.actorId);\n assert.deepStrictEqual(like.message.id, rawLike.objectId);\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n});\n\ntest(\"BotImpl.onUnliked()\", async () => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const likes: [Session<void>, Like<void>][] = [];\n bot.onUnlike = (session, like) => void (likes.push([session, like]));\n const ctx = createMockInboxContext(bot, \"https://example.com\", \"bot\");\n const rawLike = new RawLike({\n id: new URL(\"https://example.com/ap/actor/bot/like/1\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n });\n const undo = new Undo({\n id: new URL(\"https://example.com/ap/actor/bot/unlike/1\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: rawLike,\n });\n await bot.onUnliked(ctx, undo);\n assert.deepStrictEqual(likes.length, 1);\n const [session, like] = likes[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.deepStrictEqual(like.raw, rawLike);\n assert.deepStrictEqual(like.id, rawLike.id);\n assert.deepStrictEqual(like.actor.id, rawLike.actorId);\n assert.deepStrictEqual(like.message.id, rawLike.objectId);\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n\n likes.pop();\n const invalidUndo = undo.clone({\n actor: new URL(\"https://example.com/ap/actor/another\"),\n });\n await bot.onUnliked(ctx, invalidUndo);\n assert.deepStrictEqual(likes, []);\n});\n\ntest(\"BotImpl.onReacted()\", async () => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const reactions: [Session<void>, Reaction<void>][] = [];\n bot.onReact = (session, reaction) =>\n void (reactions.push([session, reaction]));\n const ctx = createMockInboxContext(bot, \"https://example.com\", \"bot\");\n\n // Test with Like containing an emoji name\n const rawLike = new RawLike({\n id: new URL(\"https://example.com/ap/actor/bot/like/1\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n name: \":heart:\",\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n tags: [\n new Emoji({\n id: new URL(\"https://example.com/ap/emoji/heart\"),\n name: \":heart:\",\n icon: new Image({\n mediaType: \"image/png\",\n url: new URL(\"https://example.com/emoji/heart.png\"),\n }),\n }),\n ],\n });\n\n await bot.onReacted(ctx, rawLike);\n assert.deepStrictEqual(reactions.length, 1);\n const [session, reaction] = reactions[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.deepStrictEqual(reaction.raw, rawLike);\n assert.deepStrictEqual(reaction.id, rawLike.id);\n assert.deepStrictEqual(reaction.actor.id, rawLike.actorId);\n assert.deepStrictEqual(reaction.message.id, rawLike.objectId);\n assert.ok(reaction.emoji instanceof Emoji);\n assert.deepStrictEqual(reaction.emoji.name, \":heart:\");\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n\n // Test with EmojiReact\n reactions.pop();\n const emojiReact = new EmojiReact({\n id: new URL(\"https://example.com/ap/actor/bot/react/1\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n name: \":thumbsup:\",\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n tags: [\n new Emoji({\n id: new URL(\"https://example.com/ap/emoji/thumbsup\"),\n name: \":thumbsup:\",\n icon: new Image({\n mediaType: \"image/png\",\n url: new URL(\"https://example.com/emoji/thumbsup.png\"),\n }),\n }),\n ],\n });\n\n await bot.onReacted(ctx, emojiReact);\n assert.deepStrictEqual(reactions.length, 1);\n const [session2, reaction2] = reactions[0];\n assert.deepStrictEqual(session2.bot, bot);\n assert.deepStrictEqual(session2.context, ctx);\n assert.deepStrictEqual(reaction2.raw, emojiReact);\n assert.deepStrictEqual(reaction2.id, emojiReact.id);\n assert.deepStrictEqual(reaction2.actor.id, emojiReact.actorId);\n assert.deepStrictEqual(reaction2.message.id, emojiReact.objectId);\n assert.ok(reaction2.emoji instanceof Emoji);\n assert.deepStrictEqual(reaction2.emoji.name, \":thumbsup:\");\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n});\n\ntest(\"BotImpl.onUnreacted()\", async () => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const reactions: [Session<void>, Reaction<void>][] = [];\n bot.onUnreact = (session, reaction) =>\n void (reactions.push([session, reaction]));\n const ctx = createMockInboxContext(bot, \"https://example.com\", \"bot\");\n\n // Test with Like containing an emoji name\n const rawLike = new RawLike({\n id: new URL(\"https://example.com/ap/actor/bot/like/1\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n name: \":heart:\",\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n tags: [\n new Emoji({\n id: new URL(\"https://example.com/ap/emoji/heart\"),\n name: \":heart:\",\n icon: new Image({\n mediaType: \"image/png\",\n url: new URL(\"https://example.com/emoji/heart.png\"),\n }),\n }),\n ],\n });\n\n const undo = new Undo({\n id: new URL(\"https://example.com/ap/actor/bot/unreact/1\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: rawLike,\n });\n\n await bot.onUnreacted(ctx, undo);\n assert.deepStrictEqual(reactions.length, 1);\n const [session, reaction] = reactions[0];\n assert.deepStrictEqual(session.bot, bot);\n assert.deepStrictEqual(session.context, ctx);\n assert.deepStrictEqual(reaction.raw, rawLike);\n assert.deepStrictEqual(reaction.id, rawLike.id);\n assert.deepStrictEqual(reaction.actor.id, rawLike.actorId);\n assert.deepStrictEqual(reaction.message.id, rawLike.objectId);\n assert.ok(reaction.emoji instanceof Emoji);\n assert.deepStrictEqual(reaction.emoji.name, \":heart:\");\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n\n // Test with EmojiReact\n reactions.pop();\n const emojiReact = new EmojiReact({\n id: new URL(\"https://example.com/ap/actor/bot/react/1\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n name: \":thumbsup:\",\n object: new Note({\n id: new URL(\"https://example.com/ap/actor/bot/note/1\"),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n content: \"Hello, world!\",\n }),\n tags: [\n new Emoji({\n id: new URL(\"https://example.com/ap/emoji/thumbsup\"),\n name: \":thumbsup:\",\n icon: new Image({\n mediaType: \"image/png\",\n url: new URL(\"https://example.com/emoji/thumbsup.png\"),\n }),\n }),\n ],\n });\n\n const undoEmojiReact = new Undo({\n id: new URL(\"https://example.com/ap/actor/bot/unreact/2\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: emojiReact,\n });\n\n await bot.onUnreacted(ctx, undoEmojiReact);\n assert.deepStrictEqual(reactions.length, 1);\n const [session2, reaction2] = reactions[0];\n assert.deepStrictEqual(session2.bot, bot);\n assert.deepStrictEqual(session2.context, ctx);\n assert.deepStrictEqual(reaction2.raw, emojiReact);\n assert.deepStrictEqual(reaction2.id, emojiReact.id);\n assert.deepStrictEqual(reaction2.actor.id, emojiReact.actorId);\n assert.deepStrictEqual(reaction2.message.id, emojiReact.objectId);\n assert.ok(reaction2.emoji instanceof Emoji);\n assert.deepStrictEqual(reaction2.emoji.name, \":thumbsup:\");\n assert.deepStrictEqual(ctx.sentActivities, []);\n assert.deepStrictEqual(ctx.forwardedRecipients, []);\n\n // Test with mismatched actor\n reactions.pop();\n const invalidUndo = undoEmojiReact.clone({\n actor: new URL(\"https://example.com/ap/actor/another\"),\n });\n await bot.onUnreacted(ctx, invalidUndo);\n assert.deepStrictEqual(reactions, []);\n\n // Test with non-reaction object\n reactions.pop();\n const nonReactionUndo = new Undo({\n id: new URL(\"https://example.com/ap/actor/bot/unreact/3\"),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new Note({}),\n });\n await bot.onUnreacted(ctx, nonReactionUndo);\n assert.deepStrictEqual(reactions, []);\n});\n\ntest(\"BotImpl.dispatchNodeInfo()\", () => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n software: {\n name: \"test\",\n version: parseSemVer(\"1.2.3\"),\n homepage: new URL(\"https://example.com/\"),\n repository: new URL(\"https://git.example.com/\"),\n },\n });\n const ctx = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n assert.deepStrictEqual(bot.dispatchNodeInfo(ctx), {\n software: {\n name: \"test\",\n version: parseSemVer(\"1.2.3\"),\n homepage: new URL(\"https://example.com/\"),\n repository: new URL(\"https://git.example.com/\"),\n },\n protocols: [\"activitypub\"],\n services: {\n outbound: [\"atom1.0\"],\n },\n usage: {\n users: {\n total: 1,\n activeMonth: 1,\n activeHalfyear: 1,\n },\n localPosts: 0,\n localComments: 0,\n },\n });\n});\n\ntest(\"BotImpl.fetch()\", async () => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const request = new Request(\n \"http://localhost/.well-known/webfinger?resource=acct:bot@example.com\",\n {\n headers: {\n \"X-Forwarded-Host\": \"example.com\",\n \"X-Forwarded-Proto\": \"https\",\n },\n },\n );\n const response = await bot.fetch(request);\n assert.deepStrictEqual(response.status, 404);\n\n const botBehindProxy = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n behindProxy: true,\n });\n const response2 = await botBehindProxy.fetch(request);\n assert.deepStrictEqual(response2.status, 200);\n});\n\ndescribe(\"BotImpl.addCustomEmoji(), BotImpl.addCustomEmojis()\", () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n\n test(\"addCustomEmoji()\", () => {\n const emojiData: CustomEmoji = {\n type: \"image/png\",\n url: \"https://example.com/emoji.png\",\n };\n const deferredEmoji = bot.addCustomEmoji(\"testEmoji\", emojiData);\n assert.deepStrictEqual(typeof deferredEmoji, \"function\");\n assert.deepStrictEqual(bot.customEmojis[\"testEmoji\"], emojiData);\n\n // Test invalid name\n assert.throws(\n () => bot.addCustomEmoji(\"invalid name\", emojiData),\n TypeError,\n \"Invalid custom emoji name\",\n );\n\n // Test duplicate name\n assert.throws(\n () => bot.addCustomEmoji(\"testEmoji\", emojiData),\n TypeError,\n \"Duplicate custom emoji name\",\n );\n\n // Test unsupported media type\n assert.throws(\n () =>\n bot.addCustomEmoji(\"invalidType\", {\n // @ts-expect-error: Intended type error for testing runtime check\n type: \"text/plain\",\n url: \"https://example.com/emoji.txt\",\n }),\n TypeError,\n \"Unsupported media type\",\n );\n });\n\n test(\"addCustomEmojis()\", () => {\n const emojisData = {\n emoji1: { type: \"image/png\", url: \"https://example.com/emoji1.png\" },\n emoji2: { type: \"image/gif\", file: \"/path/to/emoji2.gif\" },\n } as const;\n const deferredEmojis = bot.addCustomEmojis(emojisData);\n\n assert.deepStrictEqual(typeof deferredEmojis[\"emoji1\"], \"function\");\n assert.deepStrictEqual(typeof deferredEmojis[\"emoji2\"], \"function\");\n assert.deepStrictEqual(bot.customEmojis[\"emoji1\"], emojisData.emoji1);\n assert.deepStrictEqual(bot.customEmojis[\"emoji2\"], emojisData.emoji2);\n\n // Test duplicate name within the batch\n assert.throws(\n () =>\n bot.addCustomEmojis({\n emoji1: { type: \"image/png\", url: \"https://example.com/dup1.png\" },\n }),\n TypeError,\n \"Duplicate custom emoji name: emoji1\",\n );\n });\n});\n\ntest(\"BotImpl.getEmoji()\", async () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n const ctx = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n\n // Test with remote URL\n const remoteEmojiData: CustomEmoji = {\n type: \"image/png\",\n url: \"https://remote.com/emoji.png\",\n };\n bot.customEmojis[\"remoteEmoji\"] = remoteEmojiData;\n const remoteEmoji = bot.getEmoji(ctx, \"remoteEmoji\", remoteEmojiData);\n assert.ok(remoteEmoji instanceof Emoji);\n assert.deepStrictEqual(\n remoteEmoji.id,\n new URL(\"https://example.com/ap/emoji/remoteEmoji\"),\n );\n assert.deepStrictEqual(remoteEmoji.name, \":remoteEmoji:\");\n const icon = await remoteEmoji.getIcon();\n assert.ok(icon instanceof Image);\n assert.deepStrictEqual(icon.mediaType, \"image/png\");\n assert.deepStrictEqual(icon.url?.href, \"https://remote.com/emoji.png\");\n\n // Test with local file\n const localEmojiData: CustomEmoji = {\n type: \"image/gif\",\n file: \"/path/to/local/emoji.gif\",\n };\n bot.customEmojis[\"localEmoji\"] = localEmojiData;\n const localEmoji = bot.getEmoji(ctx, \"localEmoji\", localEmojiData);\n assert.ok(localEmoji instanceof Emoji);\n assert.deepStrictEqual(\n localEmoji.id,\n new URL(\"https://example.com/ap/emoji/localEmoji\"),\n );\n assert.deepStrictEqual(localEmoji.name, \":localEmoji:\");\n const icon2 = await localEmoji.getIcon();\n assert.ok(icon2 instanceof Image);\n assert.deepStrictEqual(icon2.mediaType, \"image/gif\");\n assert.deepStrictEqual(\n icon2.url?.href,\n \"https://example.com/emojis/localEmoji.gif\",\n );\n\n // Test with local file without extension mapping\n const localEmojiDataNoExt: CustomEmoji = {\n type: \"image/webp\",\n file: \"/path/to/local/emoji\",\n };\n bot.customEmojis[\"localEmojiNoExt\"] = localEmojiDataNoExt;\n const localEmojiNoExt = bot.getEmoji(\n ctx,\n \"localEmojiNoExt\",\n localEmojiDataNoExt,\n );\n const icon3 = await localEmojiNoExt.getIcon();\n assert.ok(icon3 instanceof Image);\n assert.deepStrictEqual(icon3.mediaType, \"image/webp\");\n assert.deepStrictEqual(\n icon3.url?.href,\n \"https://example.com/emojis/localEmojiNoExt.webp\",\n );\n});\n\n// Test BotImpl.dispatchEmoji()\ntest(\"BotImpl.dispatchEmoji()\", () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n const ctx = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n const emojiData: CustomEmoji = {\n type: \"image/png\",\n url: \"https://example.com/emoji.png\",\n };\n bot.customEmojis[\"testEmoji\"] = emojiData;\n\n // Test dispatching an existing emoji\n const emoji = bot.dispatchEmoji(ctx, { name: \"testEmoji\" });\n assert.ok(emoji instanceof Emoji);\n assert.deepStrictEqual(\n emoji.id,\n new URL(\"https://example.com/ap/emoji/testEmoji\"),\n );\n assert.deepStrictEqual(emoji.name, \":testEmoji:\");\n\n // Test dispatching a non-existent emoji\n const nonExistent = bot.dispatchEmoji(ctx, { name: \"nonExistent\" });\n assert.deepStrictEqual(nonExistent, null);\n});\n\ntest(\"BotImpl.getFollowersFirstCursor()\", () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n const ctx = bot.federation.createContext(\n new URL(\"https://example.com\"),\n undefined,\n );\n assert.deepStrictEqual(\n bot.getFollowersFirstCursor(ctx, \"non-existent\"),\n null,\n );\n assert.deepStrictEqual(bot.getFollowersFirstCursor(ctx, \"bot\"), \"0\");\n});\n\ninterface SentActivity {\n recipients: \"followers\" | Recipient[];\n activity: Activity;\n}\n\ninterface MockInboxContext extends InboxContext<void> {\n sentActivities: SentActivity[];\n forwardedRecipients: (\"followers\" | Recipient)[];\n}\n\nfunction createMockInboxContext(\n bot: BotImpl<void>,\n origin: string | URL,\n recipient?: string | null,\n): MockInboxContext {\n const ctx = bot.federation.createContext(\n new URL(origin),\n undefined,\n ) as MockInboxContext;\n ctx.recipient = recipient ?? null;\n ctx.sentActivities = [];\n ctx.sendActivity = (_, recipients, activity) => {\n ctx.sentActivities.push({\n recipients: recipients === \"followers\"\n ? \"followers\"\n : Array.isArray(recipients)\n ? recipients\n : [recipients],\n activity,\n });\n return Promise.resolve();\n };\n ctx.forwardedRecipients = [];\n ctx.forwardActivity = (_, recipients) => {\n if (recipients === \"followers\") {\n ctx.forwardedRecipients.push(\"followers\");\n } else if (Array.isArray(recipients)) {\n ctx.forwardedRecipients.push(...recipients);\n } else {\n ctx.forwardedRecipients.push(recipients);\n }\n return Promise.resolve();\n };\n return ctx;\n}\n\n// cSpell: ignore thumbsup\n"],"mappings":"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"}
package/dist/bot.d.ts ADDED
@@ -0,0 +1,270 @@
1
+ import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
2
+ Date.prototype.toTemporalInstant = toTemporalInstant;
3
+ import { Text } from "./text.js";
4
+ import { Repository } from "./repository.js";
5
+ import { Session } from "./session.js";
6
+ import { CustomEmoji, DeferredCustomEmoji } from "./emoji.js";
7
+ import { AcceptEventHandler, FollowEventHandler, LikeEventHandler, MentionEventHandler, MessageEventHandler, QuoteEventHandler, ReactionEventHandler, RejectEventHandler, ReplyEventHandler, SharedMessageEventHandler, UndoneReactionEventHandler, UnfollowEventHandler, UnlikeEventHandler } from "./events.js";
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";
11
+
12
+ //#region src/bot.d.ts
13
+ /**
14
+ * A bot that can interact with the ActivityPub network.
15
+ */
16
+ interface Bot<TContextData> {
17
+ /**
18
+ * An internal Fedify federation instance. Normally you don't need to access
19
+ * this directly.
20
+ */
21
+ readonly federation: Federation<TContextData>;
22
+ /**
23
+ * The internal identifier for the bot actor. It is used for the actor URI.
24
+ */
25
+ readonly identifier: string;
26
+ /**
27
+ * Gets a new session to control the bot for a specific origin and context
28
+ * data.
29
+ * @param origin The origin of the session. Even if a URL with some path or
30
+ * query is passed, only the origin part will be used.
31
+ * @param contextData The context data to pass to the federation.
32
+ * @returns The session for the origin and context data.
33
+ */
34
+ getSession(origin: string | URL, contextData: TContextData): Session<TContextData>;
35
+ /**
36
+ * Gets a new session to control bot for a specific Fedify context.
37
+ * @param context The Fedify context of the session.
38
+ * @returns The session for the Fedify context.
39
+ */
40
+ getSession(context: Context<TContextData>): Session<TContextData>;
41
+ /**
42
+ * The fetch API for handling HTTP requests. You can pass this to an HTTP
43
+ * server (e.g., `Deno.serve()`, `Bun.serve()`) to handle incoming requests.
44
+ * @param request The request to handle.
45
+ * @param contextData The context data to pass to the federation.
46
+ * @returns The response to the request.
47
+ */
48
+ fetch(request: Request, contextData: TContextData): Promise<Response>;
49
+ /**
50
+ * Defines custom emojis for the bot. The custom emojis are used for
51
+ * rendering the bot's profile and posts. The custom emojis are defined
52
+ * by their names, and the names are used as the keys of the emojis.
53
+ * @param emojis The custom emojis to define. The keys are the names of
54
+ * the emojis, and the values are the custom emoji definitions.
55
+ * @returns The defined emojis. The keys are the names of the emojis, and
56
+ * the values are the emoji objects, which are used for passing
57
+ * to the {@link customEmoji} function.
58
+ * @throws {TypeError} If any emoji name is invalid or duplicate.
59
+ * @since 0.2.0
60
+ */
61
+ addCustomEmojis<TEmojiName extends string>(emojis: Readonly<Record<TEmojiName, CustomEmoji>>): Readonly<Record<TEmojiName, DeferredCustomEmoji<TContextData>>>;
62
+ /**
63
+ * An event handler for a follow request to the bot.
64
+ */
65
+ onFollow?: FollowEventHandler<TContextData>;
66
+ /**
67
+ * An event handler for an unfollow event from the bot.
68
+ */
69
+ onUnfollow?: UnfollowEventHandler<TContextData>;
70
+ /**
71
+ * An event handler invoked when a follow request the bot sent is accepted.
72
+ */
73
+ onAcceptFollow?: AcceptEventHandler<TContextData>;
74
+ /**
75
+ * An event handler invoked when a follow request the bot sent is rejected.
76
+ */
77
+ onRejectFollow?: RejectEventHandler<TContextData>;
78
+ /**
79
+ * An event handler for a message mentioned to the bot.
80
+ */
81
+ onMention?: MentionEventHandler<TContextData>;
82
+ /**
83
+ * An event handler for a reply to the bot.
84
+ */
85
+ onReply?: ReplyEventHandler<TContextData>;
86
+ /**
87
+ * An event handler for a quote of the bot's message.
88
+ * @since 0.2.0
89
+ */
90
+ onQuote?: QuoteEventHandler<TContextData>;
91
+ /**
92
+ * An event handler for a message shown to the bot's timeline. To listen
93
+ * to this event, your bot needs to follow others first.
94
+ */
95
+ onMessage?: MessageEventHandler<TContextData>;
96
+ /**
97
+ * An event handler for a message shared to the bot. To listen to this event,
98
+ * your bot needs to follow others first.
99
+ */
100
+ onSharedMessage?: SharedMessageEventHandler<TContextData>;
101
+ /**
102
+ * An event handler for a like of a message.
103
+ */
104
+ onLike?: LikeEventHandler<TContextData>;
105
+ /**
106
+ * An event handler for an undoing of a like of a message.
107
+ */
108
+ onUnlike?: UnlikeEventHandler<TContextData>;
109
+ /**
110
+ * An event handler for an emoji reaction to a message.
111
+ * @since 0.2.0
112
+ */
113
+ onReact?: ReactionEventHandler<TContextData>;
114
+ /**
115
+ * An event handler for an undoing of an emoji reaction to a message.
116
+ * @since 0.2.0
117
+ */
118
+ onUnreact?: UndoneReactionEventHandler<TContextData>;
119
+ }
120
+ /**
121
+ * A specialized {@link Bot} tpe that doesn't require context data.
122
+ */
123
+ interface BotWithVoidContextData extends Bot<void> {
124
+ /**
125
+ * Gets a new session to control the bot for a specific origin and context
126
+ * data.
127
+ * @param origin The origin of the session. Even if a URL with some path or
128
+ * query is passed, only the origin part will be used.
129
+ * @param contextData The context data to pass to the federation.
130
+ * @returns The session for the origin and context data.
131
+ */
132
+ getSession(origin: string | URL, contextData: void): Session<void>;
133
+ /**
134
+ * Gets a new session to control bot for a specific Fedify context.
135
+ * @param context The Fedify context of the session.
136
+ * @returns The session for the Fedify context.
137
+ */
138
+ getSession(context: Context<void>): Session<void>;
139
+ /**
140
+ * Gets a new session to control the bot for a specific origin and context
141
+ * data.
142
+ * @param origin The origin of the session. Even if a URL with some path or
143
+ * query is passed, only the origin part will be used.
144
+ */
145
+ getSession(origin: string | URL): Session<void>;
146
+ /**
147
+ * The fetch API for handling HTTP requests. You can pass this to an HTTP
148
+ * server (e.g., `Deno.serve()`, `Bun.serve()`) to handle incoming requests.
149
+ * @param request The request to handle.
150
+ * @returns The response to the request.
151
+ */
152
+ fetch(request: Request): Promise<Response>;
153
+ }
154
+ /**
155
+ * Options for creating a bot.
156
+ */
157
+ interface CreateBotOptions<TContextData> {
158
+ /**
159
+ * The internal identifier of the bot. Since it is used for the actor URI,
160
+ * it *should not* be changed after the bot is federated.
161
+ *
162
+ * If omitted, `"bot"` will be used.
163
+ * @default `"bot"`
164
+ */
165
+ readonly identifier?: string;
166
+ /**
167
+ * The type of the bot actor. It should be either `Service` or `Application`.
168
+ *
169
+ * If omitted, `Service` will be used.
170
+ * @default `Service`
171
+ */
172
+ readonly class?: typeof Service$1 | typeof Application$1;
173
+ /**
174
+ * The username of the bot. It will be a part of the fediverse handle.
175
+ * It can be changed after the bot is federated.
176
+ */
177
+ readonly username: string;
178
+ /**
179
+ * The display name of the bot. It can be changed after the bot is federated.
180
+ */
181
+ readonly name?: string;
182
+ /**
183
+ * The description of the bot. It can be changed after the bot is federated.
184
+ */
185
+ readonly summary?: Text<"block", TContextData>;
186
+ /**
187
+ * The avatar URL of the bot. It can be changed after the bot is federated.
188
+ */
189
+ readonly icon?: URL | Image$1;
190
+ /**
191
+ * The header image URL of the bot. It can be changed after the bot is
192
+ * federated.
193
+ */
194
+ readonly image?: URL | Image$1;
195
+ /**
196
+ * The custom properties of the bot. It can be changed after the bot is
197
+ * federated.
198
+ */
199
+ readonly properties?: Record<string, Text<"block" | "inline", TContextData>>;
200
+ /**
201
+ * How to handle incoming follow requests. Note that this behavior can be
202
+ * overridden by manually invoking {@link FollowRequest.accept} or
203
+ * {@link FollowRequest.reject} in the {@link Bot.onFollow} event handler.
204
+ *
205
+ * - `"accept"` (default): Automatically accept all incoming follow requests.
206
+ * - `"reject"`: Automatically reject all incoming follow requests.
207
+ * - `"manual"`: Require manual handling of incoming follow requests.
208
+ * @default `"accept"`
209
+ */
210
+ readonly followerPolicy?: "accept" | "reject" | "manual";
211
+ /**
212
+ * The underlying key-value store to use for storing data.
213
+ */
214
+ readonly kv: KvStore;
215
+ /**
216
+ * The underlying repository to use for storing data. If omitted,
217
+ * {@link KvRepository} will be used.
218
+ */
219
+ readonly repository?: Repository;
220
+ /**
221
+ * The underlying message queue to use for handling incoming and outgoing
222
+ * activities. If omitted, incoming activities are processed immediately,
223
+ * and outgoing activities are sent immediately.
224
+ */
225
+ readonly queue?: MessageQueue;
226
+ /**
227
+ * The software information of the bot. If omitted, the NodeInfo protocol
228
+ * will be unimplemented.
229
+ */
230
+ readonly software?: Software$1;
231
+ /**
232
+ * Whether to trust `X-Forwarded-*` headers. If your bot application is
233
+ * behind an L7 reverse proxy, turn it on.
234
+ *
235
+ * Turned off by default.
236
+ * @default `false`
237
+ */
238
+ readonly behindProxy?: boolean;
239
+ /**
240
+ * The options for the web pages of the bot. If omitted, the default options
241
+ * will be used.
242
+ */
243
+ readonly pages?: PagesOptions;
244
+ }
245
+ /**
246
+ * Options for the web pages of the bot.
247
+ */
248
+ interface PagesOptions {
249
+ /**
250
+ * The color of the theme. It will be used for the theme color of the web
251
+ * pages. The default color is `"green"`.
252
+ * @default `"green"`
253
+ */
254
+ readonly color?: "amber" | "azure" | "blue" | "cyan" | "fuchsia" | "green" | "grey" | "indigo" | "jade" | "lime" | "orange" | "pink" | "pumpkin" | "purple" | "red" | "sand" | "slate" | "violet" | "yellow" | "zinc";
255
+ /**
256
+ * The CSS code for the bot. It will be used for the custom CSS of the web
257
+ * pages.
258
+ */
259
+ readonly css?: string;
260
+ }
261
+ /**
262
+ * Creates a {@link Bot} instance.
263
+ * @param options The options for creating the bot.
264
+ * @returns The created bot instance.
265
+ */
266
+ declare function createBot<TContextData = void>(options: CreateBotOptions<TContextData>): TContextData extends void ? BotWithVoidContextData : Bot<TContextData>;
267
+ //# sourceMappingURL=bot.d.ts.map
268
+ //#endregion
269
+ export { Application, Bot, BotWithVoidContextData, CreateBotOptions, Image, PagesOptions, SemVer, Service, Software, createBot, parseSemVer };
270
+ //# sourceMappingURL=bot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.d.ts","names":[],"sources":["../src/bot.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;UAqDiB;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;;AAMQ;EAMvB,UAAA,CAAA,EAlEF,oBAkEyB,CAlEJ,YAkEI,CAAA;EAAA;;;EAY5B,cAOU,CAAA,EAhFH,kBAgFG,CAhFgB,YAgFhB,CAAA;EAAO;;;EAQc,cAQ1B,CAAA,EA3FE,kBA2FF,CA3FqB,YA2FrB,CAAA;EAAO;;;EAnC2B,SAAA,CAAA,EAnDrC,mBAmDqC,CAnDjB,YAmDiB,CAAA;EAyClC;;;EAgBgB,OAAU,CAAA,EAvG/B,iBAuG+B,CAvGb,YAuGa,CAAA;EAAW;;;;EAqBzB,OAMV,CAAA,EA5HP,iBA4HO,CA5HW,YA4HX,CAAA;EAAG;;;;EAMQ,SAiBf,CAAA,EA7ID,mBA6IC,CA7ImB,YA6InB,CAAA;EAAO;;;;EAkCS,eAAA,CAAA,EAzKX,yBAyKW,CAzKe,YAyKf,CAAA;EAMd;AAwCjB;;EAAyB,MACG,CAAA,EAnNjB,gBAmNiB,CAnNA,YAmNA,CAAA;EAAY;;;EACa,QAAO,CAAA,EA/M/C,kBA+M+C,CA/M5B,YA+M4B,CAAA;EAAY;AAAb;;;YAzM/C,qBAAqB;;;;;cAMnB,2BAA2B;;;;;UAMxB,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"}