@evanp/activitypub-bot 0.13.0 → 0.13.2

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 (41) hide show
  1. package/package.json +2 -2
  2. package/.github/dependabot.yml +0 -11
  3. package/.github/workflows/main.yml +0 -34
  4. package/.github/workflows/tag.yml +0 -106
  5. package/.nvmrc +0 -1
  6. package/Dockerfile +0 -17
  7. package/docs/activitypub.bot.drawio +0 -110
  8. package/tests/activitydistributor.test.js +0 -606
  9. package/tests/activityhandler.test.js +0 -2276
  10. package/tests/activitypubclient.test.js +0 -210
  11. package/tests/actorstorage.test.js +0 -283
  12. package/tests/app.test.js +0 -17
  13. package/tests/authorizer.test.js +0 -301
  14. package/tests/bot.donothing.test.js +0 -30
  15. package/tests/bot.ok.test.js +0 -101
  16. package/tests/botcontext.test.js +0 -720
  17. package/tests/botdatastorage.test.js +0 -88
  18. package/tests/botfactory.provincebotfactory.test.js +0 -430
  19. package/tests/digester.test.js +0 -56
  20. package/tests/fixtures/bots.js +0 -27
  21. package/tests/fixtures/eventloggingbot.js +0 -57
  22. package/tests/fixtures/provincebotfactory.js +0 -53
  23. package/tests/httpsignature.test.js +0 -199
  24. package/tests/httpsignatureauthenticator.test.js +0 -463
  25. package/tests/index.test.js +0 -12
  26. package/tests/keystorage.test.js +0 -124
  27. package/tests/microsyntax.test.js +0 -123
  28. package/tests/objectcache.test.js +0 -133
  29. package/tests/objectstorage.test.js +0 -149
  30. package/tests/remotekeystorage.test.js +0 -78
  31. package/tests/routes.actor.test.js +0 -214
  32. package/tests/routes.collection.test.js +0 -310
  33. package/tests/routes.health.test.js +0 -41
  34. package/tests/routes.inbox.test.js +0 -216
  35. package/tests/routes.object.test.js +0 -525
  36. package/tests/routes.server.test.js +0 -69
  37. package/tests/routes.sharedinbox.test.js +0 -473
  38. package/tests/routes.webfinger.test.js +0 -68
  39. package/tests/urlformatter.test.js +0 -164
  40. package/tests/utils/digest.js +0 -7
  41. package/tests/utils/nock.js +0 -499
