@fedify/botkit 0.5.0-dev.210 → 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.
- package/dist/bot-group.test.d.ts +2 -0
- package/dist/bot-group.test.js +220 -0
- package/dist/bot-group.test.js.map +1 -0
- package/dist/bot-impl.d.ts +132 -13
- package/dist/bot-impl.d.ts.map +1 -1
- package/dist/bot-impl.js +400 -178
- package/dist/bot-impl.js.map +1 -1
- package/dist/bot-impl.test.js +214 -76
- package/dist/bot-impl.test.js.map +1 -1
- package/dist/bot.d.ts +94 -48
- package/dist/bot.d.ts.map +1 -1
- package/dist/bot.js +2 -104
- package/dist/bot.js.map +1 -1
- package/dist/bot.test.js +59 -0
- package/dist/bot.test.js.map +1 -1
- package/dist/components/FollowButton.d.ts +5 -3
- package/dist/components/FollowButton.d.ts.map +1 -1
- package/dist/components/FollowButton.js +2 -2
- package/dist/components/FollowButton.js.map +1 -1
- package/dist/components/Follower.d.ts +2 -2
- package/dist/components/Layout.js +1 -1
- package/dist/components/Layout.js.map +1 -1
- package/dist/components/Message.d.ts +2 -2
- package/dist/deno.js +2 -1
- package/dist/deno.js.map +1 -1
- package/dist/follow-impl.test.js +3 -3
- package/dist/follow-impl.test.js.map +1 -1
- package/dist/instance-impl.d.ts +158 -0
- package/dist/instance-impl.d.ts.map +1 -0
- package/dist/instance-impl.js +603 -0
- package/dist/instance-impl.js.map +1 -0
- package/dist/instance-impl.test.d.ts +2 -0
- package/dist/instance-impl.test.js +103 -0
- package/dist/instance-impl.test.js.map +1 -0
- package/dist/instance-multi.test.d.ts +2 -0
- package/dist/instance-multi.test.js +151 -0
- package/dist/instance-multi.test.js.map +1 -0
- package/dist/instance-routing.test.d.ts +2 -0
- package/dist/instance-routing.test.js +367 -0
- package/dist/instance-routing.test.js.map +1 -0
- package/dist/instance.d.ts +318 -0
- package/dist/instance.d.ts.map +1 -0
- package/dist/instance.js +51 -0
- package/dist/instance.js.map +1 -0
- package/dist/message-impl.d.ts.map +1 -1
- package/dist/message-impl.js +17 -10
- package/dist/message-impl.js.map +1 -1
- package/dist/message-impl.test.js +43 -9
- package/dist/message-impl.test.js.map +1 -1
- package/dist/mod.d.ts +5 -3
- package/dist/mod.js +4 -2
- package/dist/pages.d.ts +12 -3
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.js +112 -41
- package/dist/pages.js.map +1 -1
- package/dist/pages.test.d.ts +2 -0
- package/dist/pages.test.js +170 -0
- package/dist/pages.test.js.map +1 -0
- package/dist/repository.d.ts +385 -138
- package/dist/repository.d.ts.map +1 -1
- package/dist/repository.js +595 -223
- package/dist/repository.js.map +1 -1
- package/dist/repository.test.js +564 -136
- package/dist/repository.test.js.map +1 -1
- package/dist/session-impl.d.ts.map +1 -1
- package/dist/session-impl.js +13 -4
- package/dist/session-impl.js.map +1 -1
- package/dist/session-impl.test.d.ts.map +1 -1
- package/dist/session-impl.test.js +9 -9
- package/dist/session-impl.test.js.map +1 -1
- package/dist/session.d.ts +8 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/text.d.ts.map +1 -1
- package/dist/text.js +27 -10
- package/dist/text.js.map +1 -1
- package/dist/text.test.js +37 -2
- package/dist/text.test.js.map +1 -1
- package/dist/uri.d.ts +46 -0
- package/dist/uri.d.ts.map +1 -0
- package/dist/uri.js +64 -0
- package/dist/uri.js.map +1 -0
- package/dist/uri.test.d.ts +2 -0
- package/dist/uri.test.js +93 -0
- package/dist/uri.test.js.map +1 -0
- 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.
|
|
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"}
|
package/dist/follow-impl.test.js
CHANGED
|
@@ -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":";;;;;;;;;;;;;;;AA0BA,KAAK,2BAA2B,MAAM;CACpC,MAAM,MAAM,IAAI,QAAc;EAAE,IAAI,IAAI;EAAiB,UAAU;CAAO;CAC1E,MAAM,MAAM,kBAAkB,KAAK,sBAAsB;CACzD,MAAM,UAAU,IAAI,YAAY,KAAK;CAErC,MAAM,WAAW,IAAI,OAAO;EAC1B,IAAI,IAAI,IAAI;EACZ,mBAAmB;CACpB;CACD,MAAM,SAAS,IAAI,OAAO;EACxB,IAAI,IAAI,IAAI;EACZ,OAAO;EACP,QAAQ,QAAQ;CACjB;CACD,MAAM,gBAAgB,IAAI,kBAAkB,SAAS,QAAQ;AAC7D,QAAO,gBAAgB,cAAc,SAAS,QAAQ;AACtD,QAAO,gBAAgB,cAAc,IAAI,OAAO,GAAG;AACnD,QAAO,gBAAgB,cAAc,KAAK,OAAO;AACjD,QAAO,gBAAgB,cAAc,UAAU,SAAS;AACxD,QAAO,gBAAgB,cAAc,OAAO,UAAU;AACvD,EAAC;AAEF,KAAK,8BAA8B,YAAY;CAC7C,MAAM,aAAa,IAAI;CACvB,MAAM,MAAM,IAAI,QAAc;EAC5B,IAAI,IAAI;EACR;EACA,UAAU;CACX;CACD,MAAM,MAAM,kBAAkB,KAAK,sBAAsB;CACzD,MAAM,UAAU,IAAI,YAAY,KAAK;CAErC,MAAM,WAAW,IAAI,OAAO;EAC1B,IAAI,IAAI,IAAI;EACZ,mBAAmB;CACpB;CACD,MAAM,SAAS,IAAI,OAAO;EACxB,IAAI,IAAI,IAAI;EACZ,OAAO;EACP,QAAQ,QAAQ;CACjB;CACD,MAAM,gBAAgB,IAAI,kBAAkB,SAAS,QAAQ;AAC7D,OAAM,cAAc,QAAQ;AAC5B,QAAO,gBAAgB,cAAc,OAAO,WAAW;AACvD,QAAO,GACL,MAAM,WAAW,
|
|
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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"}
|