@oxy.so/federation 2.2.0 → 2.3.0

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 (54) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/apUri.js +4 -2
  3. package/dist/cjs/httpSignature.js +1 -1
  4. package/dist/cjs/index.js +2 -2
  5. package/dist/cjs/networkIdentity.js +3 -2
  6. package/dist/cjs/node/actorResolver.js +24 -20
  7. package/dist/cjs/node/actorRouter.js +12 -4
  8. package/dist/cjs/node/delivery.js +7 -4
  9. package/dist/cjs/node/inboundDispatch.js +4 -3
  10. package/dist/cjs/node/index.js +7 -1
  11. package/dist/cjs/node/tcoLinks.js +97 -0
  12. package/dist/esm/.tsbuildinfo +1 -1
  13. package/dist/esm/apUri.js +4 -2
  14. package/dist/esm/httpSignature.js +1 -1
  15. package/dist/esm/index.js +3 -3
  16. package/dist/esm/networkIdentity.js +3 -2
  17. package/dist/esm/node/actorResolver.js +24 -20
  18. package/dist/esm/node/actorRouter.js +12 -4
  19. package/dist/esm/node/delivery.js +7 -4
  20. package/dist/esm/node/inboundDispatch.js +4 -3
  21. package/dist/esm/node/index.js +5 -0
  22. package/dist/esm/node/tcoLinks.js +94 -0
  23. package/dist/types/.tsbuildinfo +1 -1
  24. package/dist/types/httpSignature.d.ts +1 -1
  25. package/dist/types/index.d.ts +3 -3
  26. package/dist/types/node/delivery.d.ts +2 -3
  27. package/dist/types/node/index.d.ts +5 -0
  28. package/dist/types/node/tcoLinks.d.ts +41 -0
  29. package/package.json +3 -4
  30. package/src/__tests__/actorCollectionCounts.test.ts +27 -18
  31. package/src/__tests__/actorObject.test.ts +27 -7
  32. package/src/__tests__/actorResolver.test.ts +37 -22
  33. package/src/__tests__/actorResolverNetworkIdentity.test.ts +73 -36
  34. package/src/__tests__/apUri.test.ts +9 -5
  35. package/src/__tests__/delivery.test.ts +56 -24
  36. package/src/__tests__/federationHost.test.ts +13 -3
  37. package/src/__tests__/httpSignature.test.ts +1 -3
  38. package/src/__tests__/inboundDispatch.test.ts +80 -30
  39. package/src/__tests__/networkIdentity.test.ts +240 -113
  40. package/src/__tests__/routers.test.ts +87 -27
  41. package/src/__tests__/tcoLinks.test.ts +21 -0
  42. package/src/actorObject.ts +8 -3
  43. package/src/apUri.ts +6 -2
  44. package/src/httpSignature.ts +1 -1
  45. package/src/index.ts +8 -3
  46. package/src/networkIdentity.ts +14 -5
  47. package/src/node/actorResolver.ts +91 -50
  48. package/src/node/actorRouter.ts +38 -12
  49. package/src/node/delivery.ts +55 -21
  50. package/src/node/identityBridge.ts +38 -18
  51. package/src/node/inboundDispatch.ts +33 -13
  52. package/src/node/index.ts +11 -0
  53. package/src/node/signedFetch.ts +3 -1
  54. package/src/node/tcoLinks.ts +114 -0
@@ -29,21 +29,27 @@ interface StoredActor extends DeliveryActorFields {
29
29
  }
30
30
 
31
31
  /** A capturing test rig: records every delivered/queued activity + enqueue jobs. */