@@ -1,473 +0,0 @@
1
- import { describe, it, before } from 'node:test'
2
- import assert from 'node:assert'
3
- import as2 from '../lib/activitystreams.js'
4
- import request from 'supertest'
5
-
6
- import { makeApp } from '../lib/app.js'
7
-
8
- import {
9
- nockSetup,
10
- nockSignature,
11
- nockFormat,
12
- makeActor,
13
- addFollower,
14
- addFollowing,
15
- addToCollection
16
- } from './utils/nock.js'
17
- import { makeDigest } from './utils/digest.js'
18
- import bots from './fixtures/bots.js'
19
-
20
- describe('routes.sharedinbox', async () => {
21
- const host = 'activitypubbot.test'
22
- const remoteHost = 'social.example'
23
- const origin = `https://${host}`
24
- const databaseUrl = 'sqlite::memory:'
25
- let app = null
26
- let formatter = null
27
- let actorStorage = null
28
-
29
- before(async () => {
30
- nockSetup(remoteHost)
31
- app = await makeApp(databaseUrl, origin, bots, 'silent')
32
- formatter = app.locals.formatter
33
- actorStorage = app.locals.actorStorage
34
- })
35
-
36
- describe('can handle an directly addressed activity', async () => {
37
- const username = 'actor1'
38
- const botName = 'test0'
39
- const path = '/shared/inbox'
40
- const url = `${origin}${path}`
41
- const date = new Date().toUTCString()
42
- let response = null
43
- let signature = null
44
- let body = null
45
- let digest = null
46
- let activity = null
47
- before(async () => {
48
- activity = await as2.import({
49
- type: 'Activity',
50
- actor: nockFormat({ username }),
51
- id: nockFormat({ username, type: 'activity', num: 1 }),
52
- to: formatter.format({ username: botName })
53
- })
54
- body = await activity.write()
55
- digest = makeDigest(body)
56
- signature = await nockSignature({
57
- method: 'POST',
58
- username,
59
- url,
60
- digest,
61
- date
62
- })
63
- })
64
- it('should work without an error', async () => {
65
- response = await request(app)
66
- .post(path)
67
- .send(body)
68
- .set('Signature', signature)
69
- .set('Date', date)
70
- .set('Host', host)
71
- .set('Digest', digest)
72
- .set('Content-Type', 'application/activity+json')
73
- assert.ok(response)
74
- await app.onIdle()
75
- })
76
- it('should return a 200 status', async () => {
77
- assert.strictEqual(response.status, 200)
78
- })
79
- it('should appear in the inbox', async () => {
80
- assert.strictEqual(
81
- true,
82
- await actorStorage.isInCollection(
83
- botName,
84
- 'inbox',
85
- activity
86
- )
87
- )
88
- })
89
- })
90
-
91
- describe('can handle an followers-only activity', async () => {
92
- const username = 'actor2'
93
- const botNames = ['test1', 'test2']
94
- const path = '/shared/inbox'
95
- const url = `${origin}${path}`
96
- const date = new Date().toUTCString()
97
- let response = null
98
- let signature = null
99
- let body = null
100
- let digest = null
101
- let activity = null
102
- let actor = null
103
- before(async () => {
104
- actor = await makeActor(username, remoteHost)
105
- for (const botName of botNames) {
106
- const botId = formatter.format({ username: botName })
107
- addFollower(username, botId, remoteHost)
108
- await actorStorage.addToCollection(botName, 'following', actor)
109
- }
110
- activity = await as2.import({
111
- type: 'Activity',
112
- actor: actor.id,
113
- id: nockFormat({ username, type: 'activity', num: 1 }),
114
- to: nockFormat({ username, collection: 'followers' })
115
- })
116
- body = await activity.write()
117
- digest = makeDigest(body)
118
- signature = await nockSignature({
119
- method: 'POST',
120
- username,
121
- url,
122
- digest,
123
- date
124
- })
125
- })
126
- it('should work without an error', async () => {
127
- response = await request(app)
128
- .post(path)
129
- .send(body)
130
- .set('Signature', signature)
131
- .set('Date', date)
132
- .set('Host', host)
133
- .set('Digest', digest)
134
- .set('Content-Type', 'application/activity+json')
135
- assert.ok(response)
136
- await app.onIdle()
137
- })
138
- it('should return a 200 status', async () => {
139
- assert.strictEqual(response.status, 200)
140
- })
141
- it('should appear in all inboxes', async () => {
142
- for (const botName of botNames) {
143
- assert.strictEqual(
144
- true,
145
- await actorStorage.isInCollection(
146
- botName,
147
- 'inbox',
148
- activity
149
- )
150
- )
151
- }
152
- })
153
- })
154
-
155
- describe('can handle an public activity', async () => {
156
- const username = 'actor3'
157
- const path = '/shared/inbox'
158
- const url = `${origin}${path}`
159
- const date = new Date().toUTCString()
160
- let response = null
161
- let signature = null
162
- let body = null
163
- let digest = null
164
- let activity = null
165
- let actor = null
166
- before(async () => {
167
- actor = await makeActor(username, remoteHost)
168
- activity = await as2.import({
169
- type: 'Activity',
170
- actor: actor.id,
171
- id: nockFormat({ username, type: 'activity', num: 1 }),
172
- to: 'as:Public'
173
- })
174
- body = await activity.write()
175
- digest = makeDigest(body)
176
- signature = await nockSignature({
177
- method: 'POST',
178
- username,
179
- url,
180
- digest,
181
- date
182
- })
183
- })
184
- it('should work without an error', async () => {
185
- response = await request(app)
186
- .post(path)
187
- .send(body)
188
- .set('Signature', signature)
189
- .set('Date', date)
190
- .set('Host', host)
191
- .set('Digest', digest)
192
- .set('Content-Type', 'application/activity+json')
193
- assert.ok(response)
194
- await app.onIdle()
195
- })
196
- it('should return a 200 status', async () => {
197
- assert.strictEqual(response.status, 200)
198
- })
199
- it('should appear in all inboxes', async () => {
200
- const lb = bots.logging
201
- assert.ok(lb.publics.has(activity.id))
202
- })
203
- })
204
-
205
- describe('can handle an activity to local followers collection', async () => {
206
- const username = 'actor4'
207
- const botNames = ['test3', 'test4', 'test5']
208
- const followedBot = 'test6'
209
- const path = '/shared/inbox'
210
- const url = `${origin}${path}`
211
- const date = new Date().toUTCString()
212
- let response = null
213
- let signature = null
214
- let body = null
215
- let digest = null
216
- let activity = null
217
- let actor = null
218
- before(async () => {
219
- actor = await makeActor(username, remoteHost)
220
- const followed = await as2.import({
221
- id: formatter.format({ username: followedBot })
222
- })
223
- for (const botName of botNames) {
224
- const botId = formatter.format({ username: botName })
225
- const bot = await as2.import({ id: botId })
226
- await actorStorage.addToCollection(followedBot, 'followers', bot)
227
- await actorStorage.addToCollection(botName, 'following', followed)
228
- }
229
- activity = await as2.import({
230
- type: 'Activity',
231
- actor: actor.id,
232
- id: nockFormat({ username, type: 'activity', num: 1 }),
233
- to: formatter.format({ username: followedBot, collection: 'followers' })
234
- })
235
- body = await activity.write()
236
- digest = makeDigest(body)
237
- signature = await nockSignature({
238
- method: 'POST',
239
- username,
240
- url,
241
- digest,
242
- date
243
- })
244
- })
245
- it('should work without an error', async () => {
246
- response = await request(app)
247
- .post(path)
248
- .send(body)
249
- .set('Signature', signature)
250
- .set('Date', date)
251
- .set('Host', host)
252
- .set('Digest', digest)
253
- .set('Content-Type', 'application/activity+json')
254
- assert.ok(response)
255
- await app.onIdle()
256
- })
257
- it('should return a 200 status', async () => {
258
- assert.strictEqual(response.status, 200)
259
- })
260
- it('should appear in all inboxes', async () => {
261
- for (const botName of botNames) {
262
- assert.strictEqual(
263
- true,
264
- await actorStorage.isInCollection(
265
- botName,
266
- 'inbox',
267
- activity
268
- )
269
- )
270
- }
271
- })
272
- })
273
-
274
- describe('can handle an activity to local following collection', async () => {
275
- const username = 'actor5'
276
- const botNames = ['test7', 'test8']
277
- const followingBot = 'test9'
278
- const path = '/shared/inbox'
279
- const url = `${origin}${path}`
280
- const date = new Date().toUTCString()
281
- let response = null
282
- let signature = null
283
- let body = null
284
- let digest = null
285
- let activity = null
286
- let actor = null
287
- before(async () => {
288
- actor = await makeActor(username, remoteHost)
289
- const following = await as2.import({
290
- id: formatter.format({ username: followingBot })
291
- })
292
- for (const botName of botNames) {
293
- const botId = formatter.format({ username: botName })
294
- const bot = await as2.import({ id: botId })
295
- await actorStorage.addToCollection(followingBot, 'following', bot)
296
- await actorStorage.addToCollection(botName, 'followers', following)
297
- }
298
- activity = await as2.import({
299
- type: 'Activity',
300
- actor: actor.id,
301
- id: nockFormat({ username, type: 'activity', num: 1 }),
302
- to: formatter.format({
303
- username: followingBot,
304
- collection: 'following'
305
- })
306
- })
307
- body = await activity.write()
308
- digest = makeDigest(body)
309
- signature = await nockSignature({
310
- method: 'POST',
311
- username,
312
- url,
313
- digest,
314
- date
315
- })
316
- })
317
- it('should work without an error', async () => {
318
- response = await request(app)
319
- .post(path)
320
- .send(body)
321
- .set('Signature', signature)
322
- .set('Date', date)
323
- .set('Host', host)
324
- .set('Digest', digest)
325
- .set('Content-Type', 'application/activity+json')
326
- assert.ok(response)
327
- await app.onIdle()
328
- })
329
- it('should return a 200 status', async () => {
330
- assert.strictEqual(response.status, 200)
331
- })
332
- it('should appear in all inboxes', async () => {
333
- for (const botName of botNames) {
334
- assert.strictEqual(
335
- true,
336
- await actorStorage.isInCollection(
337
- botName,
338
- 'inbox',
339
- activity
340
- )
341
- )
342
- }
343
- })
344
- })
345
-
346
- describe('can handle an activity to remote following collection', async () => {
347
- const username = 'actor6'
348
- const botNames = ['test10', 'test11', 'test12']
349
- const path = '/shared/inbox'
350
- const url = `${origin}${path}`
351
- const date = new Date().toUTCString()
352
- let response = null
353
- let signature = null
354
- let body = null
355
- let digest = null
356
- let activity = null
357
- let actor = null
358
- before(async () => {
359
- actor = await makeActor(username, remoteHost)
360
- for (const botName of botNames) {
361
- const botId = formatter.format({ username: botName })
362
- addFollowing(username, botId, remoteHost)
363
- await actorStorage.addToCollection(botName, 'followers', actor)
364
- }
365
- activity = await as2.import({
366
- type: 'Activity',
367
- actor: actor.id,
368
- id: nockFormat({ username, type: 'activity', num: 1 }),
369
- to: nockFormat({ username, collection: 'following' })
370
- })
371
- body = await activity.write()
372
- digest = makeDigest(body)
373
- signature = await nockSignature({
374
- method: 'POST',
375
- username,
376
- url,
377
- digest,
378
- date
379
- })
380
- })
381
- it('should work without an error', async () => {
382
- response = await request(app)
383
- .post(path)
384
- .send(body)
385
- .set('Signature', signature)
386
- .set('Date', date)
387
- .set('Host', host)
388
- .set('Digest', digest)
389
- .set('Content-Type', 'application/activity+json')
390
- assert.ok(response)
391
- await app.onIdle()
392
- })
393
- it('should return a 200 status', async () => {
394
- assert.strictEqual(response.status, 200)
395
- })
396
- it('should appear in all inboxes', async () => {
397
- for (const botName of botNames) {
398
- assert.strictEqual(
399
- true,
400
- await actorStorage.isInCollection(
401
- botName,
402
- 'inbox',
403
- activity
404
- )
405
- )
406
- }
407
- })
408
- })
409
-
410
- describe('can handle an activity to remote actor collection', async () => {
411
- const username = 'actor7'
412
- const botNames = ['test13', 'test14', 'test15']
413
- const path = '/shared/inbox'
414
- const url = `${origin}${path}`
415
- const collection = 1
416
- const date = new Date().toUTCString()
417
- let response = null
418
- let signature = null
419
- let body = null
420
- let digest = null
421
- let activity = null
422
- let actor = null
423
- before(async () => {
424
- actor = await makeActor(username, remoteHost)
425
- for (const botName of botNames) {
426
- const botId = formatter.format({ username: botName })
427
- addToCollection(username, collection, botId, remoteHost)
428
- }
429
- activity = await as2.import({
430
- type: 'Activity',
431
- actor: actor.id,
432
- id: nockFormat({ username, type: 'activity', num: 1 }),
433
- to: nockFormat({ username, type: 'collection', num: collection })
434
- })
435
- body = await activity.write()
436
- digest = makeDigest(body)
437
- signature = await nockSignature({
438
- method: 'POST',
439
- username,
440
- url,
441
- digest,
442
- date
443
- })
444
- })
445
- it('should work without an error', async () => {
446
- response = await request(app)
447
- .post(path)
448
- .send(body)
449
- .set('Signature', signature)
450
- .set('Date', date)
451
- .set('Host', host)
452
- .set('Digest', digest)
453
- .set('Content-Type', 'application/activity+json')
454
- assert.ok(response)
455
- await app.onIdle()
456
- })
457
- it('should return a 200 status', async () => {
458
- assert.strictEqual(response.status, 200)
459
- })
460
- it('should appear in all inboxes', async () => {
461
- for (const botName of botNames) {
462
- assert.strictEqual(
463
- true,
464
- await actorStorage.isInCollection(
465
- botName,
466
- 'inbox',
467
- activity
468
- )
469
- )
470
- }
471
- })
472
- })
473
- })
@@ -1,68 +0,0 @@
1
- import { describe, it } from 'node:test'
2
- import assert from 'node:assert'
3
- import { makeApp } from '../lib/app.js'
4
- import request from 'supertest'
5
- import bots from './fixtures/bots.js'
6
-
7
- describe('webfinger routes', async () => {
8
- const databaseUrl = 'sqlite::memory:'
9
- const origin = 'https://activitypubbot.test'
10
- const app = await makeApp(databaseUrl, origin, bots, 'silent')
11
- describe('GET /.well-known/webfinger', async () => {
12
- let response = null
13
- it('should work without an error', async () => {
14
- response = await request(app).get('/.well-known/webfinger?resource=acct%3Aok%40activitypubbot.test')
15
- })
16
- it('should return 200 OK', async () => {
17
- assert.strictEqual(response.status, 200)
18
- })
19
- it('should return JRD', async () => {
20
- assert.strictEqual(response.type, 'application/jrd+json')
21
- })
22
- it('should return an object with a subject', async () => {
23
- assert.strictEqual(typeof response.body.subject, 'string')
24
- })
25
- it('should return an object with an subject matching the request', async () => {
26
- assert.strictEqual(response.body.subject, 'acct:ok@activitypubbot.test')
27
- })
28
- it('should return an object with a links array', async () => {
29
- assert.strictEqual(Array.isArray(response.body.links), true)
30
- })
31
- it('should return an object with a links array containing the actor id', async () => {
32
- assert.strictEqual(response.body.links.length, 1)
33
- assert.strictEqual(typeof response.body.links[0].rel, 'string')
34
- assert.strictEqual(response.body.links[0].rel, 'self')
35
- assert.strictEqual(typeof response.body.links[0].type, 'string')
36
- assert.strictEqual(response.body.links[0].type, 'application/activity+json')
37
- assert.strictEqual(typeof response.body.links[0].href, 'string')
38
- assert.strictEqual(response.body.links[0].href, 'https://activitypubbot.test/user/ok')
39
- })
40
- })
41
- describe('Webfinger discovery for non-existent user', async () => {
42
- let response = null
43
- it('should work without an error', async () => {
44
- response = await request(app).get('/.well-known/webfinger?resource=acct%3Adne%40activitypubbot.test')
45
- })
46
- it('should return 404 Not Found', async () => {
47
- assert.strictEqual(response.status, 404)
48
- })
49
- })
50
- describe('Webfinger discovery for wrong domain', async () => {
51
- let response = null
52
- it('should work without an error', async () => {
53
- response = await request(app).get('/.well-known/webfinger?resource=acct%3Adne%wrongdomain.test')
54
- })
55
- it('should return 400 Bad Request', async () => {
56
- assert.strictEqual(response.status, 400)
57
- })
58
- })
59
- describe('Webfinger discovery for HTTPS', async () => {
60
- let response = null
61
- it('should work without an error', async () => {
62
- response = await request(app).get('/.well-known/webfinger?resource=' + encodeURIComponent('https://activitypubbot.test/user/ok'))
63
- })
64
- it('should return 400 Bad Request', async () => {
65
- assert.strictEqual(response.status, 400)
66
- })
67
- })
68
- })
@@ -1,164 +0,0 @@
1
- import { describe, it } from 'node:test'
2
- import assert from 'node:assert'
3
- import { UrlFormatter } from '../lib/urlformatter.js'
4
-
5
- describe('UrlFormatter', () => {
6
- const origin = 'https://activitypubbot.example'
7
- let formatter = null
8
- it('can initialize', () => {
9
- formatter = new UrlFormatter(origin)
10
- })
11
- it('can format a user URL', () => {
12
- const url = formatter.format({ username: 'megabot' })
13
- assert.equal(url, 'https://activitypubbot.example/user/megabot')
14
- })
15
- it('can format a public key URL', () => {
16
- const url = formatter.format({ username: 'megabot', type: 'publickey' })
17
- assert.equal(url, 'https://activitypubbot.example/user/megabot/publickey')
18
- })
19
- it('can format an inbox URL', () => {
20
- const url = formatter.format({ username: 'megabot', collection: 'inbox' })
21
- assert.equal(url, 'https://activitypubbot.example/user/megabot/inbox')
22
- })
23
- it('can format an inbox URL page', () => {
24
- const url = formatter.format({
25
- username: 'megabot',
26
- collection: 'inbox',
27
- page: 3
28
- })
29
- assert.equal(url, 'https://activitypubbot.example/user/megabot/inbox/3')
30
- })
31
- it('can format an activity URL', () => {
32
- const url = formatter.format({
33
- username: 'megabot',
34
- type: 'like',
35
- nanoid: 'LNPUlv9kmvhAdr4eoqkil'
36
- })
37
- assert.equal(url, 'https://activitypubbot.example/user/megabot/like/LNPUlv9kmvhAdr4eoqkil')
38
- })
39
- it('can format a note URL', () => {
40
- const url = formatter.format({
41
- username: 'megabot',
42
- type: 'note',
43
- nanoid: 'LNPUlv9kmvhAdr4eoqkil'
44
- })
45
- assert.equal(url, 'https://activitypubbot.example/user/megabot/note/LNPUlv9kmvhAdr4eoqkil')
46
- })
47
- it('can format a note replies URL', () => {
48
- const url = formatter.format({
49
- username: 'megabot',
50
- type: 'note',
51
- nanoid: 'LNPUlv9kmvhAdr4eoqkil',
52
- collection: 'replies'
53
- })
54
- assert.equal(url, 'https://activitypubbot.example/user/megabot/note/LNPUlv9kmvhAdr4eoqkil/replies')
55
- })
56
- it('can format a note replies page URL', () => {
57
- const url = formatter.format({
58
- username: 'megabot',
59
- type: 'note',
60
- nanoid: 'LNPUlv9kmvhAdr4eoqkil',
61
- collection: 'replies',
62
- page: 4
63
- })
64
- assert.equal(url, 'https://activitypubbot.example/user/megabot/note/LNPUlv9kmvhAdr4eoqkil/replies/4')
65
- })
66
- it('can format a server URL', () => {
67
- const url = formatter.format({
68
- server: true
69
- })
70
- assert.equal(url, 'https://activitypubbot.example/')
71
- })
72
- it('can format a server public key URL', () => {
73
- const url = formatter.format({
74
- server: true,
75
- type: 'publickey'
76
- })
77
- assert.equal(url, 'https://activitypubbot.example/publickey')
78
- })
79
- it('can tell if an URL is local', () => {
80
- assert.ok(formatter.isLocal('https://activitypubbot.example/user/megabot'))
81
- assert.ok(!formatter.isLocal('https://social.example/user/megabot'))
82
- })
83
- it('can get a username from a user URL', () => {
84
- const username = formatter.getUserName('https://activitypubbot.example/user/megabot')
85
- assert.equal(username, 'megabot')
86
- })
87
- it('refuses to unformat a remote URL', () => {
88
- assert.throws(() => formatter.unformat(
89
- 'https://remote.example/some/unrelated/33/path/format'
90
- ))
91
- })
92
- it('can unformat a user URL', () => {
93
- const parts = formatter.unformat(
94
- 'https://activitypubbot.example/user/megabot'
95
- )
96
- assert.equal(parts.username, 'megabot')
97
- })
98
- it('can unformat a public key URL', () => {
99
- const parts = formatter.unformat(
100
- 'https://activitypubbot.example/user/megabot/publickey'
101
- )
102
- assert.equal(parts.username, 'megabot')
103
- assert.equal(parts.type, 'publickey')
104
- })
105
- it('can unformat an inbox URL', () => {
106
- const parts = formatter.unformat(
107
- 'https://activitypubbot.example/user/megabot/inbox'
108
- )
109
- assert.equal(parts.username, 'megabot')
110
- assert.equal(parts.collection, 'inbox')
111
- })
112
- it('can unformat an inbox page URL', () => {
113
- const parts = formatter.unformat(
114
- 'https://activitypubbot.example/user/megabot/inbox/3'
115
- )
116
- assert.equal(parts.username, 'megabot')
117
- assert.equal(parts.collection, 'inbox')
118
- assert.equal(parts.page, 3)
119
- })
120
- it('can unformat an activity URL', () => {
121
- const parts = formatter.unformat(
122
- 'https://activitypubbot.example/user/megabot/like/LNPUlv9kmvhAdr4eoqkil'
123
- )
124
- assert.equal(parts.username, 'megabot')
125
- assert.equal(parts.type, 'like')
126
- assert.equal(parts.nanoid, 'LNPUlv9kmvhAdr4eoqkil')
127
- })
128
- it('can unformat a note URL', () => {
129
- const parts = formatter.unformat(
130
- 'https://activitypubbot.example/user/megabot/note/LNPUlv9kmvhAdr4eoqkil'
131
- )
132
- assert.equal(parts.username, 'megabot')
133
- assert.equal(parts.type, 'note')
134
- assert.equal(parts.nanoid, 'LNPUlv9kmvhAdr4eoqkil')
135
- })
136
- it('can unformat a note replies URL', () => {
137
- const parts = formatter.unformat(
138
- 'https://activitypubbot.example/user/megabot/note/LNPUlv9kmvhAdr4eoqkil/replies'
139
- )
140
- assert.equal(parts.username, 'megabot')
141
- assert.equal(parts.type, 'note')
142
- assert.equal(parts.nanoid, 'LNPUlv9kmvhAdr4eoqkil')
143
- assert.equal(parts.collection, 'replies')
144
- })
145
- it('can unformat a note replies page URL', () => {
146
- const parts = formatter.unformat(
147
- 'https://activitypubbot.example/user/megabot/note/LNPUlv9kmvhAdr4eoqkil/replies/4'
148
- )
149
- assert.equal(parts.username, 'megabot')
150
- assert.equal(parts.type, 'note')
151
- assert.equal(parts.nanoid, 'LNPUlv9kmvhAdr4eoqkil')
152
- assert.equal(parts.collection, 'replies')
153
- assert.equal(parts.page, 4)
154
- })
155
- it('can unformat a server URL', () => {
156
- const parts = formatter.unformat('https://activitypubbot.example/')
157
- assert.ok(parts.server)
158
- })
159
- it('can unformat a server public key URL', () => {
160
- const parts = formatter.unformat('https://activitypubbot.example/publickey')
161
- assert.ok(parts.server)
162
- assert.equal(parts.type, 'publickey')
163
- })
164
- })