@fedify/botkit 0.5.0-dev.209 → 0.5.0-dev.225

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 (85) hide show
  1. package/dist/bot-group.test.d.ts +2 -0
  2. package/dist/bot-group.test.js +220 -0
  3. package/dist/bot-group.test.js.map +1 -0
  4. package/dist/bot-impl.d.ts +132 -13
  5. package/dist/bot-impl.d.ts.map +1 -1
  6. package/dist/bot-impl.js +400 -178
  7. package/dist/bot-impl.js.map +1 -1
  8. package/dist/bot-impl.test.js +214 -76
  9. package/dist/bot-impl.test.js.map +1 -1
  10. package/dist/bot.d.ts +94 -48
  11. package/dist/bot.d.ts.map +1 -1
  12. package/dist/bot.js +2 -104
  13. package/dist/bot.js.map +1 -1
  14. package/dist/bot.test.js +59 -0
  15. package/dist/bot.test.js.map +1 -1
  16. package/dist/components/FollowButton.d.ts +5 -3
  17. package/dist/components/FollowButton.d.ts.map +1 -1
  18. package/dist/components/FollowButton.js +2 -2
  19. package/dist/components/FollowButton.js.map +1 -1
  20. package/dist/components/Follower.d.ts +2 -2
  21. package/dist/components/Layout.js +1 -1
  22. package/dist/components/Layout.js.map +1 -1
  23. package/dist/components/Message.d.ts +2 -2
  24. package/dist/deno.js +2 -1
  25. package/dist/deno.js.map +1 -1
  26. package/dist/follow-impl.test.js +3 -3
  27. package/dist/follow-impl.test.js.map +1 -1
  28. package/dist/instance-impl.d.ts +158 -0
  29. package/dist/instance-impl.d.ts.map +1 -0
  30. package/dist/instance-impl.js +603 -0
  31. package/dist/instance-impl.js.map +1 -0
  32. package/dist/instance-impl.test.d.ts +2 -0
  33. package/dist/instance-impl.test.js +103 -0
  34. package/dist/instance-impl.test.js.map +1 -0
  35. package/dist/instance-multi.test.d.ts +2 -0
  36. package/dist/instance-multi.test.js +151 -0
  37. package/dist/instance-multi.test.js.map +1 -0
  38. package/dist/instance-routing.test.d.ts +2 -0
  39. package/dist/instance-routing.test.js +367 -0
  40. package/dist/instance-routing.test.js.map +1 -0
  41. package/dist/instance.d.ts +318 -0
  42. package/dist/instance.d.ts.map +1 -0
  43. package/dist/instance.js +51 -0
  44. package/dist/instance.js.map +1 -0
  45. package/dist/message-impl.d.ts.map +1 -1
  46. package/dist/message-impl.js +17 -10
  47. package/dist/message-impl.js.map +1 -1
  48. package/dist/message-impl.test.js +43 -9
  49. package/dist/message-impl.test.js.map +1 -1
  50. package/dist/mod.d.ts +5 -3
  51. package/dist/mod.js +4 -2
  52. package/dist/pages.d.ts +10 -1
  53. package/dist/pages.d.ts.map +1 -1
  54. package/dist/pages.js +112 -41
  55. package/dist/pages.js.map +1 -1
  56. package/dist/pages.test.d.ts +2 -0
  57. package/dist/pages.test.js +170 -0
  58. package/dist/pages.test.js.map +1 -0
  59. package/dist/repository.d.ts +385 -138
  60. package/dist/repository.d.ts.map +1 -1
  61. package/dist/repository.js +595 -223
  62. package/dist/repository.js.map +1 -1
  63. package/dist/repository.test.js +564 -136
  64. package/dist/repository.test.js.map +1 -1
  65. package/dist/session-impl.d.ts.map +1 -1
  66. package/dist/session-impl.js +13 -4
  67. package/dist/session-impl.js.map +1 -1
  68. package/dist/session-impl.test.d.ts.map +1 -1
  69. package/dist/session-impl.test.js +9 -9
  70. package/dist/session-impl.test.js.map +1 -1
  71. package/dist/session.d.ts +8 -3
  72. package/dist/session.d.ts.map +1 -1
  73. package/dist/text.d.ts.map +1 -1
  74. package/dist/text.js +27 -10
  75. package/dist/text.js.map +1 -1
  76. package/dist/text.test.js +37 -2
  77. package/dist/text.test.js.map +1 -1
  78. package/dist/uri.d.ts +46 -0
  79. package/dist/uri.d.ts.map +1 -0
  80. package/dist/uri.js +64 -0
  81. package/dist/uri.js.map +1 -0
  82. package/dist/uri.test.d.ts +2 -0
  83. package/dist/uri.test.js +93 -0
  84. package/dist/uri.test.js.map +1 -0
  85. package/package.json +5 -1
