@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,195 @@
1
+
2
+ import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
3
+ Date.prototype.toTemporalInstant = toTemporalInstant;
4
+
5
+ import { createMessage, isMessageObject } from "./message-impl.js";
6
+ import { Follow, Link, Undo } from "@fedify/fedify/vocab";
7
+ import { Create as Create$1, LanguageString, Mention as Mention$1, Note as Note$1, PUBLIC_COLLECTION as PUBLIC_COLLECTION$1, isActor as isActor$1 } from "@fedify/fedify";
8
+ import { getLogger } from "@logtape/logtape";
9
+ import { encode } from "html-entities";
10
+ import { v7 } from "uuid";
11
+
12
+ //#region src/session-impl.ts
13
+ const logger = getLogger(["botkit", "session"]);
14
+ var SessionImpl = class {
15
+ bot;
16
+ context;
17
+ constructor(bot, context) {
18
+ this.bot = bot;
19
+ this.context = context;
20
+ }
21
+ get actorId() {
22
+ return this.context.getActorUri(this.bot.identifier);
23
+ }
24
+ get actorHandle() {
25
+ return `@${this.bot.username}@${this.context.host}`;
26
+ }
27
+ async getActor() {
28
+ return await this.bot.dispatchActor(this.context, this.bot.identifier);
29
+ }
30
+ async follow(actor) {
31
+ if (actor instanceof URL || typeof actor === "string") {
32
+ if (actor instanceof URL && actor.href === this.actorId.href || typeof actor === "string" && (actor === this.actorId.href || actor === this.actorHandle)) throw new TypeError("The bot cannot follow itself.");
33
+ const documentLoader = await this.context.getDocumentLoader(this.bot);
34
+ const object = await this.context.lookupObject(actor, { documentLoader });
35
+ if (!isActor$1(object)) throw new TypeError("The resolved object is not an Actor.");
36
+ actor = object;
37
+ }
38
+ if (actor.id == null) throw new TypeError("The actor does not have an ID.");
39
+ else if (actor.id.href === this.actorId.href) throw new TypeError("The bot cannot follow itself.");
40
+ const followee = await this.bot.repository.getFollowee(actor.id);
41
+ if (followee != null) {
42
+ logger.warn("The bot is already following the actor {actor}.", { actor: actor.id.href });
43
+ return;
44
+ }
45
+ const id = v7();
46
+ const follow = new Follow({
47
+ id: this.context.getObjectUri(Follow, { id }),
48
+ actor: this.context.getActorUri(this.bot.identifier),
49
+ object: actor.id,
50
+ to: actor.id
51
+ });
52
+ await this.bot.repository.addSentFollow(id, follow);
53
+ await this.context.sendActivity(this.bot, actor, follow, { excludeBaseUris: [new URL(this.context.origin)] });
54
+ }
55
+ async unfollow(actor) {
56
+ const documentLoader = await this.context.getDocumentLoader(this.bot);
57
+ if (actor instanceof URL || typeof actor === "string") {
58
+ if (actor instanceof URL && actor.href === this.actorId.href || typeof actor === "string" && (actor === this.actorId.href || actor === this.actorHandle)) throw new TypeError("The bot cannot unfollow itself.");
59
+ const object = await this.context.lookupObject(actor, { documentLoader });
60
+ if (!isActor$1(object)) throw new TypeError("The resolved object is not an Actor.");
61
+ actor = object;
62
+ }
63
+ if (actor.id == null) throw new TypeError("The actor does not have an ID.");
64
+ else if (actor.id.href === this.actorId.href) throw new TypeError("The bot cannot unfollow itself.");
65
+ const follow = await this.bot.repository.getFollowee(actor.id);
66
+ if (follow == null) {
67
+ logger.warn("The bot is not following the actor {actor}.", { actor: actor.id.href });
68
+ return;
69
+ }
70
+ await this.bot.repository.removeFollowee(actor.id);
71
+ if (follow.id != null && follow.objectId?.href === actor.id.href) await this.context.sendActivity(this.bot, actor, new Undo({
72
+ id: new URL("#undo", follow.id),
73
+ actor: this.context.getActorUri(this.bot.identifier),
74
+ object: follow,
75
+ to: actor.id
76
+ }), { excludeBaseUris: [new URL(this.context.origin)] });
77
+ }
78
+ async follows(actor) {
79
+ let actorId;
80
+ if (isActor$1(actor)) {
81
+ if (actor.id == null) throw new TypeError("The actor does not have an ID.");
82
+ actorId = actor.id;
83
+ } else if (actor instanceof URL) actorId = actor;
84
+ else if (actor.startsWith("http://") || actor.startsWith("https://")) actorId = new URL(actor);
85
+ else {
86
+ if (actor === this.actorHandle) return false;
87
+ const documentLoader = await this.context.getDocumentLoader(this.bot);
88
+ const object = await this.context.lookupObject(actor, { documentLoader });
89
+ if (!isActor$1(object)) throw new TypeError("The resolved object is not an Actor.");
90
+ if (object.id == null) throw new TypeError("The actor does not have an ID.");
91
+ actorId = object.id;
92
+ }
93
+ if (actorId.href === this.actorId.href) return false;
94
+ const follow = await this.bot.repository.getFollowee(actorId);
95
+ return follow != null;
96
+ }
97
+ async publish(content, options = {}) {
98
+ const published = /* @__PURE__ */ new Date();
99
+ const id = v7({ msecs: +published });
100
+ const cls = "class" in options ? options.class : Note$1;
101
+ const visibility = options.visibility ?? "public";
102
+ let contentHtml = "";
103
+ for await (const chunk of content.getHtml(this)) contentHtml += chunk;
104
+ const tags = await Array.fromAsync(content.getTags(this));
105
+ const mentionedActorIds = [];
106
+ for (const tag of tags) if (tag instanceof Mention$1 && tag.href != null) mentionedActorIds.push(tag.href);
107
+ if (options.quoteTarget != null) {
108
+ let url = options.quoteTarget.raw.url ?? options.quoteTarget.id;
109
+ if (url instanceof Link) url = url.href ?? options.quoteTarget.id;
110
+ contentHtml += `\n\n<p class="quote-inline"><br>RE: <a href="${encode(url.href)}">${encode(url.href)}</a></p>`;
111
+ tags.push(new Link({
112
+ mediaType: "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
113
+ rel: "https://misskey-hub.net/ns#_misskey_quote",
114
+ href: options.quoteTarget.id,
115
+ name: `RE: ${url.href}`
116
+ }));
117
+ }
118
+ const msg = new cls({
119
+ id: this.context.getObjectUri(cls, { id }),
120
+ contents: options.language == null ? [contentHtml] : [new LanguageString(contentHtml, options.language), contentHtml],
121
+ replyTarget: options.replyTarget?.id,
122
+ quoteUrl: options.quoteTarget?.id,
123
+ tags,
124
+ attribution: this.context.getActorUri(this.bot.identifier),
125
+ attachments: options.attachments ?? [],
126
+ tos: visibility === "public" ? [PUBLIC_COLLECTION$1, ...mentionedActorIds] : visibility === "unlisted" || visibility === "followers" ? [this.context.getFollowersUri(this.bot.identifier), ...mentionedActorIds] : mentionedActorIds,
127
+ ccs: visibility === "public" ? [this.context.getFollowersUri(this.bot.identifier)] : visibility === "unlisted" ? [PUBLIC_COLLECTION$1] : [],
128
+ published: published.toTemporalInstant(),
129
+ url: new URL(`/message/${id}`, this.context.origin)
130
+ });
131
+ const activity = new Create$1({
132
+ id: this.context.getObjectUri(Create$1, { id }),
133
+ actors: msg.attributionIds,
134
+ tos: msg.toIds,
135
+ ccs: msg.ccIds,
136
+ object: msg,
137
+ published: published.toTemporalInstant()
138
+ });
139
+ await this.bot.repository.addMessage(id, activity);
140
+ const preferSharedInbox = visibility === "public" || visibility === "unlisted" || visibility === "followers";
141
+ const excludeBaseUris = [new URL(this.context.origin)];
142
+ if (preferSharedInbox) await this.context.sendActivity(this.bot, "followers", activity, {
143
+ preferSharedInbox,
144
+ excludeBaseUris
145
+ });
146
+ const cachedObjects = {};
147
+ for (const cachedObject of content.getCachedObjects()) {
148
+ if (cachedObject.id == null) continue;
149
+ cachedObjects[cachedObject.id.href] = cachedObject;
150
+ }
151
+ if (mentionedActorIds.length > 0) {
152
+ const documentLoader = await this.context.getDocumentLoader(this.bot);
153
+ const promises = [];
154
+ for (const mentionedActorId of mentionedActorIds) {
155
+ const cachedObject = cachedObjects[mentionedActorId.href];
156
+ const promise = cachedObject == null ? this.context.lookupObject(mentionedActorId, { documentLoader }) : Promise.resolve(cachedObject);
157
+ promises.push(promise);
158
+ }
159
+ const objects = await Promise.all(promises);
160
+ const mentionedActors = objects.filter(isActor$1);
161
+ await this.context.sendActivity(this.bot, mentionedActors, activity, {
162
+ preferSharedInbox,
163
+ excludeBaseUris
164
+ });
165
+ }
166
+ if (options.replyTarget != null) await this.context.sendActivity(this.bot, options.replyTarget.actor, activity, {
167
+ preferSharedInbox,
168
+ excludeBaseUris,
169
+ fanout: "skip"
170
+ });
171
+ if (options.quoteTarget != null) await this.context.sendActivity(this.bot, options.quoteTarget.actor, activity, {
172
+ preferSharedInbox,
173
+ excludeBaseUris,
174
+ fanout: "skip"
175
+ });
176
+ return await createMessage(msg, this, cachedObjects, options.replyTarget, options.quoteTarget, true);
177
+ }
178
+ async *getOutbox(options = {}) {
179
+ for await (const activity of this.bot.repository.getMessages(options)) {
180
+ let object;
181
+ try {
182
+ object = await activity.getObject(this.context);
183
+ } catch {
184
+ continue;
185
+ }
186
+ if (object == null || !isMessageObject(object)) continue;
187
+ const message = await createMessage(object, this, {});
188
+ yield message;
189
+ }
190
+ }
191
+ };
192
+
193
+ //#endregion
194
+ export { SessionImpl };
195
+ //# sourceMappingURL=session-impl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-impl.js","names":["bot: BotImpl<TContextData>","context: Context<TContextData>","actor: Actor | URL | string","actorId: URL","content: Text<\"block\", TContextData>","options:\n | SessionImplPublishOptions<TContextData>\n | SessionImplPublishOptionsWithClass<MessageClass, TContextData>","Note","mentionedActorIds: URL[]","Mention","PUBLIC_COLLECTION","Create","cachedObjects: Record<string, Object>","promises: Promise<Object | null>[]","isActor","options: SessionGetOutboxOptions","object: Object | null"],"sources":["../src/session-impl.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport {\n type Actor,\n type Context,\n Create,\n isActor,\n LanguageString,\n Mention,\n Note,\n type Object,\n PUBLIC_COLLECTION,\n} from \"@fedify/fedify\";\nimport { Follow, Link, Undo } from \"@fedify/fedify/vocab\";\nimport { getLogger } from \"@logtape/logtape\";\nimport { encode } from \"html-entities\";\nimport { v7 as uuidv7 } from \"uuid\";\nimport type { BotImpl } from \"./bot-impl.ts\";\nimport { createMessage, isMessageObject } from \"./message-impl.ts\";\nimport type { AuthorizedMessage, Message, MessageClass } from \"./message.ts\";\nimport type { Uuid } from \"./repository.ts\";\nimport type {\n Session,\n SessionGetOutboxOptions,\n SessionPublishOptions,\n SessionPublishOptionsWithClass,\n} from \"./session.ts\";\nimport type { Text } from \"./text.ts\";\n\nconst logger = getLogger([\"botkit\", \"session\"]);\n\nexport interface SessionImplPublishOptions<TContextData>\n extends SessionPublishOptions<TContextData> {\n replyTarget?: Message<MessageClass, TContextData>;\n}\n\nexport interface SessionImplPublishOptionsWithClass<\n T extends MessageClass,\n TContextData,\n> extends\n SessionPublishOptionsWithClass<T, TContextData>,\n SessionImplPublishOptions<TContextData> {\n}\n\nexport class SessionImpl<TContextData> implements Session<TContextData> {\n readonly bot: BotImpl<TContextData>;\n readonly context: Context<TContextData>;\n\n constructor(bot: BotImpl<TContextData>, context: Context<TContextData>) {\n this.bot = bot;\n this.context = context;\n }\n\n get actorId() {\n return this.context.getActorUri(this.bot.identifier);\n }\n\n get actorHandle() {\n return `@${this.bot.username}@${this.context.host}` as const;\n }\n\n async getActor(): Promise<Actor> {\n return (await this.bot.dispatchActor(this.context, this.bot.identifier))!;\n }\n\n async follow(actor: Actor | URL | string): Promise<void> {\n if (actor instanceof URL || typeof actor === \"string\") {\n if (\n actor instanceof URL && actor.href === this.actorId.href ||\n typeof actor === \"string\" &&\n (actor === this.actorId.href || actor === this.actorHandle)\n ) {\n throw new TypeError(\"The bot cannot follow itself.\");\n }\n const documentLoader = await this.context.getDocumentLoader(this.bot);\n const object = await this.context.lookupObject(actor, { documentLoader });\n if (!isActor(object)) {\n throw new TypeError(\"The resolved object is not an Actor.\");\n }\n actor = object;\n }\n if (actor.id == null) {\n throw new TypeError(\"The actor does not have an ID.\");\n } else if (actor.id.href === this.actorId.href) {\n throw new TypeError(\"The bot cannot follow itself.\");\n }\n const followee = await this.bot.repository.getFollowee(actor.id);\n if (followee != null) {\n logger.warn(\n \"The bot is already following the actor {actor}.\",\n { actor: actor.id.href },\n );\n return;\n }\n const id = uuidv7() as Uuid;\n const follow = new Follow({\n id: this.context.getObjectUri(Follow, { id }),\n actor: this.context.getActorUri(this.bot.identifier),\n object: actor.id,\n to: actor.id,\n });\n await this.bot.repository.addSentFollow(id, follow);\n await this.context.sendActivity(\n this.bot,\n actor,\n follow,\n { excludeBaseUris: [new URL(this.context.origin)] },\n );\n }\n\n async unfollow(actor: Actor | URL | string): Promise<void> {\n const documentLoader = await this.context.getDocumentLoader(this.bot);\n if (actor instanceof URL || typeof actor === \"string\") {\n if (\n actor instanceof URL && actor.href === this.actorId.href ||\n typeof actor === \"string\" &&\n (actor === this.actorId.href || actor === this.actorHandle)\n ) {\n throw new TypeError(\"The bot cannot unfollow itself.\");\n }\n const object = await this.context.lookupObject(actor, { documentLoader });\n if (!isActor(object)) {\n throw new TypeError(\"The resolved object is not an Actor.\");\n }\n actor = object;\n }\n if (actor.id == null) {\n throw new TypeError(\"The actor does not have an ID.\");\n } else if (actor.id.href === this.actorId.href) {\n throw new TypeError(\"The bot cannot unfollow itself.\");\n }\n const follow = await this.bot.repository.getFollowee(actor.id);\n if (follow == null) {\n logger.warn(\n \"The bot is not following the actor {actor}.\",\n { actor: actor.id.href },\n );\n return;\n }\n await this.bot.repository.removeFollowee(actor.id);\n if (follow.id != null && follow.objectId?.href === actor.id.href) {\n await this.context.sendActivity(\n this.bot,\n actor,\n new Undo({\n id: new URL(\"#undo\", follow.id),\n actor: this.context.getActorUri(this.bot.identifier),\n object: follow,\n to: actor.id,\n }),\n { excludeBaseUris: [new URL(this.context.origin)] },\n );\n }\n }\n\n async follows(actor: Actor | URL | string): Promise<boolean> {\n let actorId: URL;\n if (isActor(actor)) {\n if (actor.id == null) {\n throw new TypeError(\"The actor does not have an ID.\");\n }\n actorId = actor.id;\n } else if (actor instanceof URL) {\n actorId = actor;\n } else {\n if (actor.startsWith(\"http://\") || actor.startsWith(\"https://\")) {\n actorId = new URL(actor);\n } else {\n if (actor === this.actorHandle) return false;\n const documentLoader = await this.context.getDocumentLoader(this.bot);\n const object = await this.context.lookupObject(actor, {\n documentLoader,\n });\n if (!isActor(object)) {\n throw new TypeError(\"The resolved object is not an Actor.\");\n }\n if (object.id == null) {\n throw new TypeError(\"The actor does not have an ID.\");\n }\n actorId = object.id;\n }\n }\n if (actorId.href === this.actorId.href) return false;\n const follow = await this.bot.repository.getFollowee(actorId);\n return follow != null;\n }\n\n async publish(\n content: Text<\"block\", TContextData>,\n options?: SessionImplPublishOptions<TContextData>,\n ): Promise<AuthorizedMessage<Note, TContextData>>;\n async publish<T extends MessageClass>(\n content: Text<\"block\", TContextData>,\n options: SessionImplPublishOptionsWithClass<T, TContextData>,\n ): Promise<AuthorizedMessage<T, TContextData>>;\n async publish(\n content: Text<\"block\", TContextData>,\n options:\n | SessionImplPublishOptions<TContextData>\n | SessionImplPublishOptionsWithClass<MessageClass, TContextData> = {},\n ): Promise<AuthorizedMessage<MessageClass, TContextData>> {\n const published = new Date();\n const id = uuidv7({ msecs: +published }) as Uuid;\n const cls = \"class\" in options ? options.class : Note;\n const visibility = options.visibility ?? \"public\";\n let contentHtml = \"\";\n for await (const chunk of content.getHtml(this)) {\n contentHtml += chunk;\n }\n const tags = await Array.fromAsync(content.getTags(this));\n const mentionedActorIds: URL[] = [];\n for (const tag of tags) {\n if (tag instanceof Mention && tag.href != null) {\n mentionedActorIds.push(tag.href);\n }\n }\n if (options.quoteTarget != null) {\n let url = options.quoteTarget.raw.url ?? options.quoteTarget.id;\n if (url instanceof Link) url = url.href ?? options.quoteTarget.id;\n contentHtml += `\\n\\n<p class=\"quote-inline\"><br>RE: <a href=\"${\n encode(url.href)\n }\">${encode(url.href)}</a></p>`;\n tags.push(\n new Link({\n mediaType:\n 'application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"',\n rel: \"https://misskey-hub.net/ns#_misskey_quote\",\n href: options.quoteTarget.id,\n name: `RE: ${url.href}`,\n }),\n );\n }\n const msg = new cls({\n id: this.context.getObjectUri<MessageClass>(cls, { id }),\n contents: options.language == null\n ? [contentHtml]\n : [new LanguageString(contentHtml, options.language), contentHtml],\n replyTarget: options.replyTarget?.id,\n quoteUrl: options.quoteTarget?.id,\n tags,\n attribution: this.context.getActorUri(this.bot.identifier),\n attachments: options.attachments ?? [],\n tos: visibility === \"public\"\n ? [PUBLIC_COLLECTION, ...mentionedActorIds]\n : visibility === \"unlisted\" || visibility === \"followers\"\n ? [\n this.context.getFollowersUri(this.bot.identifier),\n ...mentionedActorIds,\n ]\n : mentionedActorIds,\n ccs: visibility === \"public\"\n ? [this.context.getFollowersUri(this.bot.identifier)]\n : visibility === \"unlisted\"\n ? [PUBLIC_COLLECTION]\n : [],\n published: published.toTemporalInstant(),\n url: new URL(`/message/${id}`, this.context.origin),\n });\n const activity = new Create({\n id: this.context.getObjectUri(Create, { id }),\n actors: msg.attributionIds,\n tos: msg.toIds,\n ccs: msg.ccIds,\n object: msg,\n published: published.toTemporalInstant(),\n });\n await this.bot.repository.addMessage(id, activity);\n const preferSharedInbox = visibility === \"public\" ||\n visibility === \"unlisted\" || visibility === \"followers\";\n const excludeBaseUris = [new URL(this.context.origin)];\n if (preferSharedInbox) {\n await this.context.sendActivity(\n this.bot,\n \"followers\",\n activity,\n { preferSharedInbox, excludeBaseUris },\n );\n }\n const cachedObjects: Record<string, Object> = {};\n for (const cachedObject of content.getCachedObjects()) {\n if (cachedObject.id == null) continue;\n cachedObjects[cachedObject.id.href] = cachedObject;\n }\n if (mentionedActorIds.length > 0) {\n const documentLoader = await this.context.getDocumentLoader(this.bot);\n const promises: Promise<Object | null>[] = [];\n for (const mentionedActorId of mentionedActorIds) {\n const cachedObject = cachedObjects[mentionedActorId.href];\n const promise = cachedObject == null\n ? this.context.lookupObject(\n mentionedActorId,\n { documentLoader },\n )\n : Promise.resolve(cachedObject);\n promises.push(promise);\n }\n const objects = await Promise.all(promises);\n const mentionedActors = objects.filter(isActor);\n await this.context.sendActivity(\n this.bot,\n mentionedActors,\n activity,\n { preferSharedInbox, excludeBaseUris },\n );\n }\n if (options.replyTarget != null) {\n await this.context.sendActivity(\n this.bot,\n options.replyTarget.actor,\n activity,\n { preferSharedInbox, excludeBaseUris, fanout: \"skip\" },\n );\n }\n if (options.quoteTarget != null) {\n await this.context.sendActivity(\n this.bot,\n options.quoteTarget.actor,\n activity,\n { preferSharedInbox, excludeBaseUris, fanout: \"skip\" },\n );\n }\n return await createMessage(\n msg,\n this,\n cachedObjects,\n options.replyTarget,\n options.quoteTarget,\n true,\n );\n }\n\n async *getOutbox(\n options: SessionGetOutboxOptions = {},\n ): AsyncIterable<AuthorizedMessage<MessageClass, TContextData>> {\n for await (const activity of this.bot.repository.getMessages(options)) {\n let object: Object | null;\n try {\n object = await activity.getObject(this.context);\n } catch {\n continue;\n }\n if (object == null || !isMessageObject(object)) continue;\n const message = await createMessage(object, this, {});\n yield message;\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;AA0CA,MAAM,SAAS,UAAU,CAAC,UAAU,SAAU,EAAC;AAe/C,IAAa,cAAb,MAAwE;CACtE,AAAS;CACT,AAAS;CAET,YAAYA,KAA4BC,SAAgC;AACtE,OAAK,MAAM;AACX,OAAK,UAAU;CAChB;CAED,IAAI,UAAU;AACZ,SAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,WAAW;CACrD;CAED,IAAI,cAAc;AAChB,UAAQ,GAAG,KAAK,IAAI,SAAS,GAAG,KAAK,QAAQ,KAAK;CACnD;CAED,MAAM,WAA2B;AAC/B,SAAQ,MAAM,KAAK,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI,WAAW;CACxE;CAED,MAAM,OAAOC,OAA4C;AACvD,MAAI,iBAAiB,cAAc,UAAU,UAAU;AACrD,OACE,iBAAiB,OAAO,MAAM,SAAS,KAAK,QAAQ,eAC7C,UAAU,aACd,UAAU,KAAK,QAAQ,QAAQ,UAAU,KAAK,aAEjD,OAAM,IAAI,UAAU;GAEtB,MAAM,iBAAiB,MAAM,KAAK,QAAQ,kBAAkB,KAAK,IAAI;GACrE,MAAM,SAAS,MAAM,KAAK,QAAQ,aAAa,OAAO,EAAE,eAAgB,EAAC;AACzE,QAAK,UAAQ,OAAO,CAClB,OAAM,IAAI,UAAU;AAEtB,WAAQ;EACT;AACD,MAAI,MAAM,MAAM,KACd,OAAM,IAAI,UAAU;WACX,MAAM,GAAG,SAAS,KAAK,QAAQ,KACxC,OAAM,IAAI,UAAU;EAEtB,MAAM,WAAW,MAAM,KAAK,IAAI,WAAW,YAAY,MAAM,GAAG;AAChE,MAAI,YAAY,MAAM;AACpB,UAAO,KACL,mDACA,EAAE,OAAO,MAAM,GAAG,KAAM,EACzB;AACD;EACD;EACD,MAAM,KAAK,IAAQ;EACnB,MAAM,SAAS,IAAI,OAAO;GACxB,IAAI,KAAK,QAAQ,aAAa,QAAQ,EAAE,GAAI,EAAC;GAC7C,OAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,WAAW;GACpD,QAAQ,MAAM;GACd,IAAI,MAAM;EACX;AACD,QAAM,KAAK,IAAI,WAAW,cAAc,IAAI,OAAO;AACnD,QAAM,KAAK,QAAQ,aACjB,KAAK,KACL,OACA,QACA,EAAE,iBAAiB,CAAC,IAAI,IAAI,KAAK,QAAQ,OAAQ,EAAE,EACpD;CACF;CAED,MAAM,SAASA,OAA4C;EACzD,MAAM,iBAAiB,MAAM,KAAK,QAAQ,kBAAkB,KAAK,IAAI;AACrE,MAAI,iBAAiB,cAAc,UAAU,UAAU;AACrD,OACE,iBAAiB,OAAO,MAAM,SAAS,KAAK,QAAQ,eAC7C,UAAU,aACd,UAAU,KAAK,QAAQ,QAAQ,UAAU,KAAK,aAEjD,OAAM,IAAI,UAAU;GAEtB,MAAM,SAAS,MAAM,KAAK,QAAQ,aAAa,OAAO,EAAE,eAAgB,EAAC;AACzE,QAAK,UAAQ,OAAO,CAClB,OAAM,IAAI,UAAU;AAEtB,WAAQ;EACT;AACD,MAAI,MAAM,MAAM,KACd,OAAM,IAAI,UAAU;WACX,MAAM,GAAG,SAAS,KAAK,QAAQ,KACxC,OAAM,IAAI,UAAU;EAEtB,MAAM,SAAS,MAAM,KAAK,IAAI,WAAW,YAAY,MAAM,GAAG;AAC9D,MAAI,UAAU,MAAM;AAClB,UAAO,KACL,+CACA,EAAE,OAAO,MAAM,GAAG,KAAM,EACzB;AACD;EACD;AACD,QAAM,KAAK,IAAI,WAAW,eAAe,MAAM,GAAG;AAClD,MAAI,OAAO,MAAM,QAAQ,OAAO,UAAU,SAAS,MAAM,GAAG,KAC1D,OAAM,KAAK,QAAQ,aACjB,KAAK,KACL,OACA,IAAI,KAAK;GACP,IAAI,IAAI,IAAI,SAAS,OAAO;GAC5B,OAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,WAAW;GACpD,QAAQ;GACR,IAAI,MAAM;EACX,IACD,EAAE,iBAAiB,CAAC,IAAI,IAAI,KAAK,QAAQ,OAAQ,EAAE,EACpD;CAEJ;CAED,MAAM,QAAQA,OAA+C;EAC3D,IAAIC;AACJ,MAAI,UAAQ,MAAM,EAAE;AAClB,OAAI,MAAM,MAAM,KACd,OAAM,IAAI,UAAU;AAEtB,aAAU,MAAM;EACjB,WAAU,iBAAiB,IAC1B,WAAU;WAEN,MAAM,WAAW,UAAU,IAAI,MAAM,WAAW,WAAW,CAC7D,WAAU,IAAI,IAAI;OACb;AACL,OAAI,UAAU,KAAK,YAAa,QAAO;GACvC,MAAM,iBAAiB,MAAM,KAAK,QAAQ,kBAAkB,KAAK,IAAI;GACrE,MAAM,SAAS,MAAM,KAAK,QAAQ,aAAa,OAAO,EACpD,eACD,EAAC;AACF,QAAK,UAAQ,OAAO,CAClB,OAAM,IAAI,UAAU;AAEtB,OAAI,OAAO,MAAM,KACf,OAAM,IAAI,UAAU;AAEtB,aAAU,OAAO;EAClB;AAEH,MAAI,QAAQ,SAAS,KAAK,QAAQ,KAAM,QAAO;EAC/C,MAAM,SAAS,MAAM,KAAK,IAAI,WAAW,YAAY,QAAQ;AAC7D,SAAO,UAAU;CAClB;CAUD,MAAM,QACJC,SACAC,UAEqE,CAAE,GACf;EACxD,MAAM,4BAAY,IAAI;EACtB,MAAM,KAAK,GAAO,EAAE,QAAQ,UAAW,EAAC;EACxC,MAAM,MAAM,WAAW,UAAU,QAAQ,QAAQC;EACjD,MAAM,aAAa,QAAQ,cAAc;EACzC,IAAI,cAAc;AAClB,aAAW,MAAM,SAAS,QAAQ,QAAQ,KAAK,CAC7C,gBAAe;EAEjB,MAAM,OAAO,MAAM,MAAM,UAAU,QAAQ,QAAQ,KAAK,CAAC;EACzD,MAAMC,oBAA2B,CAAE;AACnC,OAAK,MAAM,OAAO,KAChB,KAAI,eAAeC,aAAW,IAAI,QAAQ,KACxC,mBAAkB,KAAK,IAAI,KAAK;AAGpC,MAAI,QAAQ,eAAe,MAAM;GAC/B,IAAI,MAAM,QAAQ,YAAY,IAAI,OAAO,QAAQ,YAAY;AAC7D,OAAI,eAAe,KAAM,OAAM,IAAI,QAAQ,QAAQ,YAAY;AAC/D,mBAAgB,+CACd,OAAO,IAAI,KAAK,CACjB,IAAI,OAAO,IAAI,KAAK,CAAC;AACtB,QAAK,KACH,IAAI,KAAK;IACP,WACE;IACF,KAAK;IACL,MAAM,QAAQ,YAAY;IAC1B,OAAO,MAAM,IAAI,KAAK;GACvB,GACF;EACF;EACD,MAAM,MAAM,IAAI,IAAI;GAClB,IAAI,KAAK,QAAQ,aAA2B,KAAK,EAAE,GAAI,EAAC;GACxD,UAAU,QAAQ,YAAY,OAC1B,CAAC,WAAY,IACb,CAAC,IAAI,eAAe,aAAa,QAAQ,WAAW,WAAY;GACpE,aAAa,QAAQ,aAAa;GAClC,UAAU,QAAQ,aAAa;GAC/B;GACA,aAAa,KAAK,QAAQ,YAAY,KAAK,IAAI,WAAW;GAC1D,aAAa,QAAQ,eAAe,CAAE;GACtC,KAAK,eAAe,WAChB,CAACC,qBAAmB,GAAG,iBAAkB,IACzC,eAAe,cAAc,eAAe,cAC5C,CACA,KAAK,QAAQ,gBAAgB,KAAK,IAAI,WAAW,EACjD,GAAG,iBACJ,IACC;GACJ,KAAK,eAAe,WAChB,CAAC,KAAK,QAAQ,gBAAgB,KAAK,IAAI,WAAW,AAAC,IACnD,eAAe,aACf,CAACA,mBAAkB,IACnB,CAAE;GACN,WAAW,UAAU,mBAAmB;GACxC,KAAK,IAAI,KAAK,WAAW,GAAG,GAAG,KAAK,QAAQ;EAC7C;EACD,MAAM,WAAW,IAAIC,SAAO;GAC1B,IAAI,KAAK,QAAQ,aAAaA,UAAQ,EAAE,GAAI,EAAC;GAC7C,QAAQ,IAAI;GACZ,KAAK,IAAI;GACT,KAAK,IAAI;GACT,QAAQ;GACR,WAAW,UAAU,mBAAmB;EACzC;AACD,QAAM,KAAK,IAAI,WAAW,WAAW,IAAI,SAAS;EAClD,MAAM,oBAAoB,eAAe,YACvC,eAAe,cAAc,eAAe;EAC9C,MAAM,kBAAkB,CAAC,IAAI,IAAI,KAAK,QAAQ,OAAQ;AACtD,MAAI,kBACF,OAAM,KAAK,QAAQ,aACjB,KAAK,KACL,aACA,UACA;GAAE;GAAmB;EAAiB,EACvC;EAEH,MAAMC,gBAAwC,CAAE;AAChD,OAAK,MAAM,gBAAgB,QAAQ,kBAAkB,EAAE;AACrD,OAAI,aAAa,MAAM,KAAM;AAC7B,iBAAc,aAAa,GAAG,QAAQ;EACvC;AACD,MAAI,kBAAkB,SAAS,GAAG;GAChC,MAAM,iBAAiB,MAAM,KAAK,QAAQ,kBAAkB,KAAK,IAAI;GACrE,MAAMC,WAAqC,CAAE;AAC7C,QAAK,MAAM,oBAAoB,mBAAmB;IAChD,MAAM,eAAe,cAAc,iBAAiB;IACpD,MAAM,UAAU,gBAAgB,OAC5B,KAAK,QAAQ,aACb,kBACA,EAAE,eAAgB,EACnB,GACC,QAAQ,QAAQ,aAAa;AACjC,aAAS,KAAK,QAAQ;GACvB;GACD,MAAM,UAAU,MAAM,QAAQ,IAAI,SAAS;GAC3C,MAAM,kBAAkB,QAAQ,OAAOC,UAAQ;AAC/C,SAAM,KAAK,QAAQ,aACjB,KAAK,KACL,iBACA,UACA;IAAE;IAAmB;GAAiB,EACvC;EACF;AACD,MAAI,QAAQ,eAAe,KACzB,OAAM,KAAK,QAAQ,aACjB,KAAK,KACL,QAAQ,YAAY,OACpB,UACA;GAAE;GAAmB;GAAiB,QAAQ;EAAQ,EACvD;AAEH,MAAI,QAAQ,eAAe,KACzB,OAAM,KAAK,QAAQ,aACjB,KAAK,KACL,QAAQ,YAAY,OACpB,UACA;GAAE;GAAmB;GAAiB,QAAQ;EAAQ,EACvD;AAEH,SAAO,MAAM,cACX,KACA,MACA,eACA,QAAQ,aACR,QAAQ,aACR,KACD;CACF;CAED,OAAO,UACLC,UAAmC,CAAE,GACyB;AAC9D,aAAW,MAAM,YAAY,KAAK,IAAI,WAAW,YAAY,QAAQ,EAAE;GACrE,IAAIC;AACJ,OAAI;AACF,aAAS,MAAM,SAAS,UAAU,KAAK,QAAQ;GAChD,QAAO;AACN;GACD;AACD,OAAI,UAAU,SAAS,gBAAgB,OAAO,CAAE;GAChD,MAAM,UAAU,MAAM,cAAc,QAAQ,MAAM,CAAE,EAAC;AACrD,SAAM;EACP;CACF;AACF"}
@@ -0,0 +1,20 @@
1
+ import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
2
+ Date.prototype.toTemporalInstant = toTemporalInstant;
3
+ import { BotImpl } from "./bot-impl.js";
4
+ import { Context } from "@fedify/fedify/federation";
5
+ import { Activity, Recipient } from "@fedify/fedify/vocab";
6
+
7
+ //#region src/session-impl.test.d.ts
8
+ interface SentActivity {
9
+ recipients: "followers" | Recipient[];
10
+ activity: Activity;
11
+ }
12
+ interface MockContext extends Context<void> {
13
+ sentActivities: SentActivity[];
14
+ }
15
+ declare function createMockContext(bot: BotImpl<void>, origin: URL | string): MockContext;
16
+ //# sourceMappingURL=session-impl.test.d.ts.map
17
+
18
+ //#endregion
19
+ export { MockContext, SentActivity, createMockContext };
20
+ //# sourceMappingURL=session-impl.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-impl.test.d.ts","names":[],"sources":["../src/session-impl.test.ts"],"sourcesContent":[],"mappings":";;;;;;;UAwqBiB,YAAA;4BACW;YAChB;;UAGK,WAAA,SAAoB;kBACnB;AANlB;AAA6B,iBASb,iBAAA,CATa,GAAA,EAUtB,OAVsB,CAAA,IAAA,CAAA,EAAA,MAAA,EAWnB,GAXmB,GAAA,MAAA,CAAA,EAY1B,WAZ0B"}