@fedify/fedify 0.12.0 → 0.13.0-dev.311

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,7 +13,6 @@ import { InboxListenerSet } from "./inbox.js";
13
13
  import { createExponentialBackoffPolicy } from "./retry.js";
14
14
  import { Router, RouterError } from "./router.js";
15
15
  import { extractInboxes, sendActivity } from "./send.js";
16
- const invokedByCreateFederation = Symbol("invokedByCreateFederation");
17
16
  /**
18
17
  * Create a new {@link Federation} instance.
19
18
  * @param parameters Parameters for initializing the instance.
@@ -21,65 +20,41 @@ const invokedByCreateFederation = Symbol("invokedByCreateFederation");
21
20
  * @since 0.10.0
22
21
  */
23
22
  export function createFederation(options) {
24
- return new Federation({
25
- ...options,
26
- // @ts-ignore: This is a private symbol.
27
- [invokedByCreateFederation]: true,
28
- });
23
+ return new FederationImpl(options);
29
24
  }
30
25
  const invokedByContext = Symbol("invokedByContext");
31
- /**
32
- * An object that registers federation-related business logic and dispatches
33
- * requests to the appropriate handlers.
34
- *
35
- * It also provides a middleware interface for handling requests before your
36
- * web framework's router; see {@link Federation.handle}.
37
- */
38
- export class Federation {
39
- #kv;
40
- #kvPrefixes;
41
- #queue;
42
- #queueStarted;
43
- #manuallyStartQueue;
44
- #router;
45
- #nodeInfoDispatcher;
46
- #actorCallbacks;
47
- #objectCallbacks;
48
- #objectTypeIds;
49
- #inboxPath;
50
- #inboxCallbacks;
51
- #outboxCallbacks;
52
- #followingCallbacks;
53
- #followersCallbacks;
54
- #likedCallbacks;
55
- #featuredCallbacks;
56
- #featuredTagsCallbacks;
57
- #inboxListeners;
58
- #inboxErrorHandler;
59
- #sharedInboxKeyDispatcher;
60
- #documentLoader;
61
- #contextLoader;
62
- #authenticatedDocumentLoaderFactory;
63
- #treatHttps;
64
- #onOutboxError;
65
- #signatureTimeWindow;
66
- #outboxRetryPolicy;
67
- #inboxRetryPolicy;
68
- /**
69
- * Create a new {@link Federation} instance.
70
- * @param parameters Parameters for initializing the instance.
71
- * @deprecated Use {@link createFederation} method instead.
72
- */
73
- constructor(parameters) {
74
- const options = parameters;
75
- const logger = getLogger(["fedify", "federation"]);
76
- // @ts-ignore: This is a private symbol.
77
- if (!options[invokedByCreateFederation]) {
78
- logger.warn("The Federation constructor is deprecated. Use the createFederation()" +
79
- "function instead.");
80
- }
81
- this.#kv = options.kv;
82
- this.#kvPrefixes = {
26
+ class FederationImpl {
27
+ kv;
28
+ kvPrefixes;
29
+ queue;
30
+ queueStarted;
31
+ manuallyStartQueue;
32
+ router;
33
+ nodeInfoDispatcher;
34
+ actorCallbacks;
35
+ objectCallbacks;
36
+ objectTypeIds;
37
+ inboxPath;
38
+ inboxCallbacks;
39
+ outboxCallbacks;
40
+ followingCallbacks;
41
+ followersCallbacks;
42
+ likedCallbacks;
43
+ featuredCallbacks;
44
+ featuredTagsCallbacks;
45
+ inboxListeners;
46
+ inboxErrorHandler;
47
+ sharedInboxKeyDispatcher;
48
+ documentLoader;
49
+ contextLoader;
50
+ authenticatedDocumentLoaderFactory;
51
+ onOutboxError;
52
+ signatureTimeWindow;
53
+ outboxRetryPolicy;
54
+ inboxRetryPolicy;
55
+ constructor(options) {
56
+ this.kv = options.kv;
57
+ this.kvPrefixes = {
83
58
  ...({
84
59
  activityIdempotence: ["_fedify", "activityIdempotence"],
85
60
  remoteDocument: ["_fedify", "remoteDocument"],
@@ -87,45 +62,38 @@ export class Federation {
87
62
  }),
88
63
  ...(options.kvPrefixes ?? {}),
89
64
  };
90
- this.#queue = options.queue;
91
- this.#queueStarted = false;
92
- this.#manuallyStartQueue = options.manuallyStartQueue ?? false;
93
- this.#router = new Router({
65
+ this.queue = options.queue;
66
+ this.queueStarted = false;
67
+ this.manuallyStartQueue = options.manuallyStartQueue ?? false;
68
+ this.router = new Router({
94
69
  trailingSlashInsensitive: options.trailingSlashInsensitive,
95
70
  });
96
- this.#router.add("/.well-known/webfinger", "webfinger");
97
- this.#router.add("/.well-known/nodeinfo", "nodeInfoJrd");
98
- this.#objectCallbacks = {};
99
- this.#objectTypeIds = {};
100
- this.#documentLoader = options.documentLoader ?? kvCache({
71
+ this.router.add("/.well-known/webfinger", "webfinger");
72
+ this.router.add("/.well-known/nodeinfo", "nodeInfoJrd");
73
+ this.objectCallbacks = {};
74
+ this.objectTypeIds = {};
75
+ this.documentLoader = options.documentLoader ?? kvCache({
101
76
  loader: fetchDocumentLoader,
102
77
  kv: options.kv,
103
- prefix: this.#kvPrefixes.remoteDocument,
78
+ prefix: this.kvPrefixes.remoteDocument,
104
79
  });
105
- this.#contextLoader = options.contextLoader ?? this.#documentLoader;
106
- this.#authenticatedDocumentLoaderFactory =
80
+ this.contextLoader = options.contextLoader ?? this.documentLoader;
81
+ this.authenticatedDocumentLoaderFactory =
107
82
  options.authenticatedDocumentLoaderFactory ??
108
83
  getAuthenticatedDocumentLoader;
109
- this.#onOutboxError = options.onOutboxError;
110
- this.#treatHttps = parameters.treatHttps ?? false;
111
- if (parameters.treatHttps) {
112
- logger.warn("The treatHttps option is deprecated and will be removed in " +
113
- "a future release. Instead, use the x-forwarded-fetch library" +
114
- " to recognize the X-Forwarded-Host and X-Forwarded-Proto " +
115
- "headers. See also: <https://github.com/dahlia/x-forwarded-fetch>.");
116
- }
117
- this.#signatureTimeWindow = options.signatureTimeWindow ?? { minutes: 1 };
118
- this.#outboxRetryPolicy = options.outboxRetryPolicy ??
84
+ this.onOutboxError = options.onOutboxError;
85
+ this.signatureTimeWindow = options.signatureTimeWindow ?? { minutes: 1 };
86
+ this.outboxRetryPolicy = options.outboxRetryPolicy ??
119
87
  createExponentialBackoffPolicy();
120
- this.#inboxRetryPolicy = options.inboxRetryPolicy ??
88
+ this.inboxRetryPolicy = options.inboxRetryPolicy ??
121
89
  createExponentialBackoffPolicy();
122
90
  }
123
91
  #startQueue(ctxData) {
124
- if (this.#queue != null && !this.#queueStarted) {
92
+ if (this.queue != null && !this.queueStarted) {
125
93
  const logger = getLogger(["fedify", "federation", "queue"]);
126
94
  logger.debug("Starting a task queue.");
127
- this.#queue?.listen((msg) => this.#listenQueue(ctxData, msg));
128
- this.#queueStarted = true;
95
+ this.queue?.listen((msg) => this.#listenQueue(ctxData, msg));
96
+ this.queueStarted = true;
129
97
  }
130
98
  }
131
99
  async #listenQueue(ctxData, message) {
@@ -161,35 +129,35 @@ export class Federation {
161
129
  keys.push(pair);
162
130
  }
163
131
  const documentLoader = rsaKeyPair == null
164
- ? this.#documentLoader
165
- : this.#authenticatedDocumentLoaderFactory(rsaKeyPair);
132
+ ? this.documentLoader
133
+ : this.authenticatedDocumentLoaderFactory(rsaKeyPair);
166
134
  activity = await Activity.fromJsonLd(message.activity, {
167
135
  documentLoader,
168
- contextLoader: this.#contextLoader,
136
+ contextLoader: this.contextLoader,
169
137
  });
170
138
  await sendActivity({
171
139
  keys,
172
140
  activity,
173
141
  inbox: new URL(message.inbox),
174
- contextLoader: this.#contextLoader,
142
+ contextLoader: this.contextLoader,
175
143
  headers: new Headers(message.headers),
176
144
  });
177
145
  }
178
146
  catch (error) {
179
147
  try {
180
- this.#onOutboxError?.(error, activity);
148
+ this.onOutboxError?.(error, activity);
181
149
  }
182
150
  catch (error) {
183
151
  logger.error("An unexpected error occurred in onError handler:\n{error}", { ...logData, error, activityId: activity?.id?.href });
184
152
  }
185
- const delay = this.#outboxRetryPolicy({
153
+ const delay = this.outboxRetryPolicy({
186
154
  elapsedTime: dntShim.Temporal.Instant.from(message.started).until(dntShim.Temporal.Now.instant()),
187
155
  attempts: message.attempt,
188
156
  });
189
157
  if (delay != null) {
190
158
  logger.error("Failed to send activity {activityId} to {inbox} (attempt " +
191
159
  "#{attempt}); retry...:\n{error}", { ...logData, error, activityId: activity?.id?.href });
192
- this.#queue?.enqueue({
160
+ this.queue?.enqueue({
193
161
  ...message,
194
162
  attempt: message.attempt + 1,
195
163
  }, {
@@ -217,8 +185,8 @@ export class Federation {
217
185
  }),
218
186
  });
219
187
  }
220
- else if (this.#sharedInboxKeyDispatcher != null) {
221
- const identity = await this.#sharedInboxKeyDispatcher(context);
188
+ else if (this.sharedInboxKeyDispatcher != null) {
189
+ const identity = await this.sharedInboxKeyDispatcher(context);
222
190
  if (identity != null) {
223
191
  context = this.#createContext(baseUrl, ctxData, {
224
192
  documentLoader: "handle" in identity
@@ -229,11 +197,11 @@ export class Federation {
229
197
  }
230
198
  const activity = await Activity.fromJsonLd(message.activity, context);
231
199
  const cacheKey = activity.id == null ? null : [
232
- ...this.#kvPrefixes.activityIdempotence,
200
+ ...this.kvPrefixes.activityIdempotence,
233
201
  activity.id.href,
234
202
  ];
235
203
  if (cacheKey != null) {
236
- const cached = await this.#kv.get(cacheKey);
204
+ const cached = await this.kv.get(cacheKey);
237
205
  if (cached === true) {
238
206
  logger.debug("Activity {activityId} has already been processed.", {
239
207
  activityId: activity.id?.href,
@@ -242,7 +210,7 @@ export class Federation {
242
210
  return;
243
211
  }
244
212
  }
245
- const listener = this.#inboxListeners?.dispatch(activity);
213
+ const listener = this.inboxListeners?.dispatch(activity);
246
214
  if (listener == null) {
247
215
  logger.error("Unsupported activity type:\n{activity}", { activity: message.activity, trial: message.attempt });
248
216
  return;
@@ -252,7 +220,7 @@ export class Federation {
252
220
  }
253
221
  catch (error) {
254
222
  try {
255
- await this.#inboxErrorHandler?.(context, error);
223
+ await this.inboxErrorHandler?.(context, error);
256
224
  }
257
225
  catch (error) {
258
226
  logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
@@ -262,7 +230,7 @@ export class Federation {
262
230
  activity: message.activity,
263
231
  });
264
232
  }
265
- const delay = this.#inboxRetryPolicy({
233
+ const delay = this.inboxRetryPolicy({
266
234
  elapsedTime: dntShim.Temporal.Instant.from(message.started).until(dntShim.Temporal.Now.instant()),
267
235
  attempts: message.attempt,
268
236
  });
@@ -274,7 +242,7 @@ export class Federation {
274
242
  activityId: activity.id?.href,
275
243
  activity: message.activity,
276
244
  });
277
- this.#queue?.enqueue({
245
+ this.queue?.enqueue({
278
246
  ...message,
279
247
  attempt: message.attempt + 1,
280
248
  }, {
@@ -290,20 +258,12 @@ export class Federation {
290
258
  return;
291
259
  }
292
260
  if (cacheKey != null) {
293
- await this.#kv.set(cacheKey, true, {
261
+ await this.kv.set(cacheKey, true, {
294
262
  ttl: dntShim.Temporal.Duration.from({ days: 1 }),
295
263
  });
296
264
  }
297
265
  logger.info("Activity {activityId} has been processed.", { activityId: activity.id?.href, activity: message.activity });
298
266
  }
299
- /**
300
- * Manually start the task queue.
301
- *
302
- * This method is useful when you set the `manuallyStartQueue` option to
303
- * `true` in the {@link createFederation} function.
304
- * @param contextData The context data to pass to the context.
305
- * @since 0.12.0
306
- */
307
267
  startQueue(contextData) {
308
268
  this.#startQueue(contextData);
309
269
  return Promise.resolve();
@@ -323,92 +283,47 @@ export class Federation {
323
283
  url.hash = "";
324
284
  url.search = "";
325
285
  }
326
- if (this.#treatHttps)
327
- url.protocol = "https:";
328
286
  const ctxOptions = {
329
287
  url,
330
288
  federation: this,
331
- router: this.#router,
332
- objectTypeIds: this.#objectTypeIds,
333
- objectCallbacks: this.#objectCallbacks,
334
- actorCallbacks: this.#actorCallbacks,
335
289
  data: contextData,
336
- documentLoader: opts.documentLoader ?? this.#documentLoader,
337
- contextLoader: this.#contextLoader,
338
- authenticatedDocumentLoaderFactory: this.#authenticatedDocumentLoaderFactory,
290
+ documentLoader: opts.documentLoader ?? this.documentLoader,
339
291
  };
340
292
  if (request == null)
341
293
  return new ContextImpl(ctxOptions);
342
294
  return new RequestContextImpl({
343
295
  ...ctxOptions,
344
296
  request,
345
- signatureTimeWindow: this.#signatureTimeWindow,
346
- followersCallbacks: this.#followersCallbacks,
347
297
  invokedFromActorDispatcher: opts.invokedFromActorDispatcher,
348
298
  invokedFromObjectDispatcher: opts.invokedFromObjectDispatcher,
349
299
  });
350
300
  }
351
- /**
352
- * Registers a NodeInfo dispatcher.
353
- * @param path The URI path pattern for the NodeInfo dispatcher. The syntax
354
- * is based on URI Template
355
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
356
- * must have no variables.
357
- * @param dispatcher A NodeInfo dispatcher callback to register.
358
- * @throws {RouterError} Thrown if the path pattern is invalid.
359
- * @since 0.2.0
360
- */
361
301
  setNodeInfoDispatcher(path, dispatcher) {
362
- if (this.#router.has("nodeInfo")) {
302
+ if (this.router.has("nodeInfo")) {
363
303
  throw new RouterError("NodeInfo dispatcher already set.");
364
304
  }
365
- const variables = this.#router.add(path, "nodeInfo");
305
+ const variables = this.router.add(path, "nodeInfo");
366
306
  if (variables.size !== 0) {
367
307
  throw new RouterError("Path for NodeInfo dispatcher must have no variables.");
368
308
  }
369
- this.#nodeInfoDispatcher = dispatcher;
309
+ this.nodeInfoDispatcher = dispatcher;
370
310
  }
371
- /**
372
- * Registers an actor dispatcher.
373
- *
374
- * @example
375
- * ``` typescript
376
- * federation.setActorDispatcher(
377
- * "/users/{handle}",
378
- * async (ctx, handle) => {
379
- * return new Person({
380
- * id: ctx.getActorUri(handle),
381
- * preferredUsername: handle,
382
- * // ...
383
- * });
384
- * }
385
- * );
386
- * ```
387
- *
388
- * @param path The URI path pattern for the actor dispatcher. The syntax is
389
- * based on URI Template
390
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
391
- * must have one variable: `{handle}`.
392
- * @param dispatcher An actor dispatcher callback to register.
393
- * @returns An object with methods to set other actor dispatcher callbacks.
394
- * @throws {RouterError} Thrown if the path pattern is invalid.
395
- */
396
311
  setActorDispatcher(path, dispatcher) {
397
- if (this.#router.has("actor")) {
312
+ if (this.router.has("actor")) {
398
313
  throw new RouterError("Actor dispatcher already set.");
399
314
  }
400
- const variables = this.#router.add(path, "actor");
315
+ const variables = this.router.add(path, "actor");
401
316
  if (variables.size !== 1 || !variables.has("handle")) {
402
317
  throw new RouterError("Path for actor dispatcher must have one variable: {handle}");
403
318
  }
404
319
  const callbacks = {
405
- dispatcher: async (context, handle, key) => {
406
- const actor = await dispatcher(context, handle, key);
320
+ dispatcher: async (context, handle) => {
321
+ const actor = await dispatcher(context, handle);
407
322
  if (actor == null)
408
323
  return null;
409
324
  const logger = getLogger(["fedify", "federation", "actor"]);
410
- if (this.#followingCallbacks != null &&
411
- this.#followingCallbacks.dispatcher != null) {
325
+ if (this.followingCallbacks != null &&
326
+ this.followingCallbacks.dispatcher != null) {
412
327
  if (actor.followingId == null) {
413
328
  logger.warn("You configured a following collection dispatcher, but the " +
414
329
  "actor does not have a following property. Set the property " +
@@ -421,8 +336,8 @@ export class Federation {
421
336
  "Context.getFollowingUri(handle).");
422
337
  }
423
338
  }
424
- if (this.#followersCallbacks != null &&
425
- this.#followersCallbacks.dispatcher != null) {
339
+ if (this.followersCallbacks != null &&
340
+ this.followersCallbacks.dispatcher != null) {
426
341
  if (actor.followersId == null) {
427
342
  logger.warn("You configured a followers collection dispatcher, but the " +
428
343
  "actor does not have a followers property. Set the property " +
@@ -435,8 +350,8 @@ export class Federation {
435
350
  "Context.getFollowersUri(handle).");
436
351
  }
437
352
  }
438
- if (this.#outboxCallbacks != null &&
439
- this.#outboxCallbacks.dispatcher != null) {
353
+ if (this.outboxCallbacks != null &&
354
+ this.outboxCallbacks.dispatcher != null) {
440
355
  if (actor?.outboxId == null) {
441
356
  logger.warn("You configured an outbox collection dispatcher, but the " +
442
357
  "actor does not have an outbox property. Set the property " +
@@ -448,8 +363,8 @@ export class Federation {
448
363
  "URI. Set the property with Context.getOutboxUri(handle).");
449
364
  }
450
365
  }
451
- if (this.#likedCallbacks != null &&
452
- this.#likedCallbacks.dispatcher != null) {
366
+ if (this.likedCallbacks != null &&
367
+ this.likedCallbacks.dispatcher != null) {
453
368
  if (actor?.likedId == null) {
454
369
  logger.warn("You configured a liked collection dispatcher, but the " +
455
370
  "actor does not have a liked property. Set the property " +
@@ -461,8 +376,8 @@ export class Federation {
461
376
  "URI. Set the property with Context.getLikedUri(handle).");
462
377
  }
463
378
  }
464
- if (this.#featuredCallbacks != null &&
465
- this.#featuredCallbacks.dispatcher != null) {
379
+ if (this.featuredCallbacks != null &&
380
+ this.featuredCallbacks.dispatcher != null) {
466
381
  if (actor?.featuredId == null) {
467
382
  logger.warn("You configured a featured collection dispatcher, but the " +
468
383
  "actor does not have a featured property. Set the property " +
@@ -474,8 +389,8 @@ export class Federation {
474
389
  "URI. Set the property with Context.getFeaturedUri(handle).");
475
390
  }
476
391
  }
477
- if (this.#featuredTagsCallbacks != null &&
478
- this.#featuredTagsCallbacks.dispatcher != null) {
392
+ if (this.featuredTagsCallbacks != null &&
393
+ this.featuredTagsCallbacks.dispatcher != null) {
479
394
  if (actor?.featuredTagsId == null) {
480
395
  logger.warn("You configured a featured tags collection dispatcher, but the " +
481
396
  "actor does not have a featuredTags property. Set the property " +
@@ -488,7 +403,7 @@ export class Federation {
488
403
  "Context.getFeaturedTagsUri(handle).");
489
404
  }
490
405
  }
491
- if (this.#router.has("inbox")) {
406
+ if (this.router.has("inbox")) {
492
407
  if (actor.inboxId == null) {
493
408
  logger.warn("You configured inbox listeners, but the actor does not " +
494
409
  "have an inbox property. Set the property with " +
@@ -525,24 +440,12 @@ export class Federation {
525
440
  return actor;
526
441
  },
527
442
  };
528
- this.#actorCallbacks = callbacks;
443
+ this.actorCallbacks = callbacks;
529
444
  const setters = {
530
445
  setKeyPairsDispatcher(dispatcher) {
531
446
  callbacks.keyPairsDispatcher = dispatcher;
532
447
  return setters;
533
448
  },
534
- setKeyPairDispatcher(dispatcher) {
535
- getLogger(["fedify", "federation", "actor"]).warn("The ActorCallbackSetters.setKeyPairDispatcher() method is " +
536
- "deprecated. Use the ActorCallbackSetters.setKeyPairsDispatcher() " +
537
- "instead.");
538
- callbacks.keyPairsDispatcher = async (ctx, handle) => {
539
- const key = await dispatcher(ctx.data, handle);
540
- if (key == null)
541
- return [];
542
- return [key];
543
- };
544
- return setters;
545
- },
546
449
  authorize(predicate) {
547
450
  callbacks.authorizePredicate = predicate;
548
451
  return setters;
@@ -554,10 +457,10 @@ export class Federation {
554
457
  // deno-lint-ignore no-explicit-any
555
458
  cls, path, dispatcher) {
556
459
  const routeName = `object:${cls.typeId.href}`;
557
- if (this.#router.has(routeName)) {
460
+ if (this.router.has(routeName)) {
558
461
  throw new RouterError(`Object dispatcher for ${cls.name} already set.`);
559
462
  }
560
- const variables = this.#router.add(path, routeName);
463
+ const variables = this.router.add(path, routeName);
561
464
  if (variables.size < 1) {
562
465
  throw new RouterError("Path for object dispatcher must have at least one variable.");
563
466
  }
@@ -565,8 +468,8 @@ export class Federation {
565
468
  dispatcher,
566
469
  parameters: variables,
567
470
  };
568
- this.#objectCallbacks[cls.typeId.href] = callbacks;
569
- this.#objectTypeIds[cls.typeId.href] = cls;
471
+ this.objectCallbacks[cls.typeId.href] = callbacks;
472
+ this.objectTypeIds[cls.typeId.href] = cls;
570
473
  const setters = {
571
474
  authorize(predicate) {
572
475
  callbacks.authorizePredicate = predicate;
@@ -575,38 +478,26 @@ export class Federation {
575
478
  };
576
479
  return setters;
577
480
  }
578
- /**
579
- * Registers an inbox dispatcher.
580
- *
581
- * @param path The URI path pattern for the outbox dispatcher. The syntax is
582
- * based on URI Template
583
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
584
- * must have one variable: `{handle}`, and must match the inbox
585
- * listener path.
586
- * @param dispatcher An inbox dispatcher callback to register.
587
- * @throws {@link RouterError} Thrown if the path pattern is invalid.
588
- * @since 0.11.0
589
- */
590
481
  setInboxDispatcher(path, dispatcher) {
591
- if (this.#inboxCallbacks != null) {
482
+ if (this.inboxCallbacks != null) {
592
483
  throw new RouterError("Inbox dispatcher already set.");
593
484
  }
594
- if (this.#router.has("inbox")) {
595
- if (this.#inboxPath !== path) {
485
+ if (this.router.has("inbox")) {
486
+ if (this.inboxPath !== path) {
596
487
  throw new RouterError("Inbox dispatcher path must match inbox listener path.");
597
488
  }
598
489
  }
599
490
  else {
600
- const variables = this.#router.add(path, "inbox");
491
+ const variables = this.router.add(path, "inbox");
601
492
  if (variables.size !== 1 || !variables.has("handle")) {
602
493
  throw new RouterError("Path for inbox dispatcher must have one variable: {handle}");
603
494
  }
604
- this.#inboxPath = path;
495
+ this.inboxPath = path;
605
496
  }
606
497
  const callbacks = {
607
498
  dispatcher,
608
499
  };
609
- this.#inboxCallbacks = callbacks;
500
+ this.inboxCallbacks = callbacks;
610
501
  const setters = {
611
502
  setCounter(counter) {
612
503
  callbacks.counter = counter;
@@ -627,41 +518,18 @@ export class Federation {
627
518
  };
628
519
  return setters;
629
520
  }
630
- /**
631
- * Registers an outbox dispatcher.
632
- *
633
- * @example
634
- * ``` typescript
635
- * federation.setOutboxDispatcher(
636
- * "/users/{handle}/outbox",
637
- * async (ctx, handle, options) => {
638
- * let items: Activity[];
639
- * let nextCursor: string;
640
- * // ...
641
- * return { items, nextCursor };
642
- * }
643
- * );
644
- * ```
645
- *
646
- * @param path The URI path pattern for the outbox dispatcher. The syntax is
647
- * based on URI Template
648
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
649
- * must have one variable: `{handle}`.
650
- * @param dispatcher An outbox dispatcher callback to register.
651
- * @throws {@link RouterError} Thrown if the path pattern is invalid.
652
- */
653
521
  setOutboxDispatcher(path, dispatcher) {
654
- if (this.#router.has("outbox")) {
522
+ if (this.router.has("outbox")) {
655
523
  throw new RouterError("Outbox dispatcher already set.");
656
524
  }
657
- const variables = this.#router.add(path, "outbox");
525
+ const variables = this.router.add(path, "outbox");
658
526
  if (variables.size !== 1 || !variables.has("handle")) {
659
527
  throw new RouterError("Path for outbox dispatcher must have one variable: {handle}");
660
528
  }
661
529
  const callbacks = {
662
530
  dispatcher,
663
531
  };
664
- this.#outboxCallbacks = callbacks;
532
+ this.outboxCallbacks = callbacks;
665
533
  const setters = {
666
534
  setCounter(counter) {
667
535
  callbacks.counter = counter;
@@ -682,29 +550,18 @@ export class Federation {
682
550
  };
683
551
  return setters;
684
552
  }
685
- /**
686
- * Registers a following collection dispatcher.
687
- * @param path The URI path pattern for the following collection. The syntax
688
- * is based on URI Template
689
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
690
- * must have one variable: `{handle}`.
691
- * @param dispatcher A following collection callback to register.
692
- * @returns An object with methods to set other following collection
693
- * callbacks.
694
- * @throws {RouterError} Thrown if the path pattern is invalid.
695
- */
696
553
  setFollowingDispatcher(path, dispatcher) {
697
- if (this.#router.has("following")) {
554
+ if (this.router.has("following")) {
698
555
  throw new RouterError("Following collection dispatcher already set.");
699
556
  }
700
- const variables = this.#router.add(path, "following");
557
+ const variables = this.router.add(path, "following");
701
558
  if (variables.size !== 1 || !variables.has("handle")) {
702
559
  throw new RouterError("Path for following collection dispatcher must have one variable: {handle}");
703
560
  }
704
561
  const callbacks = {
705
562
  dispatcher,
706
563
  };
707
- this.#followingCallbacks = callbacks;
564
+ this.followingCallbacks = callbacks;
708
565
  const setters = {
709
566
  setCounter(counter) {
710
567
  callbacks.counter = counter;
@@ -725,29 +582,18 @@ export class Federation {
725
582
  };
726
583
  return setters;
727
584
  }
728
- /**
729
- * Registers a followers collection dispatcher.
730
- * @param path The URI path pattern for the followers collection. The syntax
731
- * is based on URI Template
732
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
733
- * must have one variable: `{handle}`.
734
- * @param dispatcher A followers collection callback to register.
735
- * @returns An object with methods to set other followers collection
736
- * callbacks.
737
- * @throws {@link RouterError} Thrown if the path pattern is invalid.
738
- */
739
585
  setFollowersDispatcher(path, dispatcher) {
740
- if (this.#router.has("followers")) {
586
+ if (this.router.has("followers")) {
741
587
  throw new RouterError("Followers collection dispatcher already set.");
742
588
  }
743
- const variables = this.#router.add(path, "followers");
589
+ const variables = this.router.add(path, "followers");
744
590
  if (variables.size !== 1 || !variables.has("handle")) {
745
591
  throw new RouterError("Path for followers collection dispatcher must have one variable: {handle}");
746
592
  }
747
593
  const callbacks = {
748
594
  dispatcher,
749
595
  };
750
- this.#followersCallbacks = callbacks;
596
+ this.followersCallbacks = callbacks;
751
597
  const setters = {
752
598
  setCounter(counter) {
753
599
  callbacks.counter = counter;
@@ -768,30 +614,18 @@ export class Federation {
768
614
  };
769
615
  return setters;
770
616
  }
771
- /**
772
- * Registers a liked collection dispatcher.
773
- * @param path The URI path pattern for the liked collection. The syntax
774
- * is based on URI Template
775
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
776
- * must have one variable: `{handle}`.
777
- * @param dispatcher A liked collection callback to register.
778
- * @returns An object with methods to set other liked collection
779
- * callbacks.
780
- * @throws {@link RouterError} Thrown if the path pattern is invalid.
781
- * @since 0.11.0
782
- */
783
617
  setLikedDispatcher(path, dispatcher) {
784
- if (this.#router.has("liked")) {
618
+ if (this.router.has("liked")) {
785
619
  throw new RouterError("Liked collection dispatcher already set.");
786
620
  }
787
- const variables = this.#router.add(path, "liked");
621
+ const variables = this.router.add(path, "liked");
788
622
  if (variables.size !== 1 || !variables.has("handle")) {
789
623
  throw new RouterError("Path for liked collection dispatcher must have one variable: {handle}");
790
624
  }
791
625
  const callbacks = {
792
626
  dispatcher,
793
627
  };
794
- this.#likedCallbacks = callbacks;
628
+ this.likedCallbacks = callbacks;
795
629
  const setters = {
796
630
  setCounter(counter) {
797
631
  callbacks.counter = counter;
@@ -812,30 +646,18 @@ export class Federation {
812
646
  };
813
647
  return setters;
814
648
  }
815
- /**
816
- * Registers a featured collection dispatcher.
817
- * @param path The URI path pattern for the featured collection. The syntax
818
- * is based on URI Template
819
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
820
- * must have one variable: `{handle}`.
821
- * @param dispatcher A featured collection callback to register.
822
- * @returns An object with methods to set other featured collection
823
- * callbacks.
824
- * @throws {@link RouterError} Thrown if the path pattern is invalid.
825
- * @since 0.11.0
826
- */
827
649
  setFeaturedDispatcher(path, dispatcher) {
828
- if (this.#router.has("featured")) {
650
+ if (this.router.has("featured")) {
829
651
  throw new RouterError("Featured collection dispatcher already set.");
830
652
  }
831
- const variables = this.#router.add(path, "featured");
653
+ const variables = this.router.add(path, "featured");
832
654
  if (variables.size !== 1 || !variables.has("handle")) {
833
655
  throw new RouterError("Path for featured collection dispatcher must have one variable: {handle}");
834
656
  }
835
657
  const callbacks = {
836
658
  dispatcher,
837
659
  };
838
- this.#featuredCallbacks = callbacks;
660
+ this.featuredCallbacks = callbacks;
839
661
  const setters = {
840
662
  setCounter(counter) {
841
663
  callbacks.counter = counter;
@@ -856,23 +678,11 @@ export class Federation {
856
678
  };
857
679
  return setters;
858
680
  }
859
- /**
860
- * Registers a featured tags collection dispatcher.
861
- * @param path The URI path pattern for the featured tags collection.
862
- * The syntax is based on URI Template
863
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
864
- * must have one variable: `{handle}`.
865
- * @param dispatcher A featured tags collection callback to register.
866
- * @returns An object with methods to set other featured tags collection
867
- * callbacks.
868
- * @throws {@link RouterError} Thrown if the path pattern is invalid.
869
- * @since 0.11.0
870
- */
871
681
  setFeaturedTagsDispatcher(path, dispatcher) {
872
- if (this.#router.has("featuredTags")) {
682
+ if (this.router.has("featuredTags")) {
873
683
  throw new RouterError("Featured tags collection dispatcher already set.");
874
684
  }
875
- const variables = this.#router.add(path, "featuredTags");
685
+ const variables = this.router.add(path, "featuredTags");
876
686
  if (variables.size !== 1 || !variables.has("handle")) {
877
687
  throw new RouterError("Path for featured tags collection dispatcher must have one " +
878
688
  "variable: {handle}");
@@ -880,7 +690,7 @@ export class Federation {
880
690
  const callbacks = {
881
691
  dispatcher,
882
692
  };
883
- this.#featuredTagsCallbacks = callbacks;
693
+ this.featuredTagsCallbacks = callbacks;
884
694
  const setters = {
885
695
  setCounter(counter) {
886
696
  callbacks.counter = counter;
@@ -901,59 +711,29 @@ export class Federation {
901
711
  };
902
712
  return setters;
903
713
  }
904
- /**
905
- * Assigns the URL path for the inbox and starts setting inbox listeners.
906
- *
907
- * @example
908
- * ``` typescript
909
- * federation
910
- * .setInboxListeners("/users/{handle/inbox", "/inbox")
911
- * .on(Follow, async (ctx, follow) => {
912
- * const from = await follow.getActor(ctx);
913
- * if (!isActor(from)) return;
914
- * // ...
915
- * await ctx.sendActivity({ })
916
- * })
917
- * .on(Undo, async (ctx, undo) => {
918
- * // ...
919
- * });
920
- * ```
921
- *
922
- * @param inboxPath The URI path pattern for the inbox. The syntax is based
923
- * on URI Template
924
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)).
925
- * The path must have one variable: `{handle}`, and must
926
- * match the inbox dispatcher path.
927
- * @param sharedInboxPath An optional URI path pattern for the shared inbox.
928
- * The syntax is based on URI Template
929
- * ([RFC 6570](https://tools.ietf.org/html/rfc6570)).
930
- * The path must have no variables.
931
- * @returns An object to register inbox listeners.
932
- * @throws {RouteError} Thrown if the path pattern is invalid.
933
- */
934
714
  setInboxListeners(inboxPath, sharedInboxPath) {
935
- if (this.#inboxListeners != null) {
715
+ if (this.inboxListeners != null) {
936
716
  throw new RouterError("Inbox listeners already set.");
937
717
  }
938
- if (this.#router.has("inbox")) {
939
- if (this.#inboxPath !== inboxPath) {
718
+ if (this.router.has("inbox")) {
719
+ if (this.inboxPath !== inboxPath) {
940
720
  throw new RouterError("Inbox listener path must match inbox dispatcher path.");
941
721
  }
942
722
  }
943
723
  else {
944
- const variables = this.#router.add(inboxPath, "inbox");
724
+ const variables = this.router.add(inboxPath, "inbox");
945
725
  if (variables.size !== 1 || !variables.has("handle")) {
946
726
  throw new RouterError("Path for inbox must have one variable: {handle}");
947
727
  }
948
- this.#inboxPath = inboxPath;
728
+ this.inboxPath = inboxPath;
949
729
  }
950
730
  if (sharedInboxPath != null) {
951
- const siVars = this.#router.add(sharedInboxPath, "sharedInbox");
731
+ const siVars = this.router.add(sharedInboxPath, "sharedInbox");
952
732
  if (siVars.size !== 0) {
953
733
  throw new RouterError("Path for shared inbox must have no variables.");
954
734
  }
955
735
  }
956
- const listeners = this.#inboxListeners = new InboxListenerSet();
736
+ const listeners = this.inboxListeners = new InboxListenerSet();
957
737
  const setters = {
958
738
  on(
959
739
  // deno-lint-ignore no-explicit-any
@@ -962,27 +742,16 @@ export class Federation {
962
742
  return setters;
963
743
  },
964
744
  onError: (handler) => {
965
- this.#inboxErrorHandler = handler;
745
+ this.inboxErrorHandler = handler;
966
746
  return setters;
967
747
  },
968
748
  setSharedKeyDispatcher: (dispatcher) => {
969
- this.#sharedInboxKeyDispatcher = dispatcher;
749
+ this.sharedInboxKeyDispatcher = dispatcher;
970
750
  return setters;
971
751
  },
972
752
  };
973
753
  return setters;
974
754
  }
975
- /**
976
- * Sends an activity to recipients' inboxes. You would typically use
977
- * {@link Context.sendActivity} instead of this method.
978
- *
979
- * @param keys The sender's key pairs.
980
- * @param recipients The recipients of the activity.
981
- * @param activity The activity to send.
982
- * @param options Options for sending the activity.
983
- * @throws {TypeError} If the activity to send does not have an actor.
984
- * @deprecated Use {@link Context.sendActivity} instead.
985
- */
986
755
  async sendActivity(keys, recipients, activity, options) {
987
756
  const logger = getLogger(["fedify", "federation", "outbox"]);
988
757
  if (!(invokedByContext in options) || !options[invokedByContext]) {
@@ -1000,7 +769,7 @@ export class Federation {
1000
769
  logger.error("Activity {activityId} to send does not have an actor.", { activity, activityId: activity?.id?.href });
1001
770
  throw new TypeError("The activity to send must have at least one actor property.");
1002
771
  }
1003
- if (!this.#manuallyStartQueue)
772
+ if (!this.manuallyStartQueue)
1004
773
  this.#startQueue(contextData);
1005
774
  if (activity.id == null) {
1006
775
  activity = activity.clone({
@@ -1017,7 +786,7 @@ export class Federation {
1017
786
  activityId: activity.id?.href,
1018
787
  activity,
1019
788
  });
1020
- if (immediate || this.#queue == null) {
789
+ if (immediate || this.queue == null) {
1021
790
  if (immediate) {
1022
791
  logger.debug("Sending activity immediately without queue since immediate option " +
1023
792
  "is set.", { activityId: activity.id?.href, activity });
@@ -1031,7 +800,7 @@ export class Federation {
1031
800
  keys,
1032
801
  activity,
1033
802
  inbox: new URL(inbox),
1034
- contextLoader: this.#contextLoader,
803
+ contextLoader: this.contextLoader,
1035
804
  headers: collectionSync == null ? undefined : new Headers({
1036
805
  "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox]),
1037
806
  }),
@@ -1047,7 +816,7 @@ export class Federation {
1047
816
  keyJwkPairs.push({ keyId: keyId.href, privateKey: privateKeyJwk });
1048
817
  }
1049
818
  const activityJson = await activity.toJsonLd({
1050
- contextLoader: this.#contextLoader,
819
+ contextLoader: this.contextLoader,
1051
820
  });
1052
821
  for (const inbox in inboxes) {
1053
822
  const message = {
@@ -1061,21 +830,9 @@ export class Federation {
1061
830
  "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox]),
1062
831
  },
1063
832
  };
1064
- this.#queue.enqueue(message);
833
+ this.queue.enqueue(message);
1065
834
  }
1066
835
  }
1067
- /**
1068
- * Handles a request related to federation. If a request is not related to
1069
- * federation, the `onNotFound` or `onNotAcceptable` callback is called.
1070
- *
1071
- * Usually, this method is called from a server's request handler or
1072
- * a web framework's middleware.
1073
- *
1074
- * @param request The request object.
1075
- * @param parameters The parameters for handling the request.
1076
- * @returns The response to the request.
1077
- * @since 0.6.0
1078
- */
1079
836
  async fetch(request, options) {
1080
837
  const response = await this.#fetch(request, options);
1081
838
  const logger = getLogger(["fedify", "federation", "http"]);
@@ -1100,7 +857,7 @@ export class Federation {
1100
857
  onNotAcceptable ??= notAcceptable;
1101
858
  onUnauthorized ??= unauthorized;
1102
859
  const url = new URL(request.url);
1103
- const route = this.#router.route(url.pathname);
860
+ const route = this.router.route(url.pathname);
1104
861
  if (route == null) {
1105
862
  const response = onNotFound(request);
1106
863
  return response instanceof Promise ? await response : response;
@@ -1111,7 +868,7 @@ export class Federation {
1111
868
  case "webfinger":
1112
869
  return await handleWebFinger(request, {
1113
870
  context,
1114
- actorDispatcher: this.#actorCallbacks?.dispatcher,
871
+ actorDispatcher: this.actorCallbacks?.dispatcher,
1115
872
  onNotFound,
1116
873
  });
1117
874
  case "nodeInfoJrd":
@@ -1119,27 +876,25 @@ export class Federation {
1119
876
  case "nodeInfo":
1120
877
  return await handleNodeInfo(request, {
1121
878
  context,
1122
- nodeInfoDispatcher: this.#nodeInfoDispatcher,
879
+ nodeInfoDispatcher: this.nodeInfoDispatcher,
1123
880
  });
1124
881
  case "actor":
1125
- // FIXME: When the deprecated last parameter (key) of ActorDispatcher
1126
- // is removed, uncomment the following line.
1127
- // context = this.#createContext(request, contextData, {
1128
- // invokedFromActorDispatcher: { handle: route.values.handle },
1129
- // });
882
+ context = this.#createContext(request, contextData, {
883
+ invokedFromActorDispatcher: { handle: route.values.handle },
884
+ });
1130
885
  return await handleActor(request, {
1131
886
  handle: route.values.handle,
1132
887
  context,
1133
- actorDispatcher: this.#actorCallbacks?.dispatcher,
1134
- authorizePredicate: this.#actorCallbacks?.authorizePredicate,
888
+ actorDispatcher: this.actorCallbacks?.dispatcher,
889
+ authorizePredicate: this.actorCallbacks?.authorizePredicate,
1135
890
  onUnauthorized,
1136
891
  onNotFound,
1137
892
  onNotAcceptable,
1138
893
  });
1139
894
  case "object": {
1140
895
  const typeId = route.name.replace(/^object:/, "");
1141
- const callbacks = this.#objectCallbacks[typeId];
1142
- const cls = this.#objectTypeIds[typeId];
896
+ const callbacks = this.objectCallbacks[typeId];
897
+ const cls = this.objectTypeIds[typeId];
1143
898
  context = this.#createContext(request, contextData, {
1144
899
  invokedFromObjectDispatcher: { cls, values: route.values },
1145
900
  });
@@ -1158,7 +913,7 @@ export class Federation {
1158
913
  name: "outbox",
1159
914
  handle: route.values.handle,
1160
915
  context,
1161
- collectionCallbacks: this.#outboxCallbacks,
916
+ collectionCallbacks: this.outboxCallbacks,
1162
917
  onUnauthorized,
1163
918
  onNotFound,
1164
919
  onNotAcceptable,
@@ -1169,7 +924,7 @@ export class Federation {
1169
924
  name: "inbox",
1170
925
  handle: route.values.handle,
1171
926
  context,
1172
- collectionCallbacks: this.#inboxCallbacks,
927
+ collectionCallbacks: this.inboxCallbacks,
1173
928
  onUnauthorized,
1174
929
  onNotFound,
1175
930
  onNotAcceptable,
@@ -1182,8 +937,8 @@ export class Federation {
1182
937
  });
1183
938
  // falls through
1184
939
  case "sharedInbox":
1185
- if (routeName !== "inbox" && this.#sharedInboxKeyDispatcher != null) {
1186
- const identity = await this.#sharedInboxKeyDispatcher(context);
940
+ if (routeName !== "inbox" && this.sharedInboxKeyDispatcher != null) {
941
+ const identity = await this.sharedInboxKeyDispatcher(context);
1187
942
  if (identity != null) {
1188
943
  context = this.#createContext(request, contextData, {
1189
944
  documentLoader: "handle" in identity
@@ -1192,25 +947,25 @@ export class Federation {
1192
947
  });
1193
948
  }
1194
949
  }
1195
- if (!this.#manuallyStartQueue)
950
+ if (!this.manuallyStartQueue)
1196
951
  this.#startQueue(contextData);
1197
952
  return await handleInbox(request, {
1198
953
  handle: route.values.handle ?? null,
1199
954
  context,
1200
- kv: this.#kv,
1201
- kvPrefixes: this.#kvPrefixes,
1202
- actorDispatcher: this.#actorCallbacks?.dispatcher,
1203
- inboxListeners: this.#inboxListeners,
1204
- inboxErrorHandler: this.#inboxErrorHandler,
955
+ kv: this.kv,
956
+ kvPrefixes: this.kvPrefixes,
957
+ actorDispatcher: this.actorCallbacks?.dispatcher,
958
+ inboxListeners: this.inboxListeners,
959
+ inboxErrorHandler: this.inboxErrorHandler,
1205
960
  onNotFound,
1206
- signatureTimeWindow: this.#signatureTimeWindow,
961
+ signatureTimeWindow: this.signatureTimeWindow,
1207
962
  });
1208
963
  case "following":
1209
964
  return await handleCollection(request, {
1210
965
  name: "following",
1211
966
  handle: route.values.handle,
1212
967
  context,
1213
- collectionCallbacks: this.#followingCallbacks,
968
+ collectionCallbacks: this.followingCallbacks,
1214
969
  onUnauthorized,
1215
970
  onNotFound,
1216
971
  onNotAcceptable,
@@ -1229,7 +984,7 @@ export class Federation {
1229
984
  filterPredicate: baseUrl != null
1230
985
  ? ((i) => (i instanceof URL ? i.href : i.id?.href ?? "").startsWith(baseUrl))
1231
986
  : undefined,
1232
- collectionCallbacks: this.#followersCallbacks,
987
+ collectionCallbacks: this.followersCallbacks,
1233
988
  onUnauthorized,
1234
989
  onNotFound,
1235
990
  onNotAcceptable,
@@ -1240,7 +995,7 @@ export class Federation {
1240
995
  name: "liked",
1241
996
  handle: route.values.handle,
1242
997
  context,
1243
- collectionCallbacks: this.#likedCallbacks,
998
+ collectionCallbacks: this.likedCallbacks,
1244
999
  onUnauthorized,
1245
1000
  onNotFound,
1246
1001
  onNotAcceptable,
@@ -1250,7 +1005,7 @@ export class Federation {
1250
1005
  name: "featured",
1251
1006
  handle: route.values.handle,
1252
1007
  context,
1253
- collectionCallbacks: this.#featuredCallbacks,
1008
+ collectionCallbacks: this.featuredCallbacks,
1254
1009
  onUnauthorized,
1255
1010
  onNotFound,
1256
1011
  onNotAcceptable,
@@ -1260,7 +1015,7 @@ export class Federation {
1260
1015
  name: "featured tags",
1261
1016
  handle: route.values.handle,
1262
1017
  context,
1263
- collectionCallbacks: this.#featuredTagsCallbacks,
1018
+ collectionCallbacks: this.featuredTagsCallbacks,
1264
1019
  onUnauthorized,
1265
1020
  onNotFound,
1266
1021
  onNotAcceptable,
@@ -1273,59 +1028,49 @@ export class Federation {
1273
1028
  }
1274
1029
  }
1275
1030
  class ContextImpl {
1276
- #url;
1277
- #federation;
1278
- #router;
1279
- #objectTypeIds;
1280
- objectCallbacks;
1281
- actorCallbacks;
1031
+ url;
1032
+ federation;
1282
1033
  data;
1283
1034
  documentLoader;
1284
- contextLoader;
1285
- #authenticatedDocumentLoaderFactory;
1286
- #invokedFromActorKeyPairsDispatcher;
1287
- constructor({ url, federation, router, objectTypeIds, objectCallbacks, actorCallbacks, data, documentLoader, contextLoader, authenticatedDocumentLoaderFactory, invokedFromActorKeyPairsDispatcher, }) {
1288
- this.#url = url;
1289
- this.#federation = federation;
1290
- this.#router = router;
1291
- this.#objectTypeIds = objectTypeIds;
1292
- this.objectCallbacks = objectCallbacks;
1293
- this.actorCallbacks = actorCallbacks;
1035
+ invokedFromActorKeyPairsDispatcher;
1036
+ constructor({ url, federation, data, documentLoader, invokedFromActorKeyPairsDispatcher, }) {
1037
+ this.url = url;
1038
+ this.federation = federation;
1294
1039
  this.data = data;
1295
1040
  this.documentLoader = documentLoader;
1296
- this.contextLoader = contextLoader;
1297
- this.#authenticatedDocumentLoaderFactory =
1298
- authenticatedDocumentLoaderFactory;
1299
- this.#invokedFromActorKeyPairsDispatcher =
1041
+ this.invokedFromActorKeyPairsDispatcher =
1300
1042
  invokedFromActorKeyPairsDispatcher;
1301
1043
  }
1302
1044
  get hostname() {
1303
- return this.#url.hostname;
1045
+ return this.url.hostname;
1304
1046
  }
1305
1047
  get host() {
1306
- return this.#url.host;
1048
+ return this.url.host;
1307
1049
  }
1308
1050
  get origin() {
1309
- return this.#url.origin;
1051
+ return this.url.origin;
1052
+ }
1053
+ get contextLoader() {
1054
+ return this.federation.contextLoader;
1310
1055
  }
1311
1056
  getNodeInfoUri() {
1312
- const path = this.#router.build("nodeInfo", {});
1057
+ const path = this.federation.router.build("nodeInfo", {});
1313
1058
  if (path == null) {
1314
1059
  throw new RouterError("No NodeInfo dispatcher registered.");
1315
1060
  }
1316
- return new URL(path, this.#url);
1061
+ return new URL(path, this.url);
1317
1062
  }
1318
1063
  getActorUri(handle) {
1319
- const path = this.#router.build("actor", { handle });
1064
+ const path = this.federation.router.build("actor", { handle });
1320
1065
  if (path == null) {
1321
1066
  throw new RouterError("No actor dispatcher registered.");
1322
1067
  }
1323
- return new URL(path, this.#url);
1068
+ return new URL(path, this.url);
1324
1069
  }
1325
1070
  getObjectUri(
1326
1071
  // deno-lint-ignore no-explicit-any
1327
1072
  cls, values) {
1328
- const callbacks = this.objectCallbacks[cls.typeId.href];
1073
+ const callbacks = this.federation.objectCallbacks[cls.typeId.href];
1329
1074
  if (callbacks == null) {
1330
1075
  throw new RouterError("No object dispatcher registered.");
1331
1076
  }
@@ -1334,72 +1079,72 @@ class ContextImpl {
1334
1079
  throw new TypeError(`Missing parameter: ${param}`);
1335
1080
  }
1336
1081
  }
1337
- const path = this.#router.build(`object:${cls.typeId.href}`, values);
1082
+ const path = this.federation.router.build(`object:${cls.typeId.href}`, values);
1338
1083
  if (path == null) {
1339
1084
  throw new RouterError("No object dispatcher registered.");
1340
1085
  }
1341
- return new URL(path, this.#url);
1086
+ return new URL(path, this.url);
1342
1087
  }
1343
1088
  getOutboxUri(handle) {
1344
- const path = this.#router.build("outbox", { handle });
1089
+ const path = this.federation.router.build("outbox", { handle });
1345
1090
  if (path == null) {
1346
1091
  throw new RouterError("No outbox dispatcher registered.");
1347
1092
  }
1348
- return new URL(path, this.#url);
1093
+ return new URL(path, this.url);
1349
1094
  }
1350
1095
  getInboxUri(handle) {
1351
1096
  if (handle == null) {
1352
- const path = this.#router.build("sharedInbox", {});
1097
+ const path = this.federation.router.build("sharedInbox", {});
1353
1098
  if (path == null) {
1354
1099
  throw new RouterError("No shared inbox path registered.");
1355
1100
  }
1356
- return new URL(path, this.#url);
1101
+ return new URL(path, this.url);
1357
1102
  }
1358
- const path = this.#router.build("inbox", { handle });
1103
+ const path = this.federation.router.build("inbox", { handle });
1359
1104
  if (path == null) {
1360
1105
  throw new RouterError("No inbox path registered.");
1361
1106
  }
1362
- return new URL(path, this.#url);
1107
+ return new URL(path, this.url);
1363
1108
  }
1364
1109
  getFollowingUri(handle) {
1365
- const path = this.#router.build("following", { handle });
1110
+ const path = this.federation.router.build("following", { handle });
1366
1111
  if (path == null) {
1367
1112
  throw new RouterError("No following collection path registered.");
1368
1113
  }
1369
- return new URL(path, this.#url);
1114
+ return new URL(path, this.url);
1370
1115
  }
1371
1116
  getFollowersUri(handle) {
1372
- const path = this.#router.build("followers", { handle });
1117
+ const path = this.federation.router.build("followers", { handle });
1373
1118
  if (path == null) {
1374
1119
  throw new RouterError("No followers collection path registered.");
1375
1120
  }
1376
- return new URL(path, this.#url);
1121
+ return new URL(path, this.url);
1377
1122
  }
1378
1123
  getLikedUri(handle) {
1379
- const path = this.#router.build("liked", { handle });
1124
+ const path = this.federation.router.build("liked", { handle });
1380
1125
  if (path == null) {
1381
1126
  throw new RouterError("No liked collection path registered.");
1382
1127
  }
1383
- return new URL(path, this.#url);
1128
+ return new URL(path, this.url);
1384
1129
  }
1385
1130
  getFeaturedUri(handle) {
1386
- const path = this.#router.build("featured", { handle });
1131
+ const path = this.federation.router.build("featured", { handle });
1387
1132
  if (path == null) {
1388
1133
  throw new RouterError("No featured collection path registered.");
1389
1134
  }
1390
- return new URL(path, this.#url);
1135
+ return new URL(path, this.url);
1391
1136
  }
1392
1137
  getFeaturedTagsUri(handle) {
1393
- const path = this.#router.build("featuredTags", { handle });
1138
+ const path = this.federation.router.build("featuredTags", { handle });
1394
1139
  if (path == null) {
1395
1140
  throw new RouterError("No featured tags collection path registered.");
1396
1141
  }
1397
- return new URL(path, this.#url);
1142
+ return new URL(path, this.url);
1398
1143
  }
1399
1144
  parseUri(uri) {
1400
- if (uri.origin !== this.#url.origin)
1145
+ if (uri.origin !== this.url.origin)
1401
1146
  return null;
1402
- const route = this.#router.route(uri.pathname);
1147
+ const route = this.federation.router.route(uri.pathname);
1403
1148
  if (route == null)
1404
1149
  return null;
1405
1150
  else if (route.name === "actor") {
@@ -1409,7 +1154,7 @@ class ContextImpl {
1409
1154
  const typeId = route.name.replace(/^object:/, "");
1410
1155
  return {
1411
1156
  type: "object",
1412
- class: this.#objectTypeIds[typeId],
1157
+ class: this.federation.objectTypeIds[typeId],
1413
1158
  typeId: new URL(typeId),
1414
1159
  values: route.values,
1415
1160
  };
@@ -1442,12 +1187,12 @@ class ContextImpl {
1442
1187
  }
1443
1188
  async getActorKeyPairs(handle) {
1444
1189
  const logger = getLogger(["fedify", "federation", "actor"]);
1445
- if (this.#invokedFromActorKeyPairsDispatcher != null) {
1190
+ if (this.invokedFromActorKeyPairsDispatcher != null) {
1446
1191
  logger.warn("Context.getActorKeyPairs({getActorKeyPairsHandle}) method is " +
1447
1192
  "invoked from the actor key pairs dispatcher " +
1448
1193
  "({actorKeyPairsDispatcherHandle}); this may cause an infinite loop.", {
1449
1194
  getActorKeyPairsHandle: handle,
1450
- actorKeyPairsDispatcherHandle: this.#invokedFromActorKeyPairsDispatcher.handle,
1195
+ actorKeyPairsDispatcherHandle: this.invokedFromActorKeyPairsDispatcher.handle,
1451
1196
  });
1452
1197
  }
1453
1198
  let keyPairs;
@@ -1480,26 +1225,17 @@ class ContextImpl {
1480
1225
  }
1481
1226
  async getKeyPairsFromHandle(handle) {
1482
1227
  const logger = getLogger(["fedify", "federation", "actor"]);
1483
- if (this.actorCallbacks?.keyPairsDispatcher == null) {
1228
+ if (this.federation.actorCallbacks?.keyPairsDispatcher == null) {
1484
1229
  throw new Error("No actor key pairs dispatcher registered.");
1485
1230
  }
1486
- const path = this.#router.build("actor", { handle });
1231
+ const path = this.federation.router.build("actor", { handle });
1487
1232
  if (path == null) {
1488
1233
  logger.warn("No actor dispatcher registered.");
1489
1234
  return [];
1490
1235
  }
1491
- const actorUri = new URL(path, this.#url);
1492
- const keyPairs = await this.actorCallbacks?.keyPairsDispatcher(new ContextImpl({
1493
- url: this.#url,
1494
- federation: this.#federation,
1495
- router: this.#router,
1496
- objectTypeIds: this.#objectTypeIds,
1497
- objectCallbacks: this.objectCallbacks,
1498
- actorCallbacks: this.actorCallbacks,
1499
- data: this.data,
1500
- documentLoader: this.documentLoader,
1501
- contextLoader: this.contextLoader,
1502
- authenticatedDocumentLoaderFactory: this.#authenticatedDocumentLoaderFactory,
1236
+ const actorUri = new URL(path, this.url);
1237
+ const keyPairs = await this.federation.actorCallbacks?.keyPairsDispatcher(new ContextImpl({
1238
+ ...this,
1503
1239
  invokedFromActorKeyPairsDispatcher: { handle },
1504
1240
  }), handle);
1505
1241
  if (keyPairs.length < 1) {
@@ -1518,24 +1254,6 @@ class ContextImpl {
1518
1254
  }
1519
1255
  return result;
1520
1256
  }
1521
- async getActorKey(handle) {
1522
- getLogger(["fedify", "federation", "actor"]).warn("Context.getActorKey() method is deprecated; " +
1523
- "use Context.getActorKeyPairs() method instead.");
1524
- let keyPair;
1525
- try {
1526
- keyPair = await this.getRsaKeyPairFromHandle(handle);
1527
- }
1528
- catch (_) {
1529
- return null;
1530
- }
1531
- if (keyPair == null)
1532
- return null;
1533
- return new CryptographicKey({
1534
- id: keyPair.keyId,
1535
- owner: this.getActorUri(handle),
1536
- publicKey: keyPair.publicKey,
1537
- });
1538
- }
1539
1257
  async getRsaKeyPairFromHandle(handle) {
1540
1258
  const keyPairs = await this.getKeyPairsFromHandle(handle);
1541
1259
  for (const keyPair of keyPairs) {
@@ -1555,9 +1273,9 @@ class ContextImpl {
1555
1273
  const keyPair = this.getRsaKeyPairFromHandle(identity.handle);
1556
1274
  return keyPair.then((pair) => pair == null
1557
1275
  ? this.documentLoader
1558
- : this.#authenticatedDocumentLoaderFactory(pair));
1276
+ : this.federation.authenticatedDocumentLoaderFactory(pair));
1559
1277
  }
1560
- return this.#authenticatedDocumentLoaderFactory(identity);
1278
+ return this.federation.authenticatedDocumentLoaderFactory(identity);
1561
1279
  }
1562
1280
  async sendActivity(sender, recipients, activity, options = {}) {
1563
1281
  let keys;
@@ -1594,15 +1312,15 @@ class ContextImpl {
1594
1312
  for await (const recipient of this.getFollowers(sender.handle)) {
1595
1313
  expandedRecipients.push(recipient);
1596
1314
  }
1597
- const collectionId = this.#router.build("followers", sender);
1315
+ const collectionId = this.federation.router.build("followers", sender);
1598
1316
  opts.collectionSync = collectionId == null
1599
1317
  ? undefined
1600
- : new URL(collectionId, this.#url).href;
1318
+ : new URL(collectionId, this.url).href;
1601
1319
  }
1602
1320
  else {
1603
1321
  expandedRecipients = [recipients];
1604
1322
  }
1605
- return await this.#federation.sendActivity(keys, expandedRecipients, activity, opts);
1323
+ return await this.federation.sendActivity(keys, expandedRecipients, activity, opts);
1606
1324
  }
1607
1325
  getFollowers(_handle) {
1608
1326
  throw new Error('"followers" recipients are not supported in Context. ' +
@@ -1610,39 +1328,33 @@ class ContextImpl {
1610
1328
  }
1611
1329
  }
1612
1330
  class RequestContextImpl extends ContextImpl {
1613
- #options;
1614
- #followersCallbacks;
1615
- #signatureTimeWindow;
1616
1331
  #invokedFromActorDispatcher;
1617
1332
  #invokedFromObjectDispatcher;
1618
1333
  request;
1619
1334
  url;
1620
1335
  constructor(options) {
1621
1336
  super(options);
1622
- this.#options = options;
1623
- this.#followersCallbacks = options.followersCallbacks;
1624
- this.#signatureTimeWindow = options.signatureTimeWindow;
1625
1337
  this.#invokedFromActorDispatcher = options.invokedFromActorDispatcher;
1626
1338
  this.#invokedFromObjectDispatcher = options.invokedFromObjectDispatcher;
1627
1339
  this.request = options.request;
1628
1340
  this.url = options.url;
1629
1341
  }
1630
1342
  async *getFollowers(handle) {
1631
- if (this.#followersCallbacks == null) {
1343
+ if (this.federation.followersCallbacks == null) {
1632
1344
  throw new Error("No followers collection dispatcher registered.");
1633
1345
  }
1634
- const result = await this.#followersCallbacks.dispatcher(this, handle, null);
1346
+ const result = await this.federation.followersCallbacks.dispatcher(this, handle, null);
1635
1347
  if (result != null) {
1636
1348
  for (const recipient of result.items)
1637
1349
  yield recipient;
1638
1350
  return;
1639
1351
  }
1640
- if (this.#followersCallbacks.firstCursor == null) {
1352
+ if (this.federation.followersCallbacks.firstCursor == null) {
1641
1353
  throw new Error("No first cursor dispatcher registered for followers collection.");
1642
1354
  }
1643
- let cursor = await this.#followersCallbacks.firstCursor(this, handle);
1355
+ let cursor = await this.federation.followersCallbacks.firstCursor(this, handle);
1644
1356
  while (cursor != null) {
1645
- const result = await this.#followersCallbacks.dispatcher(this, handle, cursor);
1357
+ const result = await this.federation.followersCallbacks.dispatcher(this, handle, cursor);
1646
1358
  if (result == null)
1647
1359
  break;
1648
1360
  for (const recipient of result.items)
@@ -1651,8 +1363,8 @@ class RequestContextImpl extends ContextImpl {
1651
1363
  }
1652
1364
  }
1653
1365
  async getActor(handle) {
1654
- if (this.actorCallbacks == null ||
1655
- this.actorCallbacks.dispatcher == null) {
1366
+ if (this.federation.actorCallbacks == null ||
1367
+ this.federation.actorCallbacks.dispatcher == null) {
1656
1368
  throw new Error("No actor dispatcher registered.");
1657
1369
  }
1658
1370
  if (this.#invokedFromActorDispatcher != null) {
@@ -1663,26 +1375,15 @@ class RequestContextImpl extends ContextImpl {
1663
1375
  actorDispatcherHandle: this.#invokedFromActorDispatcher.handle,
1664
1376
  });
1665
1377
  }
1666
- let rsaKey;
1667
- try {
1668
- rsaKey = await this.getRsaKeyPairFromHandle(handle);
1669
- }
1670
- catch (_) {
1671
- rsaKey = null;
1672
- }
1673
- return await this.actorCallbacks.dispatcher(new RequestContextImpl({
1674
- ...this.#options,
1378
+ return await this.federation.actorCallbacks.dispatcher(new RequestContextImpl({
1379
+ ...this,
1675
1380
  invokedFromActorDispatcher: { handle },
1676
- }), handle, rsaKey == null ? null : new CryptographicKey({
1677
- id: rsaKey.keyId,
1678
- owner: this.getActorUri(handle),
1679
- publicKey: rsaKey.publicKey,
1680
- }));
1381
+ }), handle);
1681
1382
  }
1682
1383
  async getObject(
1683
1384
  // deno-lint-ignore no-explicit-any
1684
1385
  cls, values) {
1685
- const callbacks = this.objectCallbacks[cls.typeId.href];
1386
+ const callbacks = this.federation.objectCallbacks[cls.typeId.href];
1686
1387
  if (callbacks == null) {
1687
1388
  throw new Error("No object dispatcher registered.");
1688
1389
  }
@@ -1703,7 +1404,7 @@ class RequestContextImpl extends ContextImpl {
1703
1404
  });
1704
1405
  }
1705
1406
  return await callbacks.dispatcher(new RequestContextImpl({
1706
- ...this.#options,
1407
+ ...this,
1707
1408
  invokedFromObjectDispatcher: { cls, values },
1708
1409
  }), values);
1709
1410
  }
@@ -1713,7 +1414,7 @@ class RequestContextImpl extends ContextImpl {
1713
1414
  return this.#signedKey;
1714
1415
  return this.#signedKey = await verifyRequest(this.request, {
1715
1416
  ...this,
1716
- timeWindow: this.#signatureTimeWindow,
1417
+ timeWindow: this.federation.signatureTimeWindow,
1717
1418
  });
1718
1419
  }
1719
1420
  #signedKeyOwner = undefined;