package/dist/deno.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"deno.js","names":[],"sources":["../deno.json"],"sourcesContent":["{\n \"name\": \"@fedify/botkit\",\n \"version\": \"0.5.0-dev.209+7759c808\",\n \"license\": \"AGPL-3.0-only\",\n \"exports\": {\n \".\": \"./src/mod.ts\",\n \"./bot\": \"./src/bot.ts\",\n \"./emoji\": \"./src/emoji.ts\",\n \"./events\": \"./src/events.ts\",\n \"./follow\": \"./src/follow.ts\",\n \"./message\": \"./src/message.ts\",\n \"./poll\": \"./src/poll.ts\",\n \"./reaction\": \"./src/reaction.ts\",\n \"./repository\": \"./src/repository.ts\",\n \"./session\": \"./src/session.ts\",\n \"./text\": \"./src/text.ts\"\n },\n \"imports\": {\n \"@fedify/vocab\": \"jsr:@fedify/vocab@^2.1.2\",\n \"@fedify/vocab-runtime\": \"jsr:@fedify/vocab-runtime@^2.1.2\",\n \"@fedify/markdown-it-hashtag\": \"jsr:@fedify/markdown-it-hashtag@^0.3.0\",\n \"@fedify/markdown-it-mention\": \"jsr:@fedify/markdown-it-mention@^0.3.0\",\n \"html-entities\": \"npm:html-entities@^2.6.0\",\n \"markdown-it\": \"npm:markdown-it@^14.1.0\",\n \"mime-db\": \"npm:mime-db@^1.54.0\",\n \"tsdown\": \"npm:tsdown@^0.12.8\",\n \"url-template\": \"npm:url-template@^3.1.1\",\n \"uuid\": \"npm:uuid@^11.1.0\",\n \"xss\": \"npm:xss@^1.0.15\"\n },\n \"exclude\": [\n \"dist\",\n \"junit.xml\",\n \"src/css\"\n ],\n \"fmt\": {\n \"exclude\": [\n \"*.md\",\n \"*.yaml\",\n \"*.yml\",\n \"src/static/*.ts\"\n ]\n },\n \"tasks\": {\n \"test\": \"deno test --allow-env=NODE_V8_COVERAGE,JEST_WORKER_ID --allow-net=hollo.social --parallel\",\n \"test:node\": \"pnpm install && pnpm test\",\n \"test-all\": {\n \"dependencies\": [\n \"check\",\n \"test\",\n \"test:node\"\n ]\n },\n \"coverage\": \"deno task test --coverage --clean && deno coverage --html\"\n }\n}\n"],"mappings":";;;;;WACU;cACG;cACA;cACA;CACT,KAAK;CACL,SAAS;CACT,WAAW;CACX,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,UAAU;CACV,cAAc;CACd,gBAAgB;CAChB,aAAa;CACb,UAAU;AACX;cACU;CACT,iBAAiB;CACjB,yBAAyB;CACzB,+BAA+B;CAC/B,+BAA+B;CAC/B,iBAAiB;CACjB,eAAe;CACf,WAAW;CACX,UAAU;CACV,gBAAgB;CAChB,QAAQ;CACR,OAAO;AACR;cACU;CACT;CACA;CACA;AACD;UACM,EACL,WAAW;CACT;CACA;CACA;CACA;AACD,EACF;YACQ;CACP,QAAQ;CACR,aAAa;CACb,YAAY,EACV,gBAAgB;EACd;EACA;EACA;CACD,EACF;CACD,YAAY;AACb;mBAtDH;;;;;;;;;AAuDC"}
1
+ {"version":3,"file":"deno.js","names":[],"sources":["../deno.json"],"sourcesContent":["{\n \"name\": \"@fedify/botkit\",\n \"version\": \"0.5.0-dev.225+cfc4181c\",\n \"license\": \"AGPL-3.0-only\",\n \"exports\": {\n \".\": \"./src/mod.ts\",\n \"./bot\": \"./src/bot.ts\",\n \"./emoji\": \"./src/emoji.ts\",\n \"./events\": \"./src/events.ts\",\n \"./follow\": \"./src/follow.ts\",\n \"./instance\": \"./src/instance.ts\",\n \"./message\": \"./src/message.ts\",\n \"./poll\": \"./src/poll.ts\",\n \"./reaction\": \"./src/reaction.ts\",\n \"./repository\": \"./src/repository.ts\",\n \"./session\": \"./src/session.ts\",\n \"./text\": \"./src/text.ts\"\n },\n \"imports\": {\n \"@fedify/vocab\": \"jsr:@fedify/vocab@^2.1.2\",\n \"@fedify/vocab-runtime\": \"jsr:@fedify/vocab-runtime@^2.1.2\",\n \"@fedify/markdown-it-hashtag\": \"jsr:@fedify/markdown-it-hashtag@^0.3.0\",\n \"@fedify/markdown-it-mention\": \"jsr:@fedify/markdown-it-mention@^0.3.0\",\n \"html-entities\": \"npm:html-entities@^2.6.0\",\n \"markdown-it\": \"npm:markdown-it@^14.1.0\",\n \"mime-db\": \"npm:mime-db@^1.54.0\",\n \"tsdown\": \"npm:tsdown@^0.12.8\",\n \"url-template\": \"npm:url-template@^3.1.1\",\n \"uuid\": \"npm:uuid@^11.1.0\",\n \"xss\": \"npm:xss@^1.0.15\"\n },\n \"exclude\": [\n \"dist\",\n \"junit.xml\",\n \"src/css\"\n ],\n \"fmt\": {\n \"exclude\": [\n \"*.md\",\n \"*.yaml\",\n \"*.yml\",\n \"src/static/*.ts\"\n ]\n },\n \"tasks\": {\n \"test\": \"deno test --allow-env=NODE_V8_COVERAGE,JEST_WORKER_ID --allow-net=hollo.social --parallel\",\n \"test:node\": \"pnpm install && pnpm test\",\n \"test-all\": {\n \"dependencies\": [\n \"check\",\n \"test\",\n \"test:node\"\n ]\n },\n \"coverage\": \"deno task test --coverage --clean && deno coverage --html\"\n }\n}\n"],"mappings":";;;;;WACU;cACG;cACA;cACA;CACT,KAAK;CACL,SAAS;CACT,WAAW;CACX,YAAY;CACZ,YAAY;CACZ,cAAc;CACd,aAAa;CACb,UAAU;CACV,cAAc;CACd,gBAAgB;CAChB,aAAa;CACb,UAAU;AACX;cACU;CACT,iBAAiB;CACjB,yBAAyB;CACzB,+BAA+B;CAC/B,+BAA+B;CAC/B,iBAAiB;CACjB,eAAe;CACf,WAAW;CACX,UAAU;CACV,gBAAgB;CAChB,QAAQ;CACR,OAAO;AACR;cACU;CACT;CACA;CACA;AACD;UACM,EACL,WAAW;CACT;CACA;CACA;CACA;AACD,EACF;YACQ;CACP,QAAQ;CACR,aAAa;CACb,YAAY,EACV,gBAAgB;EACd;EACA;EACA;CACD,EACF;CACD,YAAY;AACb;mBAvDH;;;;;;;;;AAwDC"}
@@ -57,8 +57,8 @@ test("FollowRequestImpl.accept()", async () => {
57
57
  const followRequest = new FollowRequestImpl(session, follow, follower);
58
58
  await followRequest.accept();
59
59
  assert.deepStrictEqual(followRequest.state, "accepted");
60
- assert.ok(await repository.hasFollower(new URL("https://example.com/ap/actor/john")));
61
- const [storedFollower] = await Array.fromAsync(repository.getFollowers());
60
+ assert.ok(await repository.hasFollower("bot", new URL("https://example.com/ap/actor/john")));
61
+ const [storedFollower] = await Array.fromAsync(repository.getFollowers("bot"));
62
62
  assert.ok(storedFollower != null);
63
63
  assert.deepStrictEqual(storedFollower.id, follower.id);
64
64
  assert.deepStrictEqual(storedFollower.preferredUsername, follower.preferredUsername);
@@ -93,7 +93,7 @@ test("FollowRequestImpl.reject()", async () => {
93
93
  const followRequest = new FollowRequestImpl(session, follow, follower);
94
94
  await followRequest.reject();
95
95
  assert.deepStrictEqual(followRequest.state, "rejected");
96
- assert.deepStrictEqual(await repository.hasFollower(new URL("https://example.com/ap/actor/john")), false);
96
+ assert.deepStrictEqual(await repository.hasFollower("bot", new URL("https://example.com/ap/actor/john")), false);
97
97
  assert.deepStrictEqual(ctx.sentActivities.length, 1);
98
98
  const { recipients, activity } = ctx.sentActivities[0];
99
99
  assert.deepStrictEqual(recipients, [follower]);
@@ -1 +1 @@
1
- {"version":3,"file":"follow-impl.test.js","names":[],"sources":["../src/follow-impl.test.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025–2026 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { Person } from \"@fedify/vocab\";\nimport { MemoryKvStore } from \"@fedify/fedify/federation\";\nimport { Accept, Follow, Reject } from \"@fedify/vocab\";\nimport assert from \"node:assert\";\nimport { test } from \"node:test\";\nimport { BotImpl } from \"./bot-impl.ts\";\nimport { FollowRequestImpl } from \"./follow-impl.ts\";\nimport { MemoryRepository } from \"./repository.ts\";\nimport { createMockContext } from \"./session-impl.test.ts\";\nimport { SessionImpl } from \"./session-impl.ts\";\n\ntest(\"new FollowRequestImpl()\", () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n assert.deepStrictEqual(followRequest.session, session);\n assert.deepStrictEqual(followRequest.id, follow.id);\n assert.deepStrictEqual(followRequest.raw, follow);\n assert.deepStrictEqual(followRequest.follower, follower);\n assert.deepStrictEqual(followRequest.state, \"pending\");\n});\n\ntest(\"FollowRequestImpl.accept()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n await followRequest.accept();\n assert.deepStrictEqual(followRequest.state, \"accepted\");\n assert.ok(\n await repository.hasFollower(new URL(\"https://example.com/ap/actor/john\")),\n );\n const [storedFollower] = await Array.fromAsync(repository.getFollowers());\n assert.ok(storedFollower != null);\n assert.deepStrictEqual(storedFollower.id, follower.id);\n assert.deepStrictEqual(\n storedFollower.preferredUsername,\n follower.preferredUsername,\n );\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [follower]);\n assert.ok(activity instanceof Accept);\n assert.deepStrictEqual(activity.actorId, session.actorId);\n assert.deepStrictEqual(activity.toId, follower.id);\n assert.deepStrictEqual(activity.objectId, follow.id);\n\n assert.rejects(\n () => followRequest.accept(),\n TypeError,\n \"The follow request is not pending.\",\n );\n assert.rejects(\n () => followRequest.reject(),\n TypeError,\n \"The follow request is not pending.\",\n );\n});\n\ntest(\"FollowRequestImpl.reject()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n await followRequest.reject();\n assert.deepStrictEqual(followRequest.state, \"rejected\");\n assert.deepStrictEqual(\n await repository.hasFollower(new URL(\"https://example.com/ap/actor/john\")),\n false,\n );\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [follower]);\n assert.ok(activity instanceof Reject);\n assert.deepStrictEqual(activity.actorId, session.actorId);\n assert.deepStrictEqual(activity.toId, follower.id);\n assert.deepStrictEqual(activity.objectId, follow.id);\n\n assert.rejects(\n () => followRequest.accept(),\n TypeError,\n \"The follow request is not pending.\",\n );\n assert.rejects(\n () => followRequest.reject(),\n TypeError,\n \"The follow request is not pending.\",\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"follow-impl.test.js","names":[],"sources":["../src/follow-impl.test.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025–2026 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { Person } from \"@fedify/vocab\";\nimport { MemoryKvStore } from \"@fedify/fedify/federation\";\nimport { Accept, Follow, Reject } from \"@fedify/vocab\";\nimport assert from \"node:assert\";\nimport { test } from \"node:test\";\nimport { BotImpl } from \"./bot-impl.ts\";\nimport { FollowRequestImpl } from \"./follow-impl.ts\";\nimport { MemoryRepository } from \"./repository.ts\";\nimport { createMockContext } from \"./session-impl.test.ts\";\nimport { SessionImpl } from \"./session-impl.ts\";\n\ntest(\"new FollowRequestImpl()\", () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n assert.deepStrictEqual(followRequest.session, session);\n assert.deepStrictEqual(followRequest.id, follow.id);\n assert.deepStrictEqual(followRequest.raw, follow);\n assert.deepStrictEqual(followRequest.follower, follower);\n assert.deepStrictEqual(followRequest.state, \"pending\");\n});\n\ntest(\"FollowRequestImpl.accept()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n await followRequest.accept();\n assert.deepStrictEqual(followRequest.state, \"accepted\");\n assert.ok(\n await repository.hasFollower(\n \"bot\",\n new URL(\"https://example.com/ap/actor/john\"),\n ),\n );\n const [storedFollower] = await Array.fromAsync(\n repository.getFollowers(\"bot\"),\n );\n assert.ok(storedFollower != null);\n assert.deepStrictEqual(storedFollower.id, follower.id);\n assert.deepStrictEqual(\n storedFollower.preferredUsername,\n follower.preferredUsername,\n );\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [follower]);\n assert.ok(activity instanceof Accept);\n assert.deepStrictEqual(activity.actorId, session.actorId);\n assert.deepStrictEqual(activity.toId, follower.id);\n assert.deepStrictEqual(activity.objectId, follow.id);\n\n assert.rejects(\n () => followRequest.accept(),\n TypeError,\n \"The follow request is not pending.\",\n );\n assert.rejects(\n () => followRequest.reject(),\n TypeError,\n \"The follow request is not pending.\",\n );\n});\n\ntest(\"FollowRequestImpl.reject()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const follower = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const follow = new Follow({\n id: new URL(\"https://example.com/ap/follow/1\"),\n actor: follower,\n object: session.actorId,\n });\n const followRequest = new FollowRequestImpl(session, follow, follower);\n await followRequest.reject();\n assert.deepStrictEqual(followRequest.state, \"rejected\");\n assert.deepStrictEqual(\n await repository.hasFollower(\n \"bot\",\n new URL(\"https://example.com/ap/actor/john\"),\n ),\n false,\n );\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [follower]);\n assert.ok(activity instanceof Reject);\n assert.deepStrictEqual(activity.actorId, session.actorId);\n assert.deepStrictEqual(activity.toId, follower.id);\n assert.deepStrictEqual(activity.objectId, follow.id);\n\n assert.rejects(\n () => followRequest.accept(),\n TypeError,\n \"The follow request is not pending.\",\n );\n assert.rejects(\n () => followRequest.reject(),\n TypeError,\n \"The follow request is not pending.\",\n );\n});\n"],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
2
+ Date.prototype.toTemporalInstant = toTemporalInstant;
3
+ import { CustomEmoji, DeferredCustomEmoji } from "./emoji.js";
4
+ import { Repository } from "./repository.js";
5
+ import { Bot, PagesOptions } from "./bot.js";
6
+ import { BotDispatcher, BotGroup, BotProfile, CreateBotGroupOptions, CreateInstanceOptions, Instance } from "./instance.js";
7
+ import { BotImpl } from "./bot-impl.js";
8
+ import { Accept, Activity, Announce, Create, Emoji, Follow, Like, Reject, Undo } from "@fedify/vocab";
9
+ import { Context, Federation, InboxContext, KvStore, MessageQueue, NodeInfo, Software } from "@fedify/fedify";
10
+
11
+ //#region src/instance-impl.d.ts
12
+
13
+ /**
14
+ * The default identifier of the instance actor: an internal `Application`
15
+ * actor that an {@link Instance} uses for signing shared-inbox related
16
+ * requests on behalf of the whole instance. It can be overridden through
17
+ * the {@link CreateInstanceOptions.instanceActorIdentifier} option; either
18
+ * way, bots cannot take the effective identifier.
19
+ * @since 0.5.0
20
+ */
21
+ declare const DEFAULT_INSTANCE_ACTOR_IDENTIFIER = "__botkit_instance__";
22
+ /**
23
+ * Options for creating an {@link InstanceImpl}.
24
+ * @internal
25
+ */
26
+ interface InstanceImplOptions extends CreateInstanceOptions {
27
+ collectionWindow?: number;
28
+ /**
29
+ * Whether the instance was created through the single-bot
30
+ * `createBot()` compatibility path. A compatible instance keeps
31
+ * the pre-0.5 behavior: the sole bot's key signs shared-inbox
32
+ * requests and no instance actor is exposed.
33
+ */
34
+ compatMode?: boolean;
35
+ }
36
+ /**
37
+ * The internal implementation of an {@link Instance}. It owns the single
38
+ * Fedify {@link Federation} shared by every bot hosted on the instance, and
39
+ * routes federation callbacks to the right bot by its identifier.
40
+ * @internal
41
+ */
42
+ declare class InstanceImpl<TContextData> implements Omit<Instance<TContextData>, "createBot"> {
43
+ #private;
44
+ readonly kv: KvStore;
45
+ readonly queue?: MessageQueue;
46
+ /**
47
+ * The root repository shared by every bot hosted on the instance.
48
+ */
49
+ readonly repository: Repository;
50
+ readonly software?: Software;
51
+ readonly behindProxy: boolean;
52
+ readonly pages: Required<PagesOptions>;
53
+ readonly collectionWindow: number;
54
+ readonly federation: Federation<TContextData>;
55
+ readonly customEmojis: Record<string, CustomEmoji>;
56
+ /**
57
+ * The identifier of the bot actor that owns local objects whose URIs are
58
+ * in the legacy (pre-0.5) format, which did not carry the identifier.
59
+ */
60
+ readonly legacyObjectUrisIdentifier?: string;
61
+ /**
62
+ * Whether the instance was created through the single-bot
63
+ * `createBot()` compatibility path.
64
+ */
65
+ readonly compatMode: boolean;
66
+ /**
67
+ * The reserved identifier of the instance actor.
68
+ */
69
+ readonly instanceActorIdentifier: string;
70
+ constructor(options: InstanceImplOptions);
71
+ /**
72
+ * Registers a bot on the instance. Invoked by the {@link BotImpl}
73
+ * constructor.
74
+ * @param bot The bot to register.
75
+ * @throws {TypeError} If a bot with the same identifier or username
76
+ * already exists on the instance.
77
+ */
78
+ addBot(bot: BotImpl<TContextData>): void;
79
+ /**
80
+ * Resolves a bot hosted on the instance by its identifier.
81
+ * @param identifier The identifier of the bot to resolve.
82
+ * @returns The resolved bot, or `undefined` if no bot has the identifier.
83
+ */
84
+ getBot(identifier: string): BotImpl<TContextData> | undefined;
85
+ /**
86
+ * Resolves a bot by its identifier: bots registered statically win, then
87
+ * the dynamic bot groups are probed in their registration order.
88
+ * Dynamic resolutions are memoized per context.
89
+ * @param ctx The Fedify context of the resolution.
90
+ * @param identifier The identifier of the bot to resolve.
91
+ * @returns The resolved bot, or `null` if no bot has the identifier.
92
+ */
93
+ resolveBot(ctx: Context<TContextData>, identifier: string): Promise<BotImpl<TContextData> | null>;
94
+ /**
95
+ * Every bot hosted on the instance.
96
+ */
97
+ get bots(): Iterable<BotImpl<TContextData>>;
98
+ /**
99
+ * The number of bots hosted on the instance.
100
+ */
101
+ get botCount(): number;
102
+ createBot(identifier: string, profile: BotProfile<TContextData>): Bot<TContextData>;
103
+ createBot(dispatcher: BotDispatcher<TContextData>, options?: CreateBotGroupOptions<TContextData>): BotGroup<TContextData>;
104
+ /**
105
+ * Resolves a bot hosted on the instance by its username, including
106
+ * dynamically resolved bots.
107
+ * @param ctx The Fedify context of the resolution.
108
+ * @param username The username of the bot to resolve.
109
+ * @returns The resolved bot, or `null` if no bot has the username.
110
+ */
111
+ resolveBotByUsername(ctx: Context<TContextData>, username: string): Promise<BotImpl<TContextData> | null>;
112
+ mapHandle(ctx: Context<TContextData>, username: string): Promise<string | null>;
113
+ onUnverifiedActivity(_ctx: Context<TContextData>, activity: Activity, reason: {
114
+ type: string;
115
+ result?: unknown;
116
+ }): Response | void;
117
+ onFollowed(ctx: InboxContext<TContextData>, follow: Follow): Promise<void>;
118
+ onUndone(ctx: InboxContext<TContextData>, undo: Undo): Promise<void>;
119
+ onFollowAccepted(ctx: InboxContext<TContextData>, accept: Accept): Promise<void>;
120
+ onFollowRejected(ctx: InboxContext<TContextData>, reject: Reject): Promise<void>;
121
+ onLiked(ctx: InboxContext<TContextData>, like: Like): Promise<void>;
122
+ onCreated(ctx: InboxContext<TContextData>, create: Create): Promise<void>;
123
+ onAnnounced(ctx: InboxContext<TContextData>, announce: Announce): Promise<void>;
124
+ dispatchSharedKey(_ctx: Context<TContextData>): {
125
+ identifier: string;
126
+ };
127
+ dispatchNodeInfo(_ctx: Context<TContextData>): NodeInfo;
128
+ dispatchEmoji(ctx: Context<TContextData>, values: {
129
+ name: string;
130
+ }): Emoji | null;
131
+ getEmoji(ctx: Context<TContextData>, name: string, data: CustomEmoji): Emoji;
132
+ addCustomEmoji<TEmojiName extends string>(name: TEmojiName, data: CustomEmoji): DeferredCustomEmoji<TContextData>;
133
+ addCustomEmojis<TEmojiName extends string>(emojis: Readonly<Record<TEmojiName, CustomEmoji>>): Readonly<Record<TEmojiName, DeferredCustomEmoji<TContextData>>>;
134
+ addCollectionInverseProperty(request: Request, contextData: TContextData, response: Response): Promise<Response>;
135
+ fetch(request: Request, contextData: TContextData): Promise<Response>;
136
+ /**
137
+ * The web page URL of a bot hosted on the instance. A compatible
138
+ * (single-bot) instance serves its bot at the web root; a multi-bot
139
+ * instance serves each bot under a path derived from its username.
140
+ * @param bot The bot to get the web page URL of.
141
+ * @param origin The origin of the URL.
142
+ * @returns The web page URL of the bot.
143
+ */
144
+ getBotWebUrl(bot: BotImpl<TContextData>, origin: string | URL): URL;
145
+ /**
146
+ * The web permalink of a message published by a bot hosted on
147
+ * the instance.
148
+ * @param bot The bot that published the message.
149
+ * @param id The UUID of the message.
150
+ * @param origin The origin of the URL.
151
+ * @returns The web permalink of the message.
152
+ */
153
+ getMessageWebUrl(bot: BotImpl<TContextData>, id: string, origin: string | URL): URL;
154
+ }
155
+ //# sourceMappingURL=instance-impl.d.ts.map
156
+ //#endregion
157
+ export { DEFAULT_INSTANCE_ACTOR_IDENTIFIER, InstanceImpl, InstanceImplOptions };
158
+ //# sourceMappingURL=instance-impl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-impl.d.ts","names":[],"sources":["../src/instance-impl.ts"],"sourcesContent":[],"mappings":"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"}