@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,464 @@
1
+
2
+ import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
3
+ Date.prototype.toTemporalInstant = toTemporalInstant;
4
+
5
+ import { createMessage } from "./message-impl.js";
6
+ import { MemoryRepository } from "./repository.js";
7
+ import { SessionImpl } from "./session-impl.js";
8
+ import { BotImpl } from "./bot-impl.js";
9
+ import { mention, text } from "./text.js";
10
+ import { MemoryKvStore } from "@fedify/fedify/federation";
11
+ import { Create, Follow, Note, PUBLIC_COLLECTION, Person, Undo } from "@fedify/fedify/vocab";
12
+ import assert from "node:assert";
13
+ import { describe, test } from "node:test";
14
+
15
+ //#region src/session-impl.test.ts
16
+ test("SessionImpl.follow()", async (t) => {
17
+ const repository = new MemoryRepository();
18
+ const bot = new BotImpl({
19
+ kv: new MemoryKvStore(),
20
+ repository,
21
+ username: "bot"
22
+ });
23
+ const ctx = createMockContext(bot, "https://example.com");
24
+ const session = new SessionImpl(bot, ctx);
25
+ await t.test("follow", async () => {
26
+ const actor = new Person({
27
+ id: new URL("https://example.com/ap/actor/john"),
28
+ preferredUsername: "john"
29
+ });
30
+ await session.follow(actor);
31
+ assert.deepStrictEqual(ctx.sentActivities.length, 1);
32
+ const { recipients, activity } = ctx.sentActivities[0];
33
+ assert.deepStrictEqual(recipients, [actor]);
34
+ assert.ok(activity instanceof Follow);
35
+ const parsed = ctx.parseUri(activity.id);
36
+ assert.deepStrictEqual(parsed?.type, "object");
37
+ assert.ok(parsed?.type === "object");
38
+ assert.deepStrictEqual(parsed.class, Follow);
39
+ assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));
40
+ assert.deepStrictEqual(activity.objectId, actor.id);
41
+ assert.deepStrictEqual(activity.toIds, [actor.id]);
42
+ const follow = await repository.getSentFollow(parsed.values.id);
43
+ assert.ok(follow != null);
44
+ assert.deepStrictEqual(await follow.toJsonLd({ format: "compact" }), await activity.toJsonLd({ format: "compact" }));
45
+ });
46
+ await t.test("follow again", async () => {
47
+ ctx.sentActivities = [];
48
+ await repository.addFollowee(new URL("https://example.com/ap/actor/alice"), new Follow({
49
+ id: new URL("https://example.com/ap/follow/4114eadb-2596-408f-ad99-06f467c9ace0"),
50
+ actor: new URL("https://example.com/ap/actor/bot"),
51
+ object: new URL("https://example.com/ap/actor/alice")
52
+ }));
53
+ const actor = new Person({
54
+ id: new URL("https://example.com/ap/actor/alice"),
55
+ preferredUsername: "alice"
56
+ });
57
+ await session.follow(actor);
58
+ assert.deepStrictEqual(ctx.sentActivities, []);
59
+ });
60
+ await t.test("follow bot itself", async () => {
61
+ ctx.sentActivities = [];
62
+ await assert.rejects(() => session.follow(session.actorId.href), TypeError, "The bot cannot follow itself.");
63
+ assert.deepStrictEqual(ctx.sentActivities, []);
64
+ await assert.rejects(() => session.follow(session.actorId), TypeError, "The bot cannot follow itself.");
65
+ assert.deepStrictEqual(ctx.sentActivities, []);
66
+ await assert.rejects(() => session.follow(session.actorHandle), TypeError, "The bot cannot follow itself.");
67
+ assert.deepStrictEqual(ctx.sentActivities, []);
68
+ const actor = await session.getActor();
69
+ await assert.rejects(() => session.follow(actor), TypeError, "The bot cannot follow itself.");
70
+ assert.deepStrictEqual(ctx.sentActivities, []);
71
+ });
72
+ });
73
+ test("SessionImpl.unfollow()", async (t) => {
74
+ const repository = new MemoryRepository();
75
+ const bot = new BotImpl({
76
+ kv: new MemoryKvStore(),
77
+ repository,
78
+ username: "bot"
79
+ });
80
+ const ctx = createMockContext(bot, "https://example.com");
81
+ const session = new SessionImpl(bot, ctx);
82
+ await t.test("unfollow", async () => {
83
+ await repository.addFollowee(new URL("https://example.com/ap/actor/alice"), new Follow({
84
+ id: new URL("https://example.com/ap/follow/4114eadb-2596-408f-ad99-06f467c9ace0"),
85
+ actor: new URL("https://example.com/ap/actor/bot"),
86
+ object: new URL("https://example.com/ap/actor/alice")
87
+ }));
88
+ const actor = new Person({
89
+ id: new URL("https://example.com/ap/actor/alice"),
90
+ preferredUsername: "alice"
91
+ });
92
+ await session.unfollow(actor);
93
+ assert.deepStrictEqual(ctx.sentActivities.length, 1);
94
+ const { recipients, activity } = ctx.sentActivities[0];
95
+ assert.deepStrictEqual(recipients, [actor]);
96
+ assert.ok(activity instanceof Undo);
97
+ const object = await activity.getObject(ctx);
98
+ assert.ok(object instanceof Follow);
99
+ assert.deepStrictEqual(object.id, new URL("https://example.com/ap/follow/4114eadb-2596-408f-ad99-06f467c9ace0"));
100
+ assert.deepStrictEqual(object.actorId, ctx.getActorUri(bot.identifier));
101
+ assert.deepStrictEqual(await repository.getFollowee(new URL("https://example.com/ap/actor/alice")), void 0);
102
+ });
103
+ await t.test("unfollow again", async () => {
104
+ ctx.sentActivities = [];
105
+ const actor = new Person({
106
+ id: new URL("https://example.com/ap/actor/alice"),
107
+ preferredUsername: "alice"
108
+ });
109
+ await session.unfollow(actor);
110
+ assert.deepStrictEqual(ctx.sentActivities, []);
111
+ });
112
+ await t.test("unfollow bot itself", async () => {
113
+ ctx.sentActivities = [];
114
+ await assert.rejects(() => session.unfollow(session.actorId.href), TypeError, "The bot cannot unfollow itself.");
115
+ assert.deepStrictEqual(ctx.sentActivities, []);
116
+ await assert.rejects(() => session.unfollow(session.actorId), TypeError, "The bot cannot unfollow itself.");
117
+ assert.deepStrictEqual(ctx.sentActivities, []);
118
+ await assert.rejects(() => session.unfollow(session.actorHandle), TypeError, "The bot cannot unfollow itself.");
119
+ assert.deepStrictEqual(ctx.sentActivities, []);
120
+ const actor = await session.getActor();
121
+ await assert.rejects(() => session.unfollow(actor), TypeError, "The bot cannot unfollow itself.");
122
+ assert.deepStrictEqual(ctx.sentActivities, []);
123
+ });
124
+ });
125
+ describe("SessionImpl.follows()", () => {
126
+ const repository = new MemoryRepository();
127
+ const bot = new BotImpl({
128
+ kv: new MemoryKvStore(),
129
+ repository,
130
+ username: "bot"
131
+ });
132
+ const ctx = createMockContext(bot, "https://example.com");
133
+ const session = new SessionImpl(bot, ctx);
134
+ test("when it follows", async () => {
135
+ const followeeId = new URL("https://example.com/ap/actor/alice");
136
+ const followee = new Person({
137
+ id: followeeId,
138
+ preferredUsername: "alice"
139
+ });
140
+ await repository.addFollowee(new URL("https://example.com/ap/actor/alice"), new Follow({
141
+ id: new URL("https://example.com/ap/follow/4114eadb-2596-408f-ad99-06f467c9ace0"),
142
+ actor: new URL("https://example.com/ap/actor/bot"),
143
+ object: followee
144
+ }));
145
+ assert.ok(await session.follows(followeeId.href));
146
+ assert.ok(await session.follows(followeeId));
147
+ assert.ok(await session.follows(followee));
148
+ });
149
+ test("when it does not follow", async () => {
150
+ const actorId = new URL("https://example.com/ap/actor/john");
151
+ const actor = new Person({
152
+ id: actorId,
153
+ preferredUsername: "john"
154
+ });
155
+ assert.deepStrictEqual(await session.follows(actorId.href), false);
156
+ assert.deepStrictEqual(await session.follows(actorId), false);
157
+ assert.deepStrictEqual(await session.follows(actor), false);
158
+ });
159
+ test("bot itself", async () => {
160
+ assert.deepStrictEqual(await session.follows(session.actorId.href), false);
161
+ assert.deepStrictEqual(await session.follows(session.actorId), false);
162
+ assert.deepStrictEqual(await session.follows(await session.getActor()), false);
163
+ assert.deepStrictEqual(await session.follows(session.actorHandle), false);
164
+ });
165
+ });
166
+ test("SessionImpl.publish()", async (t) => {
167
+ const kv = new MemoryKvStore();
168
+ const bot = new BotImpl({
169
+ kv,
170
+ username: "bot"
171
+ });
172
+ const ctx = createMockContext(bot, "https://example.com");
173
+ const session = new SessionImpl(bot, ctx);
174
+ await t.test("public", async () => {
175
+ ctx.sentActivities = [];
176
+ const publicMsg = await session.publish(text`Hello, world!`);
177
+ assert.deepStrictEqual(ctx.sentActivities.length, 1);
178
+ const { recipients, activity } = ctx.sentActivities[0];
179
+ assert.deepStrictEqual(recipients, "followers");
180
+ assert.ok(activity instanceof Create);
181
+ assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));
182
+ assert.deepStrictEqual(activity.toIds, [PUBLIC_COLLECTION]);
183
+ assert.deepStrictEqual(activity.ccIds, [ctx.getFollowersUri(bot.identifier)]);
184
+ const object = await activity.getObject(ctx);
185
+ assert.ok(object instanceof Note);
186
+ assert.deepStrictEqual(object.attributionId, ctx.getActorUri(bot.identifier));
187
+ assert.deepStrictEqual(object.toIds, [PUBLIC_COLLECTION]);
188
+ assert.deepStrictEqual(object.ccIds, [ctx.getFollowersUri(bot.identifier)]);
189
+ assert.deepStrictEqual(object.content, "<p>Hello, world!</p>");
190
+ assert.deepStrictEqual(object.tagIds, []);
191
+ assert.deepStrictEqual(publicMsg.id, object.id);
192
+ assert.deepStrictEqual(publicMsg.text, "Hello, world!");
193
+ assert.deepStrictEqual(publicMsg.html, "<p>Hello, world!</p>");
194
+ assert.deepStrictEqual(publicMsg.visibility, "public");
195
+ assert.deepStrictEqual(publicMsg.mentions, []);
196
+ });
197
+ await t.test("unlisted", async () => {
198
+ ctx.sentActivities = [];
199
+ const unlistedMsg = await session.publish(text`Hello!`, { visibility: "unlisted" });
200
+ assert.deepStrictEqual(ctx.sentActivities.length, 1);
201
+ const { recipients, activity } = ctx.sentActivities[0];
202
+ assert.deepStrictEqual(recipients, "followers");
203
+ assert.ok(activity instanceof Create);
204
+ assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));
205
+ assert.deepStrictEqual(activity.toIds, [ctx.getFollowersUri(bot.identifier)]);
206
+ assert.deepStrictEqual(activity.ccIds, [PUBLIC_COLLECTION]);
207
+ const object = await activity.getObject(ctx);
208
+ assert.ok(object instanceof Note);
209
+ assert.deepStrictEqual(object.attributionId, ctx.getActorUri(bot.identifier));
210
+ assert.deepStrictEqual(object.toIds, [ctx.getFollowersUri(bot.identifier)]);
211
+ assert.deepStrictEqual(object.ccIds, [PUBLIC_COLLECTION]);
212
+ assert.deepStrictEqual(object.content, "<p>Hello!</p>");
213
+ assert.deepStrictEqual(object.tagIds, []);
214
+ assert.deepStrictEqual(unlistedMsg.id, object.id);
215
+ assert.deepStrictEqual(unlistedMsg.text, "Hello!");
216
+ assert.deepStrictEqual(unlistedMsg.html, "<p>Hello!</p>");
217
+ assert.deepStrictEqual(unlistedMsg.visibility, "unlisted");
218
+ assert.deepStrictEqual(unlistedMsg.mentions, []);
219
+ });
220
+ await t.test("followers", async () => {
221
+ ctx.sentActivities = [];
222
+ const followersMsg = await session.publish(text`Hi!`, { visibility: "followers" });
223
+ assert.deepStrictEqual(ctx.sentActivities.length, 1);
224
+ const { recipients, activity } = ctx.sentActivities[0];
225
+ assert.deepStrictEqual(recipients, "followers");
226
+ assert.ok(activity instanceof Create);
227
+ assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));
228
+ assert.deepStrictEqual(activity.toIds, [ctx.getFollowersUri(bot.identifier)]);
229
+ assert.deepStrictEqual(activity.ccIds, []);
230
+ const object = await activity.getObject(ctx);
231
+ assert.ok(object instanceof Note);
232
+ assert.deepStrictEqual(object.attributionId, ctx.getActorUri(bot.identifier));
233
+ assert.deepStrictEqual(object.toIds, [ctx.getFollowersUri(bot.identifier)]);
234
+ assert.deepStrictEqual(object.ccIds, []);
235
+ assert.deepStrictEqual(object.content, "<p>Hi!</p>");
236
+ assert.deepStrictEqual(object.tagIds, []);
237
+ assert.deepStrictEqual(followersMsg.id, object.id);
238
+ assert.deepStrictEqual(followersMsg.text, "Hi!");
239
+ assert.deepStrictEqual(followersMsg.html, "<p>Hi!</p>");
240
+ assert.deepStrictEqual(followersMsg.visibility, "followers");
241
+ assert.deepStrictEqual(followersMsg.mentions, []);
242
+ });
243
+ await t.test("direct", async () => {
244
+ const mentioned = new Person({
245
+ id: new URL("https://example.com/ap/actor/john"),
246
+ preferredUsername: "john"
247
+ });
248
+ ctx.sentActivities = [];
249
+ const directMsg = await session.publish(text`Hey ${mention(mentioned)}!`, { visibility: "direct" });
250
+ assert.deepStrictEqual(ctx.sentActivities.length, 1);
251
+ const { recipients, activity } = ctx.sentActivities[0];
252
+ assert.deepStrictEqual(recipients, [mentioned]);
253
+ assert.ok(activity instanceof Create);
254
+ assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));
255
+ assert.deepStrictEqual(activity.toIds, [mentioned.id]);
256
+ assert.deepStrictEqual(activity.ccIds, []);
257
+ const object = await activity.getObject(ctx);
258
+ assert.ok(object instanceof Note);
259
+ assert.deepStrictEqual(object.attributionId, ctx.getActorUri(bot.identifier));
260
+ assert.deepStrictEqual(object.toIds, [mentioned.id]);
261
+ assert.deepStrictEqual(object.ccIds, []);
262
+ assert.deepStrictEqual(object.content, "<p>Hey <a href=\"https://example.com/ap/actor/john\" translate=\"no\" class=\"h-card u-url mention\" target=\"_blank\">@<span>john@example.com</span></a>!</p>");
263
+ const tags = await Array.fromAsync(object.getTags());
264
+ assert.deepStrictEqual(tags.length, 1);
265
+ assert.deepStrictEqual(directMsg.id, object.id);
266
+ assert.deepStrictEqual(directMsg.text, "Hey @john@example.com!");
267
+ assert.deepStrictEqual(directMsg.html, object.content);
268
+ assert.deepStrictEqual(directMsg.visibility, "direct");
269
+ });
270
+ await t.test("quote", async () => {
271
+ const originalAuthor = new Person({
272
+ id: new URL("https://example.com/ap/actor/john"),
273
+ preferredUsername: "john"
274
+ });
275
+ const originalPost = new Note({
276
+ id: new URL("https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788"),
277
+ content: "<p>Hello, world!</p>",
278
+ attribution: originalAuthor,
279
+ to: new URL("https://example.com/ap/actor/john/followers"),
280
+ cc: PUBLIC_COLLECTION
281
+ });
282
+ const originalMsg = await createMessage(originalPost, session, {});
283
+ ctx.sentActivities = [];
284
+ const quote = await session.publish(text`Check this out!`, { quoteTarget: originalMsg });
285
+ assert.deepStrictEqual(ctx.sentActivities.length, 2);
286
+ const { recipients, activity } = ctx.sentActivities[0];
287
+ assert.deepStrictEqual(recipients, "followers");
288
+ assert.ok(activity instanceof Create);
289
+ assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));
290
+ assert.deepStrictEqual(activity.toIds, [PUBLIC_COLLECTION]);
291
+ assert.deepStrictEqual(activity.ccIds, [ctx.getFollowersUri(bot.identifier)]);
292
+ const object = await activity.getObject(ctx);
293
+ const { recipients: recipients2, activity: activity2 } = ctx.sentActivities[1];
294
+ assert.deepStrictEqual(recipients2, [originalAuthor]);
295
+ assert.ok(activity2 instanceof Create);
296
+ assert.deepStrictEqual(activity2.actorId, ctx.getActorUri(bot.identifier));
297
+ assert.deepStrictEqual(activity2.toIds, [PUBLIC_COLLECTION]);
298
+ assert.deepStrictEqual(activity2.ccIds, [ctx.getFollowersUri(bot.identifier)]);
299
+ assert.ok(object instanceof Note);
300
+ assert.deepStrictEqual(object.attributionId, ctx.getActorUri(bot.identifier));
301
+ assert.deepStrictEqual(object.toIds, [PUBLIC_COLLECTION]);
302
+ assert.deepStrictEqual(object.ccIds, [ctx.getFollowersUri(bot.identifier)]);
303
+ assert.deepStrictEqual(object.content, `<p>Check this out!</p>
304
+
305
+ <p class="quote-inline"><br>RE: <a href="${originalMsg.id.href}">${originalMsg.id.href}</a></p>`);
306
+ assert.deepStrictEqual(object.quoteUrl, originalMsg.id);
307
+ assert.deepStrictEqual(quote.id, object.id);
308
+ assert.deepStrictEqual(quote.text, `Check this out!\n\nRE: ${originalMsg.id.href}`);
309
+ assert.deepStrictEqual(quote.html, `<p>Check this out!</p>
310
+
311
+ <p><br>RE: <a href="${originalMsg.id.href}">${originalMsg.id.href}</a></p>`);
312
+ assert.deepStrictEqual(quote.visibility, "public");
313
+ assert.deepStrictEqual(quote.quoteTarget?.id, originalMsg.id);
314
+ });
315
+ });
316
+ test("SessionImpl.getOutbox()", async (t) => {
317
+ const repository = new MemoryRepository();
318
+ const bot = new BotImpl({
319
+ kv: new MemoryKvStore(),
320
+ repository,
321
+ username: "bot"
322
+ });
323
+ const ctx = createMockContext(bot, "https://example.com");
324
+ const session = new SessionImpl(bot, ctx);
325
+ const messageA = new Create({
326
+ id: new URL("https://example.com/ap/create/01941f29-7c00-7fe8-ab0a-7b593990a3c0"),
327
+ actor: new URL("https://example.com/ap/actor/bot"),
328
+ to: new URL("https://example.com/ap/actor/bot/followers"),
329
+ cc: PUBLIC_COLLECTION,
330
+ object: new Note({
331
+ id: new URL("https://example.com/ap/note/01941f29-7c00-7fe8-ab0a-7b593990a3c0"),
332
+ attribution: new URL("https://example.com/ap/actor/bot"),
333
+ to: new URL("https://example.com/ap/actor/bot/followers"),
334
+ cc: PUBLIC_COLLECTION,
335
+ content: "Hello, world!",
336
+ published: Temporal.Instant.from("2025-01-01T00:00:00Z")
337
+ }),
338
+ published: Temporal.Instant.from("2025-01-01T00:00:00Z")
339
+ });
340
+ const messageB = new Create({
341
+ id: new URL("https://example.com/ap/create/0194244f-d800-7873-8993-ef71ccd47306"),
342
+ actor: new URL("https://example.com/ap/actor/bot"),
343
+ to: new URL("https://example.com/ap/actor/bot/followers"),
344
+ cc: PUBLIC_COLLECTION,
345
+ object: new Note({
346
+ id: new URL("https://example.com/ap/note/0194244f-d800-7873-8993-ef71ccd47306"),
347
+ attribution: new URL("https://example.com/ap/actor/bot"),
348
+ to: new URL("https://example.com/ap/actor/bot/followers"),
349
+ cc: PUBLIC_COLLECTION,
350
+ content: "Hello, world!",
351
+ published: Temporal.Instant.from("2025-01-02T00:00:00Z")
352
+ }),
353
+ published: Temporal.Instant.from("2025-01-02T00:00:00Z")
354
+ });
355
+ const messageC = new Create({
356
+ id: new URL("https://example.com/ap/create/01942976-3400-7f34-872e-2cbf0f9eeac4"),
357
+ actor: new URL("https://example.com/ap/actor/bot"),
358
+ to: new URL("https://example.com/ap/actor/bot/followers"),
359
+ cc: PUBLIC_COLLECTION,
360
+ object: new Note({
361
+ id: new URL("https://example.com/ap/note/01942976-3400-7f34-872e-2cbf0f9eeac4"),
362
+ attribution: new URL("https://example.com/ap/actor/bot"),
363
+ to: new URL("https://example.com/ap/actor/bot/followers"),
364
+ cc: PUBLIC_COLLECTION,
365
+ content: "Hello, world!",
366
+ published: Temporal.Instant.from("2025-01-03T00:00:00Z")
367
+ }),
368
+ published: Temporal.Instant.from("2025-01-03T00:00:00Z")
369
+ });
370
+ const messageD = new Create({
371
+ id: new URL("https://example.com/ap/create/01942e9c-9000-7480-a553-7a6ce737ce14"),
372
+ actor: new URL("https://example.com/ap/actor/bot"),
373
+ to: new URL("https://example.com/ap/actor/bot/followers"),
374
+ cc: PUBLIC_COLLECTION,
375
+ object: new Note({
376
+ id: new URL("https://example.com/ap/note/01942e9c-9000-7480-a553-7a6ce737ce14"),
377
+ attribution: new URL("https://example.com/ap/actor/bot"),
378
+ to: new URL("https://example.com/ap/actor/bot/followers"),
379
+ cc: PUBLIC_COLLECTION,
380
+ content: "Hello, world!",
381
+ published: Temporal.Instant.from("2025-01-04T00:00:00Z")
382
+ }),
383
+ published: Temporal.Instant.from("2025-01-04T00:00:00Z")
384
+ });
385
+ await repository.addMessage("01941f29-7c00-7fe8-ab0a-7b593990a3c0", messageA);
386
+ await repository.addMessage("0194244f-d800-7873-8993-ef71ccd47306", messageB);
387
+ await repository.addMessage("01942976-3400-7f34-872e-2cbf0f9eeac4", messageC);
388
+ await repository.addMessage("01942e9c-9000-7480-a553-7a6ce737ce14", messageD);
389
+ await t.test("default", async () => {
390
+ const outbox = session.getOutbox({ order: "oldest" });
391
+ const messages = await Array.fromAsync(outbox);
392
+ assert.deepStrictEqual(messages.length, 4);
393
+ assert.deepStrictEqual(messages[0].id.href, "https://example.com/ap/note/01941f29-7c00-7fe8-ab0a-7b593990a3c0");
394
+ assert.deepStrictEqual(messages[0].actor.id?.href, "https://example.com/ap/actor/bot");
395
+ assert.deepStrictEqual(messages[0].visibility, "unlisted");
396
+ assert.deepStrictEqual(messages[0].text, "Hello, world!");
397
+ assert.deepStrictEqual(messages[0].published, Temporal.Instant.from("2025-01-01T00:00:00Z"));
398
+ assert.deepStrictEqual(messages[1].id.href, "https://example.com/ap/note/0194244f-d800-7873-8993-ef71ccd47306");
399
+ assert.deepStrictEqual(messages[1].actor.id?.href, "https://example.com/ap/actor/bot");
400
+ assert.deepStrictEqual(messages[1].visibility, "unlisted");
401
+ assert.deepStrictEqual(messages[1].text, "Hello, world!");
402
+ assert.deepStrictEqual(messages[1].published, Temporal.Instant.from("2025-01-02T00:00:00Z"));
403
+ assert.deepStrictEqual(messages[2].id.href, "https://example.com/ap/note/01942976-3400-7f34-872e-2cbf0f9eeac4");
404
+ assert.deepStrictEqual(messages[2].actor.id?.href, "https://example.com/ap/actor/bot");
405
+ assert.deepStrictEqual(messages[2].visibility, "unlisted");
406
+ assert.deepStrictEqual(messages[2].text, "Hello, world!");
407
+ assert.deepStrictEqual(messages[2].published, Temporal.Instant.from("2025-01-03T00:00:00Z"));
408
+ assert.deepStrictEqual(messages[3].id.href, "https://example.com/ap/note/01942e9c-9000-7480-a553-7a6ce737ce14");
409
+ assert.deepStrictEqual(messages[3].actor.id?.href, "https://example.com/ap/actor/bot");
410
+ assert.deepStrictEqual(messages[3].visibility, "unlisted");
411
+ assert.deepStrictEqual(messages[3].text, "Hello, world!");
412
+ assert.deepStrictEqual(messages[3].published, Temporal.Instant.from("2025-01-04T00:00:00Z"));
413
+ });
414
+ await t.test("order: 'oldest'", async () => {
415
+ const outbox = session.getOutbox({ order: "oldest" });
416
+ const messages = await Array.fromAsync(outbox);
417
+ const messageIds = messages.map((msg) => msg.id.href);
418
+ assert.deepStrictEqual(messageIds, [
419
+ "https://example.com/ap/note/01941f29-7c00-7fe8-ab0a-7b593990a3c0",
420
+ "https://example.com/ap/note/0194244f-d800-7873-8993-ef71ccd47306",
421
+ "https://example.com/ap/note/01942976-3400-7f34-872e-2cbf0f9eeac4",
422
+ "https://example.com/ap/note/01942e9c-9000-7480-a553-7a6ce737ce14"
423
+ ]);
424
+ });
425
+ await t.test("order: 'newest'", async () => {
426
+ const outbox = session.getOutbox({ order: "newest" });
427
+ const messages = await Array.fromAsync(outbox);
428
+ const messageIds = messages.map((msg) => msg.id.href);
429
+ assert.deepStrictEqual(messageIds, [
430
+ "https://example.com/ap/note/01942e9c-9000-7480-a553-7a6ce737ce14",
431
+ "https://example.com/ap/note/01942976-3400-7f34-872e-2cbf0f9eeac4",
432
+ "https://example.com/ap/note/0194244f-d800-7873-8993-ef71ccd47306",
433
+ "https://example.com/ap/note/01941f29-7c00-7fe8-ab0a-7b593990a3c0"
434
+ ]);
435
+ });
436
+ await t.test("since", async () => {
437
+ const outbox = session.getOutbox({ since: Temporal.Instant.from("2025-01-03T00:00:00Z") });
438
+ const messages = await Array.fromAsync(outbox);
439
+ const messageIds = messages.map((msg) => msg.id.href);
440
+ assert.deepStrictEqual(messageIds, ["https://example.com/ap/note/01942e9c-9000-7480-a553-7a6ce737ce14", "https://example.com/ap/note/01942976-3400-7f34-872e-2cbf0f9eeac4"]);
441
+ });
442
+ await t.test("until", async () => {
443
+ const outbox = session.getOutbox({ until: Temporal.Instant.from("2025-01-02T00:00:00Z") });
444
+ const messages = await Array.fromAsync(outbox);
445
+ const messageIds = messages.map((msg) => msg.id.href);
446
+ assert.deepStrictEqual(messageIds, ["https://example.com/ap/note/0194244f-d800-7873-8993-ef71ccd47306", "https://example.com/ap/note/01941f29-7c00-7fe8-ab0a-7b593990a3c0"]);
447
+ });
448
+ });
449
+ function createMockContext(bot, origin) {
450
+ const ctx = bot.federation.createContext(new URL(origin), void 0);
451
+ ctx.sentActivities = [];
452
+ ctx.sendActivity = (_, recipients, activity) => {
453
+ ctx.sentActivities.push({
454
+ recipients: recipients === "followers" ? "followers" : Array.isArray(recipients) ? recipients : [recipients],
455
+ activity
456
+ });
457
+ return Promise.resolve();
458
+ };
459
+ return ctx;
460
+ }
461
+
462
+ //#endregion
463
+ export { createMockContext };
464
+ //# sourceMappingURL=session-impl.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-impl.test.js","names":["bot: BotImpl<void>","origin: URL | string"],"sources":["../src/session-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 Context, MemoryKvStore } from \"@fedify/fedify/federation\";\nimport {\n type Activity,\n Create,\n Follow,\n Note,\n Person,\n PUBLIC_COLLECTION,\n type Recipient,\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 { createMessage } from \"./message-impl.ts\";\nimport { MemoryRepository, type Uuid } from \"./repository.ts\";\nimport { SessionImpl } from \"./session-impl.ts\";\nimport { mention, text } from \"./text.ts\";\n\ntest(\"SessionImpl.follow()\", 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 ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n await t.test(\"follow\", async () => {\n const actor = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n await session.follow(actor);\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [actor]);\n assert.ok(activity instanceof Follow);\n const parsed = ctx.parseUri(activity.id);\n assert.deepStrictEqual(parsed?.type, \"object\");\n assert.ok(parsed?.type === \"object\");\n assert.deepStrictEqual(parsed.class, Follow);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.objectId, actor.id);\n assert.deepStrictEqual(activity.toIds, [actor.id]);\n const follow = await repository.getSentFollow(parsed.values.id as Uuid);\n assert.ok(follow != null);\n assert.deepStrictEqual(\n await follow.toJsonLd({ format: \"compact\" }),\n await activity.toJsonLd({ format: \"compact\" }),\n );\n });\n\n await t.test(\"follow again\", async () => {\n ctx.sentActivities = [];\n await repository.addFollowee(\n new URL(\"https://example.com/ap/actor/alice\"),\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/4114eadb-2596-408f-ad99-06f467c9ace0\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new URL(\"https://example.com/ap/actor/alice\"),\n }),\n );\n const actor = new Person({\n id: new URL(\"https://example.com/ap/actor/alice\"),\n preferredUsername: \"alice\",\n });\n await session.follow(actor);\n assert.deepStrictEqual(ctx.sentActivities, []);\n });\n\n await t.test(\"follow bot itself\", async () => {\n ctx.sentActivities = [];\n await assert.rejects(\n () => session.follow(session.actorId.href),\n TypeError,\n \"The bot cannot follow itself.\",\n );\n assert.deepStrictEqual(ctx.sentActivities, []);\n\n await assert.rejects(\n () => session.follow(session.actorId),\n TypeError,\n \"The bot cannot follow itself.\",\n );\n assert.deepStrictEqual(ctx.sentActivities, []);\n\n await assert.rejects(\n () => session.follow(session.actorHandle),\n TypeError,\n \"The bot cannot follow itself.\",\n );\n assert.deepStrictEqual(ctx.sentActivities, []);\n\n const actor = await session.getActor();\n await assert.rejects(\n () => session.follow(actor),\n TypeError,\n \"The bot cannot follow itself.\",\n );\n assert.deepStrictEqual(ctx.sentActivities, []);\n });\n});\n\ntest(\"SessionImpl.unfollow()\", 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 ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n await t.test(\"unfollow\", async () => {\n await repository.addFollowee(\n new URL(\"https://example.com/ap/actor/alice\"),\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/4114eadb-2596-408f-ad99-06f467c9ace0\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: new URL(\"https://example.com/ap/actor/alice\"),\n }),\n );\n const actor = new Person({\n id: new URL(\"https://example.com/ap/actor/alice\"),\n preferredUsername: \"alice\",\n });\n await session.unfollow(actor);\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [actor]);\n assert.ok(activity instanceof Undo);\n const object = await activity.getObject(ctx);\n assert.ok(object instanceof Follow);\n assert.deepStrictEqual(\n object.id,\n new URL(\n \"https://example.com/ap/follow/4114eadb-2596-408f-ad99-06f467c9ace0\",\n ),\n );\n assert.deepStrictEqual(object.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(\n await repository.getFollowee(\n new URL(\"https://example.com/ap/actor/alice\"),\n ),\n undefined,\n );\n });\n\n await t.test(\"unfollow again\", async () => {\n ctx.sentActivities = [];\n const actor = new Person({\n id: new URL(\"https://example.com/ap/actor/alice\"),\n preferredUsername: \"alice\",\n });\n await session.unfollow(actor);\n assert.deepStrictEqual(ctx.sentActivities, []);\n });\n\n await t.test(\"unfollow bot itself\", async () => {\n ctx.sentActivities = [];\n await assert.rejects(\n () => session.unfollow(session.actorId.href),\n TypeError,\n \"The bot cannot unfollow itself.\",\n );\n assert.deepStrictEqual(ctx.sentActivities, []);\n\n await assert.rejects(\n () => session.unfollow(session.actorId),\n TypeError,\n \"The bot cannot unfollow itself.\",\n );\n assert.deepStrictEqual(ctx.sentActivities, []);\n\n await assert.rejects(\n () => session.unfollow(session.actorHandle),\n TypeError,\n \"The bot cannot unfollow itself.\",\n );\n assert.deepStrictEqual(ctx.sentActivities, []);\n\n const actor = await session.getActor();\n await assert.rejects(\n () => session.unfollow(actor),\n TypeError,\n \"The bot cannot unfollow itself.\",\n );\n assert.deepStrictEqual(ctx.sentActivities, []);\n });\n});\n\ndescribe(\"SessionImpl.follows()\", () => {\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 test(\"when it follows\", async () => {\n const followeeId = new URL(\"https://example.com/ap/actor/alice\");\n const followee = new Person({\n id: followeeId,\n preferredUsername: \"alice\",\n });\n await repository.addFollowee(\n new URL(\"https://example.com/ap/actor/alice\"),\n new Follow({\n id: new URL(\n \"https://example.com/ap/follow/4114eadb-2596-408f-ad99-06f467c9ace0\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n object: followee,\n }),\n );\n assert.ok(await session.follows(followeeId.href));\n assert.ok(await session.follows(followeeId));\n assert.ok(await session.follows(followee));\n });\n\n test(\"when it does not follow\", async () => {\n const actorId = new URL(\"https://example.com/ap/actor/john\");\n const actor = new Person({\n id: actorId,\n preferredUsername: \"john\",\n });\n assert.deepStrictEqual(await session.follows(actorId.href), false);\n assert.deepStrictEqual(await session.follows(actorId), false);\n assert.deepStrictEqual(await session.follows(actor), false);\n });\n\n test(\"bot itself\", async () => {\n assert.deepStrictEqual(await session.follows(session.actorId.href), false);\n assert.deepStrictEqual(await session.follows(session.actorId), false);\n assert.deepStrictEqual(\n await session.follows(await session.getActor()),\n false,\n );\n assert.deepStrictEqual(await session.follows(session.actorHandle), false);\n });\n});\n\ntest(\"SessionImpl.publish()\", async (t) => {\n const kv = new MemoryKvStore();\n const bot = new BotImpl<void>({ kv, username: \"bot\" });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n await t.test(\"public\", async () => {\n ctx.sentActivities = [];\n const publicMsg = await session.publish(text`Hello, world!`);\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Create);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.toIds, [PUBLIC_COLLECTION]);\n assert.deepStrictEqual(activity.ccIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n const object = await activity.getObject(ctx);\n assert.ok(object instanceof Note);\n assert.deepStrictEqual(\n object.attributionId,\n ctx.getActorUri(bot.identifier),\n );\n assert.deepStrictEqual(object.toIds, [PUBLIC_COLLECTION]);\n assert.deepStrictEqual(object.ccIds, [ctx.getFollowersUri(bot.identifier)]);\n assert.deepStrictEqual(object.content, \"<p>Hello, world!</p>\");\n assert.deepStrictEqual(object.tagIds, []);\n assert.deepStrictEqual(publicMsg.id, object.id);\n assert.deepStrictEqual(publicMsg.text, \"Hello, world!\");\n assert.deepStrictEqual(publicMsg.html, \"<p>Hello, world!</p>\");\n assert.deepStrictEqual(publicMsg.visibility, \"public\");\n assert.deepStrictEqual(publicMsg.mentions, []);\n });\n\n await t.test(\"unlisted\", async () => {\n ctx.sentActivities = [];\n const unlistedMsg = await session.publish(text`Hello!`, {\n visibility: \"unlisted\",\n });\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Create);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.toIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.deepStrictEqual(activity.ccIds, [PUBLIC_COLLECTION]);\n const object = await activity.getObject(ctx);\n assert.ok(object instanceof Note);\n assert.deepStrictEqual(\n object.attributionId,\n ctx.getActorUri(bot.identifier),\n );\n assert.deepStrictEqual(object.toIds, [ctx.getFollowersUri(bot.identifier)]);\n assert.deepStrictEqual(object.ccIds, [PUBLIC_COLLECTION]);\n assert.deepStrictEqual(object.content, \"<p>Hello!</p>\");\n assert.deepStrictEqual(object.tagIds, []);\n assert.deepStrictEqual(unlistedMsg.id, object.id);\n assert.deepStrictEqual(unlistedMsg.text, \"Hello!\");\n assert.deepStrictEqual(unlistedMsg.html, \"<p>Hello!</p>\");\n assert.deepStrictEqual(unlistedMsg.visibility, \"unlisted\");\n assert.deepStrictEqual(unlistedMsg.mentions, []);\n });\n\n await t.test(\"followers\", async () => {\n ctx.sentActivities = [];\n const followersMsg = await session.publish(text`Hi!`, {\n visibility: \"followers\",\n });\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Create);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.toIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.deepStrictEqual(activity.ccIds, []);\n const object = await activity.getObject(ctx);\n assert.ok(object instanceof Note);\n assert.deepStrictEqual(\n object.attributionId,\n ctx.getActorUri(bot.identifier),\n );\n assert.deepStrictEqual(object.toIds, [ctx.getFollowersUri(bot.identifier)]);\n assert.deepStrictEqual(object.ccIds, []);\n assert.deepStrictEqual(object.content, \"<p>Hi!</p>\");\n assert.deepStrictEqual(object.tagIds, []);\n assert.deepStrictEqual(followersMsg.id, object.id);\n assert.deepStrictEqual(followersMsg.text, \"Hi!\");\n assert.deepStrictEqual(followersMsg.html, \"<p>Hi!</p>\");\n assert.deepStrictEqual(followersMsg.visibility, \"followers\");\n assert.deepStrictEqual(followersMsg.mentions, []);\n });\n\n await t.test(\"direct\", async () => {\n const mentioned = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n ctx.sentActivities = [];\n const directMsg = await session.publish(\n text`Hey ${mention(mentioned)}!`,\n { visibility: \"direct\" },\n );\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, [mentioned]);\n assert.ok(activity instanceof Create);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.toIds, [mentioned.id]);\n assert.deepStrictEqual(activity.ccIds, []);\n const object = await activity.getObject(ctx);\n assert.ok(object instanceof Note);\n assert.deepStrictEqual(\n object.attributionId,\n ctx.getActorUri(bot.identifier),\n );\n assert.deepStrictEqual(object.toIds, [mentioned.id]);\n assert.deepStrictEqual(object.ccIds, []);\n assert.deepStrictEqual(\n object.content,\n '<p>Hey <a href=\"https://example.com/ap/actor/john\" translate=\"no\" ' +\n 'class=\"h-card u-url mention\" target=\"_blank\">@<span>john@example.com' +\n \"</span></a>!</p>\",\n );\n const tags = await Array.fromAsync(object.getTags());\n assert.deepStrictEqual(tags.length, 1);\n assert.deepStrictEqual(directMsg.id, object.id);\n assert.deepStrictEqual(directMsg.text, \"Hey @john@example.com!\");\n assert.deepStrictEqual(directMsg.html, object.content);\n assert.deepStrictEqual(directMsg.visibility, \"direct\");\n // assert.deepStrictEqual(directMsg.mentions, [mentioned]); // FIXME\n });\n\n await t.test(\"quote\", async () => {\n const originalAuthor = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const originalPost = new Note({\n id: new URL(\n \"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n content: \"<p>Hello, world!</p>\",\n attribution: originalAuthor,\n to: new URL(\"https://example.com/ap/actor/john/followers\"),\n cc: PUBLIC_COLLECTION,\n });\n const originalMsg = await createMessage<Note, void>(\n originalPost,\n session,\n {},\n );\n ctx.sentActivities = [];\n const quote = await session.publish(text`Check this out!`, {\n quoteTarget: originalMsg,\n });\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Create);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.toIds, [PUBLIC_COLLECTION]);\n assert.deepStrictEqual(activity.ccIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n const object = await activity.getObject(ctx);\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [originalAuthor]);\n assert.ok(activity2 instanceof Create);\n assert.deepStrictEqual(activity2.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity2.toIds, [PUBLIC_COLLECTION]);\n assert.deepStrictEqual(activity2.ccIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.ok(object instanceof Note);\n assert.deepStrictEqual(\n object.attributionId,\n ctx.getActorUri(bot.identifier),\n );\n assert.deepStrictEqual(object.toIds, [PUBLIC_COLLECTION]);\n assert.deepStrictEqual(object.ccIds, [ctx.getFollowersUri(bot.identifier)]);\n assert.deepStrictEqual(\n object.content,\n `<p>Check this out!</p>\n\n<p class=\"quote-inline\"><br>RE: <a href=\"${originalMsg.id.href}\">${originalMsg.id.href}</a></p>`,\n );\n assert.deepStrictEqual(object.quoteUrl, originalMsg.id);\n assert.deepStrictEqual(quote.id, object.id);\n assert.deepStrictEqual(\n quote.text,\n `Check this out!\\n\\nRE: ${originalMsg.id.href}`,\n );\n assert.deepStrictEqual(\n quote.html,\n `<p>Check this out!</p>\n\n<p><br>RE: <a href=\"${originalMsg.id.href}\">${originalMsg.id.href}</a></p>`,\n );\n assert.deepStrictEqual(quote.visibility, \"public\");\n assert.deepStrictEqual(quote.quoteTarget?.id, originalMsg.id);\n });\n});\n\ntest(\"SessionImpl.getOutbox()\", 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 ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n const messageA = new Create({\n id: new URL(\n \"https://example.com/ap/create/01941f29-7c00-7fe8-ab0a-7b593990a3c0\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\n object: new Note({\n id: new URL(\n \"https://example.com/ap/note/01941f29-7c00-7fe8-ab0a-7b593990a3c0\",\n ),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\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 const messageB = new Create({\n id: new URL(\n \"https://example.com/ap/create/0194244f-d800-7873-8993-ef71ccd47306\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\n object: new Note({\n id: new URL(\n \"https://example.com/ap/note/0194244f-d800-7873-8993-ef71ccd47306\",\n ),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\n content: \"Hello, world!\",\n published: Temporal.Instant.from(\"2025-01-02T00:00:00Z\"),\n }),\n published: Temporal.Instant.from(\"2025-01-02T00:00:00Z\"),\n });\n const messageC = new Create({\n id: new URL(\n \"https://example.com/ap/create/01942976-3400-7f34-872e-2cbf0f9eeac4\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\n object: new Note({\n id: new URL(\n \"https://example.com/ap/note/01942976-3400-7f34-872e-2cbf0f9eeac4\",\n ),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\n content: \"Hello, world!\",\n published: Temporal.Instant.from(\"2025-01-03T00:00:00Z\"),\n }),\n published: Temporal.Instant.from(\"2025-01-03T00:00:00Z\"),\n });\n const messageD = new Create({\n id: new URL(\n \"https://example.com/ap/create/01942e9c-9000-7480-a553-7a6ce737ce14\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\n object: new Note({\n id: new URL(\n \"https://example.com/ap/note/01942e9c-9000-7480-a553-7a6ce737ce14\",\n ),\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\n content: \"Hello, world!\",\n published: Temporal.Instant.from(\"2025-01-04T00:00:00Z\"),\n }),\n published: Temporal.Instant.from(\"2025-01-04T00:00:00Z\"),\n });\n await repository.addMessage(\"01941f29-7c00-7fe8-ab0a-7b593990a3c0\", messageA);\n await repository.addMessage(\"0194244f-d800-7873-8993-ef71ccd47306\", messageB);\n await repository.addMessage(\"01942976-3400-7f34-872e-2cbf0f9eeac4\", messageC);\n await repository.addMessage(\"01942e9c-9000-7480-a553-7a6ce737ce14\", messageD);\n\n await t.test(\"default\", async () => {\n const outbox = session.getOutbox({ order: \"oldest\" });\n const messages = await Array.fromAsync(outbox);\n assert.deepStrictEqual(messages.length, 4);\n\n assert.deepStrictEqual(\n messages[0].id.href,\n \"https://example.com/ap/note/01941f29-7c00-7fe8-ab0a-7b593990a3c0\",\n );\n assert.deepStrictEqual(\n messages[0].actor.id?.href,\n \"https://example.com/ap/actor/bot\",\n );\n assert.deepStrictEqual(messages[0].visibility, \"unlisted\");\n assert.deepStrictEqual(messages[0].text, \"Hello, world!\");\n assert.deepStrictEqual(\n messages[0].published,\n Temporal.Instant.from(\"2025-01-01T00:00:00Z\"),\n );\n\n assert.deepStrictEqual(\n messages[1].id.href,\n \"https://example.com/ap/note/0194244f-d800-7873-8993-ef71ccd47306\",\n );\n assert.deepStrictEqual(\n messages[1].actor.id?.href,\n \"https://example.com/ap/actor/bot\",\n );\n assert.deepStrictEqual(messages[1].visibility, \"unlisted\");\n assert.deepStrictEqual(messages[1].text, \"Hello, world!\");\n assert.deepStrictEqual(\n messages[1].published,\n Temporal.Instant.from(\"2025-01-02T00:00:00Z\"),\n );\n\n assert.deepStrictEqual(\n messages[2].id.href,\n \"https://example.com/ap/note/01942976-3400-7f34-872e-2cbf0f9eeac4\",\n );\n assert.deepStrictEqual(\n messages[2].actor.id?.href,\n \"https://example.com/ap/actor/bot\",\n );\n assert.deepStrictEqual(messages[2].visibility, \"unlisted\");\n assert.deepStrictEqual(messages[2].text, \"Hello, world!\");\n assert.deepStrictEqual(\n messages[2].published,\n Temporal.Instant.from(\"2025-01-03T00:00:00Z\"),\n );\n\n assert.deepStrictEqual(\n messages[3].id.href,\n \"https://example.com/ap/note/01942e9c-9000-7480-a553-7a6ce737ce14\",\n );\n assert.deepStrictEqual(\n messages[3].actor.id?.href,\n \"https://example.com/ap/actor/bot\",\n );\n assert.deepStrictEqual(messages[3].visibility, \"unlisted\");\n assert.deepStrictEqual(messages[3].text, \"Hello, world!\");\n assert.deepStrictEqual(\n messages[3].published,\n Temporal.Instant.from(\"2025-01-04T00:00:00Z\"),\n );\n });\n\n await t.test(\"order: 'oldest'\", async () => {\n const outbox = session.getOutbox({ order: \"oldest\" });\n const messages = await Array.fromAsync(outbox);\n const messageIds = messages.map((msg) => msg.id.href);\n assert.deepStrictEqual(messageIds, [\n \"https://example.com/ap/note/01941f29-7c00-7fe8-ab0a-7b593990a3c0\",\n \"https://example.com/ap/note/0194244f-d800-7873-8993-ef71ccd47306\",\n \"https://example.com/ap/note/01942976-3400-7f34-872e-2cbf0f9eeac4\",\n \"https://example.com/ap/note/01942e9c-9000-7480-a553-7a6ce737ce14\",\n ]);\n });\n\n await t.test(\"order: 'newest'\", async () => {\n const outbox = session.getOutbox({ order: \"newest\" });\n const messages = await Array.fromAsync(outbox);\n const messageIds = messages.map((msg) => msg.id.href);\n assert.deepStrictEqual(messageIds, [\n \"https://example.com/ap/note/01942e9c-9000-7480-a553-7a6ce737ce14\",\n \"https://example.com/ap/note/01942976-3400-7f34-872e-2cbf0f9eeac4\",\n \"https://example.com/ap/note/0194244f-d800-7873-8993-ef71ccd47306\",\n \"https://example.com/ap/note/01941f29-7c00-7fe8-ab0a-7b593990a3c0\",\n ]);\n });\n\n await t.test(\"since\", async () => {\n const outbox = session.getOutbox({\n since: Temporal.Instant.from(\"2025-01-03T00:00:00Z\"),\n });\n const messages = await Array.fromAsync(outbox);\n const messageIds = messages.map((msg) => msg.id.href);\n assert.deepStrictEqual(messageIds, [\n \"https://example.com/ap/note/01942e9c-9000-7480-a553-7a6ce737ce14\",\n \"https://example.com/ap/note/01942976-3400-7f34-872e-2cbf0f9eeac4\",\n ]);\n });\n\n await t.test(\"until\", async () => {\n const outbox = session.getOutbox({\n until: Temporal.Instant.from(\"2025-01-02T00:00:00Z\"),\n });\n const messages = await Array.fromAsync(outbox);\n const messageIds = messages.map((msg) => msg.id.href);\n assert.deepStrictEqual(messageIds, [\n \"https://example.com/ap/note/0194244f-d800-7873-8993-ef71ccd47306\",\n \"https://example.com/ap/note/01941f29-7c00-7fe8-ab0a-7b593990a3c0\",\n ]);\n });\n});\n\nexport interface SentActivity {\n recipients: \"followers\" | Recipient[];\n activity: Activity;\n}\n\nexport interface MockContext extends Context<void> {\n sentActivities: SentActivity[];\n}\n\nexport function createMockContext(\n bot: BotImpl<void>,\n origin: URL | string,\n): MockContext {\n const ctx = bot.federation.createContext(\n new URL(origin),\n undefined,\n ) as MockContext;\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 return ctx;\n}\n"],"mappings":"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"}