32
- function makeRig(overrides: {
33
- actorsByUri?: Record<string, StoredActor>;
34
- followerActorUris?: string[];
35
- followerInboxes?: Record<string, { sharedInboxUrl?: string | null; inboxUrl?: string | null }>;
36
- enqueueReturns?: boolean;
37
- federationEnabled?: boolean;
38
- sharingEnabled?: boolean;
39
- assertSafeInboxUrl?: DeliveryServiceConfig<StoredActor>['assertSafeInboxUrl'];
40
- blockedHosts?: string[];
41
- } = {}) {
32
+ function makeRig(
33
+ overrides: {
34
+ actorsByUri?: Record<string, StoredActor>;
35
+ followerActorUris?: string[];
36
+ followerInboxes?: Record<string, { sharedInboxUrl?: string | null; inboxUrl?: string | null }>;
37
+ enqueueReturns?: boolean;
38
+ federationEnabled?: boolean;
39
+ sharingEnabled?: boolean;
40
+ assertSafeInboxUrl?: DeliveryServiceConfig<StoredActor>['assertSafeInboxUrl'];
41
+ blockedHosts?: string[];
42
+ } = {},
43
+ ) {
42
44
  const deliveredBodies: Array<{ url: string; body: string }> = [];
43
45
  const enqueued: DeliveryQueueJob[] = [];
44
46
  const fallbackCreates: Array<DeliveryQueueJob & { nextAttemptAt: Date }> = [];
45
47
  const fallbackInserts: Array<DeliveryQueueJob & { nextAttemptAt: Date }> = [];
46
- const upsertedFollows: Array<{ localOxyUserId: string; remoteActorUri: string; activityId: string }> = [];
48
+ const upsertedFollows: Array<{
49
+ localOxyUserId: string;
50
+ remoteActorUri: string;
51
+ activityId: string;
52
+ }> = [];
47
53
  const deletedFollowIds: unknown[] = [];
48
54
  const refreshedInBackground: string[] = [];
49
55
 
@@ -65,7 +71,10 @@ function makeRig(overrides: {
65
71
  deliverSingleHop: async (url, init): Promise<DeliverSingleHopResult> => {
66
72
  deliveredBodies.push({ url, body: init.body });
67
73
  // 202 Accepted — success path (response body destroyed, never read).
68
- return { response: Readable.from([]) as unknown as DeliverSingleHopResult['response'], status: 202 };
74
+ return {
75
+ response: Readable.from([]) as unknown as DeliverSingleHopResult['response'],
76
+ status: 202,
77
+ };
69
78
  },
70
79
  assertSafeInboxUrl: overrides.assertSafeInboxUrl ?? (async () => ({ ok: true })),
71
80
  transport: {
@@ -89,7 +98,10 @@ function makeRig(overrides: {
89
98
  findActorInboxesByUris: async (uris) =>
90
99
  uris
91
100
  .map((u) => overrides.followerInboxes?.[u])
92
- .filter((a): a is { sharedInboxUrl?: string | null; inboxUrl?: string | null } => a !== undefined),
101
+ .filter(
102
+ (a): a is { sharedInboxUrl?: string | null; inboxUrl?: string | null } =>
103
+ a !== undefined,
104
+ ),
93
105
  },
94
106
  follows: {
95
107
  listAcceptedInboundFollowerActorUris: async () => overrides.followerActorUris ?? [],
@@ -98,7 +110,9 @@ function makeRig(overrides: {
98
110
  },
99
111
  findOutbound: async (_localOxyUserId, remoteActorUri) => {
100
112
  const actor = overrides.actorsByUri?.[remoteActorUri];
101
- return actor ? { _id: actor._id, activityId: `${urls.actor('alice')}/follows/${String(actor._id)}` } : null;
113
+ return actor
114
+ ? { _id: actor._id, activityId: `${urls.actor('alice')}/follows/${String(actor._id)}` }
115
+ : null;
102
116
  },
103
117
  deleteById: async (id) => {
104
118
  deletedFollowIds.push(id);
@@ -120,7 +134,11 @@ function makeRig(overrides: {
120
134
  }),
121
135
  },
122
136
  profile: { getBanner: async () => 'https://cdn.example/banner.png' },
123
- buildLocalActorObject: (params) => ({ id: urls.actor(params.username), type: 'Person', name: params.displayName }),
137
+ buildLocalActorObject: (params) => ({
138
+ id: urls.actor(params.username),
139
+ type: 'Person',
140
+ name: params.displayName,
141
+ }),
124
142
  logger: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
125
143
  isBlockedDomain: domainPolicy.isBlockedDomain,
126
144
  };
@@ -173,7 +191,11 @@ describe('sendFollow', () => {
173
191
  expect(result).toEqual({ success: true, pending: false });
174
192
  expect(rig.refreshedInBackground).toEqual([remote]);
175
193
  expect(rig.upsertedFollows).toEqual([
176
- { localOxyUserId: 'u-alice', remoteActorUri: remote, activityId: `${urls.actor('alice')}/follows/ACTID` },
194
+ {
195
+ localOxyUserId: 'u-alice',
196
+ remoteActorUri: remote,
197
+ activityId: `${urls.actor('alice')}/follows/ACTID`,
198
+ },
177
199
  ]);
178
200
  // Byte-frozen Follow activity — the bare AS2 context (NOT the full AP_CONTEXT).
179
201
  expect(rig.deliveredBodies).toHaveLength(1);
@@ -185,7 +207,11 @@ describe('sendFollow', () => {
185
207
 
186
208
  it('short-circuits when federation is disabled', async () => {
187
209
  const rig = makeRig({ federationEnabled: false });
188
- const result = await rig.service.sendFollow('u-alice', 'alice', 'https://remote.example/users/bob');
210
+ const result = await rig.service.sendFollow(
211
+ 'u-alice',
212
+ 'alice',
213
+ 'https://remote.example/users/bob',
214
+ );
189
215
  expect(result).toEqual({ success: false, pending: false });
190
216
  expect(rig.deliveredBodies).toHaveLength(0);
191
217
  expect(rig.upsertedFollows).toHaveLength(0);
@@ -214,7 +240,9 @@ describe('sendAccept', () => {
214
240
  it('delivers the exact Accept(Follow) activity with the full AP_CONTEXT', async () => {
215
241
  const remote = 'https://remote.example/users/bob';
216
242
  const rig = makeRig({
217
- actorsByUri: { [remote]: { _id: 'A', uri: remote, inboxUrl: 'https://remote.example/inbox' } },
243
+ actorsByUri: {
244
+ [remote]: { _id: 'A', uri: remote, inboxUrl: 'https://remote.example/inbox' },
245
+ },
218
246
  });
219
247
 
220
248
  await rig.service.sendAccept('u-alice', 'alice', 'https://remote.example/follows/1', remote);
@@ -265,7 +293,9 @@ describe('sendAccept', () => {
265
293
  const remote = 'https://blocked.example/users/bob';
266
294
  const rig = makeRig({
267
295
  blockedHosts: ['blocked.example'],
268
- actorsByUri: { [remote]: { _id: 'A', uri: remote, inboxUrl: 'https://blocked.example/inbox' } },
296
+ actorsByUri: {
297
+ [remote]: { _id: 'A', uri: remote, inboxUrl: 'https://blocked.example/inbox' },
298
+ },
269
299
  });
270
300
 
271
301
  await rig.service.sendAccept('u-alice', 'alice', 'https://blocked.example/follows/1', remote);
@@ -279,7 +309,9 @@ describe('sendUndoFollow', () => {
279
309
  it('deletes the local follow, then delivers the exact Undo(Follow) with AP_CONTEXT', async () => {
280
310
  const remote = 'https://remote.example/users/bob';
281
311
  const rig = makeRig({
282
- actorsByUri: { [remote]: { _id: 'A', uri: remote, inboxUrl: 'https://remote.example/inbox' } },
312
+ actorsByUri: {
313
+ [remote]: { _id: 'A', uri: remote, inboxUrl: 'https://remote.example/inbox' },
314
+ },
283
315
  });
284
316
 
285
317
  const ok = await rig.service.sendUndoFollow('u-alice', 'alice', remote);
@@ -307,7 +339,9 @@ describe('sendUndoFollow', () => {
307
339
  const remote = 'https://blocked.example/users/bob';
308
340
  const rig = makeRig({
309
341
  blockedHosts: ['blocked.example'],
310
- actorsByUri: { [remote]: { _id: 'A', uri: remote, inboxUrl: 'https://blocked.example/inbox' } },
342
+ actorsByUri: {
343
+ [remote]: { _id: 'A', uri: remote, inboxUrl: 'https://blocked.example/inbox' },
344
+ },
311
345
  });
312
346
 
313
347
  const ok = await rig.service.sendUndoFollow('u-alice', 'alice', remote);
@@ -366,9 +400,7 @@ describe('deliverToFollowers', () => {
366
400
 
367
401
  it('skips unsafe inbox URLs instead of enqueueing or falling back', async () => {
368
402
  const unsafeGuard = jest.fn(async (url: string) =>
369
- url.includes('unsafe')
370
- ? { ok: false as const, reason: 'blocked' }
371
- : { ok: true as const },
403
+ url.includes('unsafe') ? { ok: false as const, reason: 'blocked' } : { ok: true as const },
372
404
  );
373
405
  const rig = makeRig({
374
406
  followerActorUris: ['a', 'b'],
@@ -49,7 +49,11 @@ const CASES: ReadonlyArray<{
49
49
  }> = [
50
50
  { name: 'exact host', actorUri: 'https://spam.example/users/bob', expectedBlocked: true },
51
51
  { name: 'uppercase host', actorUri: 'https://SPAM.EXAMPLE/users/bob', expectedBlocked: true },
52
- { name: 'www. on the wire', actorUri: 'https://www.spam.example/users/bob', expectedBlocked: true },
52
+ {
53
+ name: 'www. on the wire',
54
+ actorUri: 'https://www.spam.example/users/bob',
55
+ expectedBlocked: true,
56
+ },
53
57
  {
54
58
  name: 'www. on the blocklist entry, bare on the wire',
55
59
  actorUri: 'https://spam.example/users/bob',
@@ -86,7 +90,11 @@ const CASES: ReadonlyArray<{
86
90
  entry: 'über.example',
87
91
  expectedBlocked: false,
88
92
  },
89
- { name: 'unrelated host', actorUri: 'https://mastodon.social/users/alice', expectedBlocked: false },
93
+ {
94
+ name: 'unrelated host',
95
+ actorUri: 'https://mastodon.social/users/alice',
96
+ expectedBlocked: false,
97
+ },
90
98
  {
91
99
  name: 'blocked host as a subdomain prefix',
92
100
  actorUri: 'https://spam.example.evil.test/users/bob',
@@ -227,7 +235,9 @@ describe('canonicalFederationHost', () => {
227
235
 
228
236
  it('does not convert a unicode host to its punycode wire form', () => {
229
237
  expect(canonicalFederationHost('ÜBER.example')).toBe('über.example');
230
- expect(canonicalFederationHost('über.example')).not.toBe(new URL('https://über.example').hostname);
238
+ expect(canonicalFederationHost('über.example')).not.toBe(
239
+ new URL('https://über.example').hostname,
240
+ );
231
241
  });
232
242
  });
233
243
 
@@ -117,9 +117,7 @@ const fetchPublicKey = async (keyId: string) =>
117
117
 
118
118
  /** Reproduce how Express lowercases req.headers, folding content-type as a real header. */
119
119
  function lowerHeaders(headers: Record<string, string>): Record<string, string> {
120
- const lowered = Object.fromEntries(
121
- Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]),
122
- );
120
+ const lowered = Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]));
123
121
  if (lowered.digest && !lowered['content-type']) {
124
122
  lowered['content-type'] = DEFAULT_SIGNED_CONTENT_TYPE;
125
123
  }
@@ -21,21 +21,32 @@ import {
21
21
  const LOCAL_ACTOR = 'https://mention.earth/ap/users/alice';
22
22
  const REMOTE_ACTOR = 'https://remote.example/users/bob';
23
23
 
24
- function makeRig(overrides: {
25
- localUser?: { _id?: string | null; id?: string | null } | null;
26
- sharingEnabled?: boolean;
27
- followerOxyUserId?: string | null;
28
- inboundFollow?: { _id: unknown; localUserId: string } | null;
29
- actorOxyUserIdForUndo?: string | null;
30
- validate?: (activity: Record<string, unknown>) => InboundActivityValidation;
31
- blockedHosts?: string[];
32
- withMoveHandler?: boolean;
33
- } = {}) {
24
+ function makeRig(
25
+ overrides: {
26
+ localUser?: { _id?: string | null; id?: string | null } | null;
27
+ sharingEnabled?: boolean;
28
+ followerOxyUserId?: string | null;
29
+ inboundFollow?: { _id: unknown; localUserId: string } | null;
30
+ actorOxyUserIdForUndo?: string | null;
31
+ validate?: (activity: Record<string, unknown>) => InboundActivityValidation;
32
+ blockedHosts?: string[];
33
+ withMoveHandler?: boolean;
34
+ } = {},
35
+ ) {
34
36
  const moves: Array<{ activityId: string; oldActorUri: string; targetActorUri: string }> = [];
35
37
  const bridgeFollowCalls: Array<[string, string]> = [];
36
38
  const bridgeUnfollowCalls: Array<[string, string]> = [];
37
- const acceptsSent: Array<{ localOxyUserId: string; localUsername: string; followActivityId: string; remoteActorUri: string }> = [];
38
- const inboundAcceptedUpserts: Array<{ localUserId: string; remoteActorUri: string; activityId: string }> = [];
39
+ const acceptsSent: Array<{
40
+ localOxyUserId: string;
41
+ localUsername: string;
42
+ followActivityId: string;
43
+ remoteActorUri: string;
44
+ }> = [];
45
+ const inboundAcceptedUpserts: Array<{
46
+ localUserId: string;
47
+ remoteActorUri: string;
48
+ activityId: string;
49
+ }> = [];
39
50
  const deletedFollowIds: unknown[] = [];
40
51
  const contentActivities: Array<{ type: unknown; verifiedActorUri: string }> = [];
41
52
  const outboundAcceptedByActivityId: Array<[string, string]> = [];
@@ -111,7 +122,11 @@ function makeRig(overrides: {
111
122
  ...(overrides.withMoveHandler === false
112
123
  ? {}
113
124
  : {
114
- onMove: async (move: { activityId: string; oldActorUri: string; targetActorUri: string }) => {
125
+ onMove: async (move: {
126
+ activityId: string;
127
+ oldActorUri: string;
128
+ targetActorUri: string;
129
+ }) => {
115
130
  moves.push(move);
116
131
  },
117
132
  }),
@@ -145,9 +160,16 @@ describe('inbound Follow', () => {
145
160
  );
146
161
 
147
162
  expect(rig.bridgeFollowCalls).toEqual([['u-bob', 'u-alice']]);
148
- expect(rig.inboundAcceptedUpserts).toEqual([{ localUserId: 'u-alice', remoteActorUri: REMOTE_ACTOR, activityId: 'f1' }]);
163
+ expect(rig.inboundAcceptedUpserts).toEqual([
164
+ { localUserId: 'u-alice', remoteActorUri: REMOTE_ACTOR, activityId: 'f1' },
165
+ ]);
149
166
  expect(rig.acceptsSent).toEqual([
150
- { localOxyUserId: 'u-alice', localUsername: 'alice', followActivityId: 'f1', remoteActorUri: REMOTE_ACTOR },
167
+ {
168
+ localOxyUserId: 'u-alice',
169
+ localUsername: 'alice',
170
+ followActivityId: 'f1',
171
+ remoteActorUri: REMOTE_ACTOR,
172
+ },
151
173
  ]);
152
174
  expect(rig.onInboundFollowAcceptedCalls).toEqual([['u-alice', 'u-bob', REMOTE_ACTOR]]);
153
175
  });
@@ -233,20 +255,32 @@ describe('inbound Accept / Reject', () => {
233
255
  it('marks the outbound follow accepted by activity id + triggers the outbox backfill', async () => {
234
256
  const rig = makeRig();
235
257
  await rig.dispatcher.processInboxActivity(
236
- { type: 'Accept', actor: REMOTE_ACTOR, object: { type: 'Follow', id: 'https://mention.earth/ap/users/alice/follows/1' } },
258
+ {
259
+ type: 'Accept',
260
+ actor: REMOTE_ACTOR,
261
+ object: { type: 'Follow', id: 'https://mention.earth/ap/users/alice/follows/1' },
262
+ },
237
263
  REMOTE_ACTOR,
238
264
  );
239
- expect(rig.outboundAcceptedByActivityId).toEqual([[REMOTE_ACTOR, 'https://mention.earth/ap/users/alice/follows/1']]);
265
+ expect(rig.outboundAcceptedByActivityId).toEqual([
266
+ [REMOTE_ACTOR, 'https://mention.earth/ap/users/alice/follows/1'],
267
+ ]);
240
268
  expect(rig.onOutboundFollowAcceptedCalls).toEqual([REMOTE_ACTOR]);
241
269
  });
242
270
 
243
271
  it('marks accepted (string ref, then any-pending fallback)', async () => {
244
272
  const rig = makeRig();
245
273
  await rig.dispatcher.processInboxActivity(
246
- { type: 'Accept', actor: REMOTE_ACTOR, object: 'https://mention.earth/ap/users/alice/follows/1' },
274
+ {
275
+ type: 'Accept',
276
+ actor: REMOTE_ACTOR,
277
+ object: 'https://mention.earth/ap/users/alice/follows/1',
278
+ },
247
279
  REMOTE_ACTOR,
248
280
  );
249
- expect(rig.outboundAcceptedByActivityId).toEqual([[REMOTE_ACTOR, 'https://mention.earth/ap/users/alice/follows/1']]);
281
+ expect(rig.outboundAcceptedByActivityId).toEqual([
282
+ [REMOTE_ACTOR, 'https://mention.earth/ap/users/alice/follows/1'],
283
+ ]);
250
284
  });
251
285
 
252
286
  it('marks the outbound follow rejected on Reject(Follow)', async () => {
@@ -273,13 +307,18 @@ describe('Move → onMove', () => {
273
307
  it('hands a well-formed self-Move to the app', async () => {
274
308
  const rig = makeRig();
275
309
  await rig.dispatcher.processInboxActivity(move(), REMOTE_ACTOR);
276
- expect(rig.moves).toEqual([{ activityId: `${REMOTE_ACTOR}#moves/1`, oldActorUri: REMOTE_ACTOR, targetActorUri: TARGET }]);
310
+ expect(rig.moves).toEqual([
311
+ { activityId: `${REMOTE_ACTOR}#moves/1`, oldActorUri: REMOTE_ACTOR, targetActorUri: TARGET },
312
+ ]);
277
313
  expect(rig.contentActivities).toHaveLength(0);
278
314
  });
279
315
 
280
316
  it('accepts embedded object/target references', async () => {
281
317
  const rig = makeRig();
282
- await rig.dispatcher.processInboxActivity(move({ object: { id: REMOTE_ACTOR }, target: { id: TARGET } }), REMOTE_ACTOR);
318
+ await rig.dispatcher.processInboxActivity(
319
+ move({ object: { id: REMOTE_ACTOR }, target: { id: TARGET } }),
320
+ REMOTE_ACTOR,
321
+ );
283
322
  expect(rig.moves).toHaveLength(1);
284
323
  });
285
324
 
@@ -304,18 +343,23 @@ describe('Move → onMove', () => {
304
343
 
305
344
  it('drops a Move when the app registered no handler', async () => {
306
345
  const rig = makeRig({ withMoveHandler: false });
307
- await expect(rig.dispatcher.processInboxActivity(move(), REMOTE_ACTOR)).resolves.toBeUndefined();
346
+ await expect(
347
+ rig.dispatcher.processInboxActivity(move(), REMOTE_ACTOR),
348
+ ).resolves.toBeUndefined();
308
349
  expect(rig.contentActivities).toHaveLength(0);
309
350
  });
310
351
  });
311
352
 
312
353
  describe('content verbs → onContentActivity', () => {
313
- it.each(['Create', 'Announce', 'Like', 'Delete', 'Update'])('routes %s to the app', async (type) => {
314
- const rig = makeRig();
315
- await rig.dispatcher.processInboxActivity({ type, actor: REMOTE_ACTOR }, REMOTE_ACTOR);
316
- expect(rig.contentActivities).toEqual([{ type, verifiedActorUri: REMOTE_ACTOR }]);
317
- expect(rig.bridgeFollowCalls).toHaveLength(0);
318
- });
354
+ it.each(['Create', 'Announce', 'Like', 'Delete', 'Update'])(
355
+ 'routes %s to the app',
356
+ async (type) => {
357
+ const rig = makeRig();
358
+ await rig.dispatcher.processInboxActivity({ type, actor: REMOTE_ACTOR }, REMOTE_ACTOR);
359
+ expect(rig.contentActivities).toEqual([{ type, verifiedActorUri: REMOTE_ACTOR }]);
360
+ expect(rig.bridgeFollowCalls).toHaveLength(0);
361
+ },
362
+ );
319
363
 
320
364
  it('drops a malformed activity without dispatching', async () => {
321
365
  const rig = makeRig({ validate: () => ({ ok: false, summary: 'bad shape' }) });
@@ -402,7 +446,10 @@ describe('blocked-origin domain policy', () => {
402
446
 
403
447
  it('refuses the origin BEFORE the payload is parsed', async () => {
404
448
  const rig = makeRig({ blockedHosts: ['spam.example'] });
405
- await rig.dispatcher.processInboxActivity({ type: 'Create', actor: BLOCKED_ACTOR }, BLOCKED_ACTOR);
449
+ await rig.dispatcher.processInboxActivity(
450
+ { type: 'Create', actor: BLOCKED_ACTOR },
451
+ BLOCKED_ACTOR,
452
+ );
406
453
  expect(rig.validatedActivities).toHaveLength(0);
407
454
  });
408
455
 
@@ -424,7 +471,10 @@ describe('blocked-origin domain policy', () => {
424
471
 
425
472
  it('still dispatches an allowed origin while another host is blocked', async () => {
426
473
  const rig = makeRig({ blockedHosts: ['spam.example'] });
427
- await rig.dispatcher.processInboxActivity({ type: 'Create', actor: REMOTE_ACTOR }, REMOTE_ACTOR);
474
+ await rig.dispatcher.processInboxActivity(
475
+ { type: 'Create', actor: REMOTE_ACTOR },
476
+ REMOTE_ACTOR,
477
+ );
428
478
  expect(rig.contentActivities).toEqual([{ type: 'Create', verifiedActorUri: REMOTE_ACTOR }]);
429
479
  });
430
480