@fedify/fedify 1.7.15 → 1.7.16

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 (129) hide show
  1. package/dist/actor-BzWaWDTY.js +146 -0
  2. package/dist/actor.js +34648 -5
  3. package/dist/{assert.js → assert-C-mZuSQl.js} +1 -1
  4. package/dist/{assert_instance_of.js → assert_instance_of-lS0Jr2iu.js} +1 -1
  5. package/dist/{assert_is_error.js → assert_is_error-CIYFACrT.js} +1 -1
  6. package/dist/{assert_not_equals.js → assert_not_equals-C1azCAB0.js} +1 -1
  7. package/dist/{assert_rejects.js → assert_rejects-Bkh5lA1a.js} +2 -2
  8. package/dist/{assert_throws.js → assert_throws-CmpfkWEM.js} +2 -2
  9. package/dist/authdocloader-1vrHbYJF.js +51 -0
  10. package/dist/authdocloader.js +2 -4
  11. package/dist/{builder.js → builder-8YjpOSrf.js} +5 -5
  12. package/dist/{client.js → client-CJ3nfMyp.js} +2 -2
  13. package/dist/compat/transformers.test.js +30 -30
  14. package/dist/{context.js → context-OXYKUfFL.js} +4 -4
  15. package/dist/docloader-I3SkMpZK.js +4421 -0
  16. package/dist/docloader.js +61 -4
  17. package/dist/{esm.js → esm-BRXvTSrx.js} +1 -1
  18. package/dist/federation/builder.test.js +17 -17
  19. package/dist/federation/collection.test.js +8 -8
  20. package/dist/federation/handler.test.js +36 -36
  21. package/dist/federation/inbox.test.js +11 -11
  22. package/dist/federation/keycache.test.js +12 -12
  23. package/dist/federation/kv.test.js +8 -8
  24. package/dist/federation/middleware.test.js +39 -39
  25. package/dist/federation/mq.test.js +10 -10
  26. package/dist/federation/retry.test.js +5 -5
  27. package/dist/federation/router.test.js +9 -9
  28. package/dist/federation/send.test.js +23 -23
  29. package/dist/http-CiQH4CF3.js +789 -0
  30. package/dist/http.js +4 -5
  31. package/dist/{inbox.js → inbox-BqBPO0vG.js} +3 -3
  32. package/dist/key-Ba-IjS2c.js +259 -0
  33. package/dist/key-CdNa4Um6.js +16 -0
  34. package/dist/key.js +1 -7
  35. package/dist/key2.js +2 -4
  36. package/dist/{keycache.js → keycache-BdgRTisV.js} +1 -1
  37. package/dist/{keys.js → keys-CLFIvF3E.js} +1 -1
  38. package/dist/{ld.js → ld-Dm1tdWDX.js} +4 -4
  39. package/dist/{lookup2.js → lookup-BumKjgCt.js} +4 -4
  40. package/dist/lookup-CoCshjhM.js +129 -0
  41. package/dist/lookup.js +1 -3
  42. package/dist/middleware-Dvd4BUlF.js +2661 -0
  43. package/dist/middleware-pC0Ld2I6.js +32 -0
  44. package/dist/middleware.js +1222 -364
  45. package/dist/middleware2.js +6 -21
  46. package/dist/nodeinfo/client.test.js +12 -12
  47. package/dist/nodeinfo/handler.test.js +34 -34
  48. package/dist/nodeinfo/semver.test.js +8 -8
  49. package/dist/nodeinfo/types.test.js +9 -9
  50. package/dist/{owner.js → owner-BO3ZhyYg.js} +3 -3
  51. package/dist/proof-Btlfk6hr.js +255 -0
  52. package/dist/proof.js +330 -8
  53. package/dist/runtime/authdocloader.test.js +20 -20
  54. package/dist/runtime/docloader.test.js +13 -13
  55. package/dist/runtime/key.test.js +15 -15
  56. package/dist/runtime/langstr.test.js +8 -8
  57. package/dist/runtime/multibase/multibase.test.js +8 -8
  58. package/dist/runtime/url.test.js +7 -7
  59. package/dist/{send.js → send-Dj-482tr.js} +2 -2
  60. package/dist/sig/http.test.js +20 -20
  61. package/dist/sig/key.test.js +17 -17
  62. package/dist/sig/ld.test.js +18 -18
  63. package/dist/sig/owner.test.js +20 -20
  64. package/dist/sig/proof.test.js +19 -19
  65. package/dist/{std__assert.js → std__assert-BdP_WkD-.js} +1 -1
  66. package/dist/testing/docloader.test.js +8 -8
  67. package/dist/testing/mod.js +2 -2
  68. package/dist/{testing.js → testing-qaAD4B0t.js} +1 -1
  69. package/dist/types-CB_2uuCA.js +51 -0
  70. package/dist/types.js +397 -3
  71. package/dist/vocab/actor.test.js +16 -16
  72. package/dist/vocab/lookup.test.js +17 -17
  73. package/dist/vocab/type.test.js +9 -9
  74. package/dist/vocab/vocab.test.js +17 -17
  75. package/dist/vocab-B8zleLsO.js +34386 -0
  76. package/dist/vocab.js +133 -34351
  77. package/dist/webfinger/handler.test.js +34 -34
  78. package/dist/webfinger/lookup.test.js +11 -11
  79. package/dist/x/cfworkers.test.js +7 -7
  80. package/package.json +1 -1
  81. /package/dist/{assert_equals.js → assert_equals-Dy0MG_Zw.js} +0 -0
  82. /package/dist/{chunk.js → chunk-DvTpRkcT.js} +0 -0
  83. /package/dist/{collection.js → collection-XNLQhehO.js} +0 -0
  84. /package/dist/compat/{transformers.test.d.ts → transformers.test-DnJbd34u.d.ts} +0 -0
  85. /package/dist/{denokv.js → denokv-NcJeZ6rP.js} +0 -0
  86. /package/dist/{docloader2.js → docloader-BDSHZfTJ.js} +0 -0
  87. /package/dist/federation/{builder.test.d.ts → builder.test-Bpt6NOZ6.d.ts} +0 -0
  88. /package/dist/federation/{collection.test.d.ts → collection.test-DKJ6JOZz.d.ts} +0 -0
  89. /package/dist/federation/{handler.test.d.ts → handler.test-BMT7uLC0.d.ts} +0 -0
  90. /package/dist/federation/{inbox.test.d.ts → inbox.test-Do6i02Qp.d.ts} +0 -0
  91. /package/dist/federation/{keycache.test.d.ts → keycache.test-BT83IPZY.d.ts} +0 -0
  92. /package/dist/federation/{kv.test.d.ts → kv.test-kFzzF2VN.d.ts} +0 -0
  93. /package/dist/federation/{middleware.test.d.ts → middleware.test-B1R4_e3-.d.ts} +0 -0
  94. /package/dist/federation/{mq.test.d.ts → mq.test-l79EQQOe.d.ts} +0 -0
  95. /package/dist/federation/{retry.test.d.ts → retry.test-BqS50VCX.d.ts} +0 -0
  96. /package/dist/federation/{router.test.d.ts → router.test-CYQl4po-.d.ts} +0 -0
  97. /package/dist/federation/{send.test.d.ts → send.test-COUnNUzv.d.ts} +0 -0
  98. /package/dist/{kv.js → kv-QeuZ51go.js} +0 -0
  99. /package/dist/{langstr.js → langstr-pFHBDU4y.js} +0 -0
  100. /package/dist/{multibase.js → multibase-DBcKTV2a.js} +0 -0
  101. /package/dist/nodeinfo/{client.test.d.ts → client.test-CZLe79hL.d.ts} +0 -0
  102. /package/dist/nodeinfo/{handler.test.d.ts → handler.test-B-EDZ_hK.d.ts} +0 -0
  103. /package/dist/nodeinfo/{semver.test.d.ts → semver.test-BEuuQSEM.d.ts} +0 -0
  104. /package/dist/nodeinfo/{types.test.d.ts → types.test-B5AT89WV.d.ts} +0 -0
  105. /package/dist/{retry.js → retry-BQet39_l.js} +0 -0
  106. /package/dist/{router.js → router-BuDkN4RQ.js} +0 -0
  107. /package/dist/runtime/{authdocloader.test.d.ts → authdocloader.test-hCRKzn9v.d.ts} +0 -0
  108. /package/dist/runtime/{docloader.test.d.ts → docloader.test-CVd7i_5h.d.ts} +0 -0
  109. /package/dist/runtime/{key.test.d.ts → key.test-DBsILYSD.d.ts} +0 -0
  110. /package/dist/runtime/{langstr.test.d.ts → langstr.test-CiKxuuRY.d.ts} +0 -0
  111. /package/dist/runtime/multibase/{multibase.test.d.ts → multibase.test-Brh6gPBP.d.ts} +0 -0
  112. /package/dist/runtime/{url.test.d.ts → url.test-DlRqkU2j.d.ts} +0 -0
  113. /package/dist/{semver.js → semver-D9d-VO-_.js} +0 -0
  114. /package/dist/sig/{http.test.d.ts → http.test-BpXNAWNI.d.ts} +0 -0
  115. /package/dist/sig/{key.test.d.ts → key.test-B2iLIugy.d.ts} +0 -0
  116. /package/dist/sig/{ld.test.d.ts → ld.test-D-cI70Gw.d.ts} +0 -0
  117. /package/dist/sig/{owner.test.d.ts → owner.test-B_YRjMPj.d.ts} +0 -0
  118. /package/dist/sig/{proof.test.d.ts → proof.test-BagEM_-4.d.ts} +0 -0
  119. /package/dist/testing/{docloader.test.d.ts → docloader.test-lrzf6sDZ.d.ts} +0 -0
  120. /package/dist/testing/{mod.d.ts → mod-3uM8ZvS7.d.ts} +0 -0
  121. /package/dist/{type.js → type-DFsmi-p1.js} +0 -0
  122. /package/dist/{url.js → url-BdNvnK9P.js} +0 -0
  123. /package/dist/vocab/{actor.test.d.ts → actor.test-ClC-iVWk.d.ts} +0 -0
  124. /package/dist/vocab/{lookup.test.d.ts → lookup.test-Cq1I-27w.d.ts} +0 -0
  125. /package/dist/vocab/{type.test.d.ts → type.test-bfFiYGcs.d.ts} +0 -0
  126. /package/dist/vocab/{vocab.test.d.ts → vocab.test-h-ZTisfu.d.ts} +0 -0
  127. /package/dist/webfinger/{handler.test.d.ts → handler.test-DiUeEDDD.d.ts} +0 -0
  128. /package/dist/webfinger/{lookup.test.d.ts → lookup.test-D9onm3U3.d.ts} +0 -0
  129. /package/dist/x/{cfworkers.test.d.ts → cfworkers.test-KXHlJ29z.d.ts} +0 -0
@@ -1,301 +1,845 @@
1
1
 
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
- globalThis.addEventListener = () => {};
5
4
 
6
- import { d as version, i as getDocumentLoader, s as kvCache, u as name } from "./docloader.js";
7
- import { t as getNodeInfo } from "./client.js";
8
- import { n as RouterError } from "./router.js";
9
- import { t as nodeInfoToJson } from "./types.js";
10
- import { _ as Object$1, b as OrderedCollectionPage, h as Multikey, m as Link, o as CryptographicKey, t as Activity, y as OrderedCollection } from "./vocab.js";
5
+ import { r as getDefaultActivityTransformers } from "./transformers.js";
6
+ import { d as name, f as version, i as getDocumentLoader, s as kvCache } from "./docloader.js";
7
+ import { G as Multikey, Tt as getTypeId, V as Link, X as OrderedCollectionPage, Y as OrderedCollection, q as Object$1, s as Activity, y as CryptographicKey } from "./actor.js";
11
8
  import { t as lookupWebFinger } from "./lookup.js";
12
- import { t as getTypeId } from "./type.js";
13
9
  import { a as validateCryptoKey, i as importJwk, t as exportJwk } from "./key2.js";
14
- import { l as verifyRequest } from "./http.js";
10
+ import { r as verifyRequest, t as doubleKnock } from "./http.js";
11
+ import { a as doesActorOwnKey, d as signJsonLd, f as verifyJsonLd, l as detachSignature, n as signObject, o as getKeyOwner, r as verifyObject, u as hasSignature } from "./proof.js";
12
+ import { n as getNodeInfo, t as nodeInfoToJson } from "./types.js";
15
13
  import { t as getAuthenticatedDocumentLoader } from "./authdocloader.js";
16
- import { a as signJsonLd, i as hasSignature, o as verifyJsonLd, r as detachSignature } from "./ld.js";
17
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner.js";
18
- import { n as signObject, r as verifyObject } from "./proof.js";
19
- import { n as traverseCollection, t as lookupObject } from "./lookup2.js";
20
- import { n as routeActivity } from "./inbox.js";
21
- import { t as FederationBuilderImpl } from "./builder.js";
22
- import { t as buildCollectionSynchronizationHeader } from "./collection.js";
23
- import { t as KvKeyCache } from "./keycache.js";
24
- import { t as createExponentialBackoffPolicy } from "./retry.js";
25
- import { n as sendActivity, t as extractInboxes } from "./send.js";
14
+ import { n as lookupObject, r as traverseCollection } from "./vocab.js";
26
15
  import { getLogger, withContext } from "@logtape/logtape";
27
16
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
17
+ import { encodeHex } from "byte-encodings/hex";
18
+ import { cloneDeep } from "@es-toolkit/es-toolkit";
19
+ import { Router } from "uri-template-router";
20
+ import { parseTemplate } from "url-template";
28
21
  import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_HEADER, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
29
22
  import { domainToASCII } from "node:url";
30
23
 
31
- //#region compat/transformers.ts
32
- const logger$1 = getLogger([
33
- "fedify",
34
- "compat",
35
- "transformers"
36
- ]);
37
- /**
38
- * An activity transformer that assigns a new random ID to an activity if it
39
- * does not already have one. This is useful for ensuring that activities
40
- * have an ID before they are sent to other servers.
41
- *
42
- * The generated ID is an origin URI with a fragment which contains an activity
43
- * type name with a random UUID:
44
- *
45
- * ```
46
- * https://example.com/#Follow/12345678-1234-5678-1234-567812345678
47
- * ```
48
- *
49
- * @typeParam TContextData The type of the context data.
50
- * @param activity The activity to assign an ID to.
51
- * @param context The context of the activity.
52
- * @return The activity with an ID assigned.
53
- * @since 1.4.0
54
- */
55
- function autoIdAssigner(activity, context$1) {
56
- if (activity.id != null) return activity;
57
- const id = new URL(`/#${activity.constructor.name}/${crypto.randomUUID()}`, context$1.origin);
58
- logger$1.warn("As the activity to send does not have an id, a new id {id} has been generated for it. However, it is recommended to explicitly set the id for the activity.", { id: id.href });
59
- return activity.clone({ id });
60
- }
61
- /**
62
- * An activity transformer that dehydrates the actor property of an activity
63
- * so that it only contains the actor's URI. For example, suppose we have an
64
- * activity like this:
65
- *
66
- * ```typescript
67
- * import { Follow, Person } from "@fedify/fedify/vocab";
68
- * const input = new Follow({
69
- * id: new URL("http://example.com/activities/1"),
70
- * actor: new Person({
71
- * id: new URL("http://example.com/actors/1"),
72
- * name: "Alice",
73
- * preferredUsername: "alice",
74
- * }),
75
- * object: new Person({
76
- * id: new URL("http://example.com/actors/2"),
77
- * name: "Bob",
78
- * preferredUsername: "bob",
79
- * }),
80
- * });
81
- * ```
82
- *
83
- * The result of applying this transformer would be:
84
- *
85
- * ```typescript
86
- * import { Follow, Person } from "@fedify/fedify/vocab";
87
- * const output = new Follow({
88
- * id: new URL("http://example.com/activities/1"),
89
- * actor: new URL("http://example.com/actors/1"),
90
- * object: new Person({
91
- * id: new URL("http://example.com/actors/2"),
92
- * name: "Bob",
93
- * preferredUsername: "bob",
94
- * }),
95
- * });
96
- * ```
97
- *
98
- * As some ActivityPub implementations like Threads fail to deal with inlined
99
- * actor objects, this transformer can be used to work around this issue.
100
- * @typeParam TContextData The type of the context data.
101
- * @param activity The activity to dehydrate the actor property of.
102
- * @param context The context of the activity.
103
- * @returns The dehydrated activity.
104
- * @since 1.4.0
105
- */
106
- function actorDehydrator(activity, _context) {
107
- if (activity.actorIds.length < 1) return activity;
108
- return activity.clone({ actors: activity.actorIds });
109
- }
110
- /**
111
- * Gets the default activity transformers that are applied to all outgoing
112
- * activities.
113
- * @typeParam TContextData The type of the context data.
114
- * @returns The default activity transformers.
115
- * @since 1.4.0
116
- */
117
- function getDefaultActivityTransformers() {
118
- return [autoIdAssigner, actorDehydrator];
24
+ //#region federation/inbox.ts
25
+ var InboxListenerSet = class InboxListenerSet {
26
+ #listeners;
27
+ constructor() {
28
+ this.#listeners = /* @__PURE__ */ new Map();
29
+ }
30
+ clone() {
31
+ const clone = new InboxListenerSet();
32
+ clone.#listeners = new Map(this.#listeners);
33
+ return clone;
34
+ }
35
+ add(type, listener) {
36
+ if (this.#listeners.has(type)) throw new TypeError("Listener already set for this type.");
37
+ this.#listeners.set(type, listener);
38
+ }
39
+ dispatchWithClass(activity) {
40
+ let cls = activity.constructor;
41
+ const inboxListeners = this.#listeners;
42
+ if (inboxListeners == null) return null;
43
+ while (true) {
44
+ if (inboxListeners.has(cls)) break;
45
+ if (cls === Activity) return null;
46
+ cls = globalThis.Object.getPrototypeOf(cls);
47
+ }
48
+ const listener = inboxListeners.get(cls);
49
+ return {
50
+ class: cls,
51
+ listener
52
+ };
53
+ }
54
+ dispatch(activity) {
55
+ return this.dispatchWithClass(activity)?.listener ?? null;
56
+ }
57
+ };
58
+ async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider }) {
59
+ const logger$1 = getLogger([
60
+ "fedify",
61
+ "federation",
62
+ "inbox"
63
+ ]);
64
+ const cacheKey = activity.id == null ? null : [
65
+ ...kvPrefixes.activityIdempotence,
66
+ ctx.origin,
67
+ activity.id.href
68
+ ];
69
+ if (cacheKey != null) {
70
+ if (await kv.get(cacheKey) === true) {
71
+ logger$1.debug("Activity {activityId} has already been processed.", {
72
+ activityId: activity.id?.href,
73
+ activity: json,
74
+ recipient
75
+ });
76
+ span.setStatus({
77
+ code: SpanStatusCode.UNSET,
78
+ message: `Activity ${activity.id?.href} has already been processed.`
79
+ });
80
+ return "alreadyProcessed";
81
+ }
82
+ }
83
+ if (activity.actorId == null) {
84
+ logger$1.error("Missing actor.", { activity: json });
85
+ span.setStatus({
86
+ code: SpanStatusCode.ERROR,
87
+ message: "Missing actor."
88
+ });
89
+ return "missingActor";
90
+ }
91
+ span.setAttribute("activitypub.actor.id", activity.actorId.href);
92
+ if (queue != null) {
93
+ const carrier = {};
94
+ propagation.inject(context.active(), carrier);
95
+ try {
96
+ await queue.enqueue({
97
+ type: "inbox",
98
+ id: crypto.randomUUID(),
99
+ baseUrl: ctx.origin,
100
+ activity: json,
101
+ identifier: recipient,
102
+ attempt: 0,
103
+ started: (/* @__PURE__ */ new Date()).toISOString(),
104
+ traceContext: carrier
105
+ });
106
+ } catch (error) {
107
+ logger$1.error("Failed to enqueue the incoming activity {activityId}:\n{error}", {
108
+ error,
109
+ activityId: activity.id?.href,
110
+ activity: json,
111
+ recipient
112
+ });
113
+ span.setStatus({
114
+ code: SpanStatusCode.ERROR,
115
+ message: `Failed to enqueue the incoming activity ${activity.id?.href}.`
116
+ });
117
+ throw error;
118
+ }
119
+ logger$1.info("Activity {activityId} is enqueued.", {
120
+ activityId: activity.id?.href,
121
+ activity: json,
122
+ recipient
123
+ });
124
+ return "enqueued";
125
+ }
126
+ tracerProvider = tracerProvider ?? trace.getTracerProvider();
127
+ return await tracerProvider.getTracer(name, version).startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span$1) => {
128
+ const dispatched = inboxListeners?.dispatchWithClass(activity);
129
+ if (dispatched == null) {
130
+ logger$1.error("Unsupported activity type:\n{activity}", {
131
+ activity: json,
132
+ recipient
133
+ });
134
+ span$1.setStatus({
135
+ code: SpanStatusCode.UNSET,
136
+ message: `Unsupported activity type: ${getTypeId(activity).href}`
137
+ });
138
+ span$1.end();
139
+ return "unsupportedActivity";
140
+ }
141
+ const { class: cls, listener } = dispatched;
142
+ span$1.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
143
+ try {
144
+ await listener(inboxContextFactory(recipient, json, activity?.id?.href, getTypeId(activity).href), activity);
145
+ } catch (error) {
146
+ try {
147
+ await inboxErrorHandler?.(ctx, error);
148
+ } catch (error$1) {
149
+ logger$1.error("An unexpected error occurred in inbox error handler:\n{error}", {
150
+ error: error$1,
151
+ activityId: activity.id?.href,
152
+ activity: json,
153
+ recipient
154
+ });
155
+ }
156
+ logger$1.error("Failed to process the incoming activity {activityId}:\n{error}", {
157
+ error,
158
+ activityId: activity.id?.href,
159
+ activity: json,
160
+ recipient
161
+ });
162
+ span$1.setStatus({
163
+ code: SpanStatusCode.ERROR,
164
+ message: String(error)
165
+ });
166
+ span$1.end();
167
+ return "error";
168
+ }
169
+ if (cacheKey != null) await kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
170
+ logger$1.info("Activity {activityId} has been processed.", {
171
+ activityId: activity.id?.href,
172
+ activity: json,
173
+ recipient
174
+ });
175
+ span$1.end();
176
+ return "success";
177
+ });
119
178
  }
120
179
 
121
180
  //#endregion
122
- //#region nodeinfo/handler.ts
123
- /**
124
- * Handles a NodeInfo request. You would not typically call this function
125
- * directly, but instead use {@link Federation.handle} method.
126
- * @param request The NodeInfo request to handle.
127
- * @param parameters The parameters for handling the request.
128
- * @returns The response to the request.
129
- */
130
- async function handleNodeInfo(_request, { context: context$1, nodeInfoDispatcher }) {
131
- const promise = nodeInfoDispatcher(context$1);
132
- const json = nodeInfoToJson(promise instanceof Promise ? await promise : promise);
133
- return new Response(JSON.stringify(json), { headers: { "Content-Type": "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\"" } });
181
+ //#region federation/router.ts
182
+ function cloneInnerRouter(router) {
183
+ const clone = new Router();
184
+ clone.nid = router.nid;
185
+ clone.fsm = cloneDeep(router.fsm);
186
+ clone.routeSet = new Set(router.routeSet);
187
+ clone.templateRouteMap = new Map(router.templateRouteMap);
188
+ clone.valueRouteMap = new Map(router.valueRouteMap);
189
+ clone.hierarchy = cloneDeep(router.hierarchy);
190
+ return clone;
134
191
  }
135
192
  /**
136
- * Handles a request to `/.well-known/nodeinfo`. You would not typically call
137
- * this function directly, but instead use {@link Federation.handle} method.
138
- * @param request The request to handle.
139
- * @param context The request context.
140
- * @returns The response to the request.
193
+ * URL router and constructor based on URI Template
194
+ * ([RFC 6570](https://tools.ietf.org/html/rfc6570)).
141
195
  */
142
- function handleNodeInfoJrd(_request, context$1) {
143
- const links = [];
144
- try {
145
- links.push({
146
- rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
147
- href: context$1.getNodeInfoUri().href,
148
- type: "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\""
149
- });
150
- } catch (e) {
151
- if (!(e instanceof RouterError)) throw e;
196
+ var Router$1 = class Router$1 {
197
+ #router;
198
+ #templates;
199
+ #templateStrings;
200
+ /**
201
+ * Whether to ignore trailing slashes when matching paths.
202
+ * @since 1.6.0
203
+ */
204
+ trailingSlashInsensitive;
205
+ /**
206
+ * Create a new {@link Router}.
207
+ * @param options Options for the router.
208
+ */
209
+ constructor(options = {}) {
210
+ this.#router = new Router();
211
+ this.#templates = {};
212
+ this.#templateStrings = {};
213
+ this.trailingSlashInsensitive = options.trailingSlashInsensitive ?? false;
214
+ }
215
+ clone() {
216
+ const clone = new Router$1({ trailingSlashInsensitive: this.trailingSlashInsensitive });
217
+ clone.#router = cloneInnerRouter(this.#router);
218
+ clone.#templates = { ...this.#templates };
219
+ clone.#templateStrings = { ...this.#templateStrings };
220
+ return clone;
221
+ }
222
+ /**
223
+ * Checks if a path name exists in the router.
224
+ * @param name The name of the path.
225
+ * @returns `true` if the path name exists, otherwise `false`.
226
+ */
227
+ has(name$1) {
228
+ return name$1 in this.#templates;
229
+ }
230
+ /**
231
+ * Adds a new path rule to the router.
232
+ * @param template The path pattern.
233
+ * @param name The name of the path.
234
+ * @returns The names of the variables in the path pattern.
235
+ */
236
+ add(template, name$1) {
237
+ if (!template.startsWith("/")) throw new RouterError("Path must start with a slash.");
238
+ const rule = this.#router.addTemplate(template, {}, name$1);
239
+ this.#templates[name$1] = parseTemplate(template);
240
+ this.#templateStrings[name$1] = template;
241
+ return new Set(rule.variables.map((v) => v.varname));
242
+ }
243
+ /**
244
+ * Resolves a path name and values from a URL, if any match.
245
+ * @param url The URL to resolve.
246
+ * @returns The name of the path and its values, if any match. Otherwise,
247
+ * `null`.
248
+ */
249
+ route(url) {
250
+ let match = this.#router.resolveURI(url);
251
+ if (match == null) {
252
+ if (!this.trailingSlashInsensitive) return null;
253
+ url = url.endsWith("/") ? url.replace(/\/+$/, "") : `${url}/`;
254
+ match = this.#router.resolveURI(url);
255
+ if (match == null) return null;
256
+ }
257
+ return {
258
+ name: match.matchValue,
259
+ template: this.#templateStrings[match.matchValue],
260
+ values: match.params
261
+ };
152
262
  }
153
- const jrd = { links };
154
- const response = new Response(JSON.stringify(jrd), { headers: { "Content-Type": "application/jrd+json" } });
155
- return Promise.resolve(response);
156
- }
157
-
158
- //#endregion
159
- //#region vocab/constants.ts
263
+ /**
264
+ * Constructs a URL/path from a path name and values.
265
+ * @param name The name of the path.
266
+ * @param values The values to expand the path with.
267
+ * @returns The URL/path, if the name exists. Otherwise, `null`.
268
+ */
269
+ build(name$1, values) {
270
+ if (name$1 in this.#templates) return this.#templates[name$1].expand(values);
271
+ return null;
272
+ }
273
+ };
160
274
  /**
161
- * The special public collection for [public addressing]. *Do not mutate this
162
- * object.*
163
- *
164
- * [public addressing]: https://www.w3.org/TR/activitypub/#public-addressing
165
- *
166
- * @since 0.7.0
275
+ * An error thrown by the {@link Router}.
167
276
  */
168
- const PUBLIC_COLLECTION = new URL("https://www.w3.org/ns/activitystreams#Public");
277
+ var RouterError = class extends Error {
278
+ /**
279
+ * Create a new {@link RouterError}.
280
+ * @param message The error message.
281
+ */
282
+ constructor(message) {
283
+ super(message);
284
+ this.name = "RouterError";
285
+ }
286
+ };
169
287
 
170
288
  //#endregion
171
- //#region webfinger/handler.ts
172
- const logger = getLogger([
173
- "fedify",
174
- "webfinger",
175
- "server"
176
- ]);
177
- /**
178
- * Handles a WebFinger request. You would not typically call this function
179
- * directly, but instead use {@link Federation.fetch} method.
180
- * @param request The WebFinger request to handle.
181
- * @param parameters The parameters for handling the request.
182
- * @returns The response to the request.
183
- */
184
- async function handleWebFinger(request, options) {
185
- if (options.tracer == null) return await handleWebFingerInternal(request, options);
186
- return await options.tracer.startActiveSpan("webfinger.handle", { kind: SpanKind.SERVER }, async (span) => {
187
- try {
188
- const response = await handleWebFingerInternal(request, options);
189
- span.setStatus({ code: response.ok ? SpanStatusCode.UNSET : SpanStatusCode.ERROR });
190
- return response;
191
- } catch (error) {
192
- span.setStatus({
193
- code: SpanStatusCode.ERROR,
194
- message: String(error)
289
+ //#region federation/builder.ts
290
+ var FederationBuilderImpl = class {
291
+ router;
292
+ actorCallbacks;
293
+ nodeInfoDispatcher;
294
+ objectCallbacks;
295
+ objectTypeIds;
296
+ inboxPath;
297
+ inboxCallbacks;
298
+ outboxCallbacks;
299
+ followingCallbacks;
300
+ followersCallbacks;
301
+ likedCallbacks;
302
+ featuredCallbacks;
303
+ featuredTagsCallbacks;
304
+ inboxListeners;
305
+ inboxErrorHandler;
306
+ sharedInboxKeyDispatcher;
307
+ constructor() {
308
+ this.router = new Router$1();
309
+ this.objectCallbacks = {};
310
+ this.objectTypeIds = {};
311
+ }
312
+ async build(options) {
313
+ const { FederationImpl: FederationImpl$1 } = await import("./middleware2.js");
314
+ const f = new FederationImpl$1(options);
315
+ const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
316
+ f.router = this.router.clone();
317
+ f.router.trailingSlashInsensitive = trailingSlashInsensitiveValue;
318
+ f._initializeRouter();
319
+ f.actorCallbacks = this.actorCallbacks == null ? void 0 : { ...this.actorCallbacks };
320
+ f.nodeInfoDispatcher = this.nodeInfoDispatcher;
321
+ f.objectCallbacks = { ...this.objectCallbacks };
322
+ f.objectTypeIds = { ...this.objectTypeIds };
323
+ f.inboxPath = this.inboxPath;
324
+ f.inboxCallbacks = this.inboxCallbacks == null ? void 0 : { ...this.inboxCallbacks };
325
+ f.outboxCallbacks = this.outboxCallbacks == null ? void 0 : { ...this.outboxCallbacks };
326
+ f.followingCallbacks = this.followingCallbacks == null ? void 0 : { ...this.followingCallbacks };
327
+ f.followersCallbacks = this.followersCallbacks == null ? void 0 : { ...this.followersCallbacks };
328
+ f.likedCallbacks = this.likedCallbacks == null ? void 0 : { ...this.likedCallbacks };
329
+ f.featuredCallbacks = this.featuredCallbacks == null ? void 0 : { ...this.featuredCallbacks };
330
+ f.featuredTagsCallbacks = this.featuredTagsCallbacks == null ? void 0 : { ...this.featuredTagsCallbacks };
331
+ f.inboxListeners = this.inboxListeners?.clone();
332
+ f.inboxErrorHandler = this.inboxErrorHandler;
333
+ f.sharedInboxKeyDispatcher = this.sharedInboxKeyDispatcher;
334
+ return f;
335
+ }
336
+ _getTracer() {
337
+ return trace.getTracer(name, version);
338
+ }
339
+ setActorDispatcher(path, dispatcher) {
340
+ if (this.router.has("actor")) throw new RouterError("Actor dispatcher already set.");
341
+ const variables = this.router.add(path, "actor");
342
+ if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for actor dispatcher must have one variable: {identifier}");
343
+ if (variables.has("handle")) getLogger([
344
+ "fedify",
345
+ "federation",
346
+ "actor"
347
+ ]).warn("The {{handle}} variable in the actor dispatcher path is deprecated. Use {{identifier}} instead.");
348
+ const callbacks = { dispatcher: async (context$1, identifier) => {
349
+ const actor = await this._getTracer().startActiveSpan("activitypub.dispatch_actor", {
350
+ kind: SpanKind.SERVER,
351
+ attributes: { "fedify.actor.identifier": identifier }
352
+ }, async (span) => {
353
+ try {
354
+ const actor$1 = await dispatcher(context$1, identifier);
355
+ span.setAttribute("activitypub.actor.id", (actor$1?.id ?? context$1.getActorUri(identifier)).href);
356
+ if (actor$1 == null) span.setStatus({ code: SpanStatusCode.ERROR });
357
+ else span.setAttribute("activitypub.actor.type", getTypeId(actor$1).href);
358
+ return actor$1;
359
+ } catch (error) {
360
+ span.setStatus({
361
+ code: SpanStatusCode.ERROR,
362
+ message: String(error)
363
+ });
364
+ throw error;
365
+ } finally {
366
+ span.end();
367
+ }
195
368
  });
196
- throw error;
197
- } finally {
198
- span.end();
369
+ if (actor == null) return null;
370
+ const logger$1 = getLogger([
371
+ "fedify",
372
+ "federation",
373
+ "actor"
374
+ ]);
375
+ if (actor.id == null) logger$1.warn("Actor dispatcher returned an actor without an id property. Set the property with Context.getActorUri(identifier).");
376
+ else if (actor.id.href != context$1.getActorUri(identifier).href) logger$1.warn("Actor dispatcher returned an actor with an id property that does not match the actor URI. Set the property with Context.getActorUri(identifier).");
377
+ if (this.followingCallbacks != null && this.followingCallbacks.dispatcher != null) {
378
+ if (actor.followingId == null) logger$1.warn("You configured a following collection dispatcher, but the actor does not have a following property. Set the property with Context.getFollowingUri(identifier).");
379
+ else if (actor.followingId.href != context$1.getFollowingUri(identifier).href) logger$1.warn("You configured a following collection dispatcher, but the actor's following property does not match the following collection URI. Set the property with Context.getFollowingUri(identifier).");
380
+ }
381
+ if (this.followersCallbacks != null && this.followersCallbacks.dispatcher != null) {
382
+ if (actor.followersId == null) logger$1.warn("You configured a followers collection dispatcher, but the actor does not have a followers property. Set the property with Context.getFollowersUri(identifier).");
383
+ else if (actor.followersId.href != context$1.getFollowersUri(identifier).href) logger$1.warn("You configured a followers collection dispatcher, but the actor's followers property does not match the followers collection URI. Set the property with Context.getFollowersUri(identifier).");
384
+ }
385
+ if (this.outboxCallbacks != null && this.outboxCallbacks.dispatcher != null) {
386
+ if (actor?.outboxId == null) logger$1.warn("You configured an outbox collection dispatcher, but the actor does not have an outbox property. Set the property with Context.getOutboxUri(identifier).");
387
+ else if (actor.outboxId.href != context$1.getOutboxUri(identifier).href) logger$1.warn("You configured an outbox collection dispatcher, but the actor's outbox property does not match the outbox collection URI. Set the property with Context.getOutboxUri(identifier).");
388
+ }
389
+ if (this.likedCallbacks != null && this.likedCallbacks.dispatcher != null) {
390
+ if (actor?.likedId == null) logger$1.warn("You configured a liked collection dispatcher, but the actor does not have a liked property. Set the property with Context.getLikedUri(identifier).");
391
+ else if (actor.likedId.href != context$1.getLikedUri(identifier).href) logger$1.warn("You configured a liked collection dispatcher, but the actor's liked property does not match the liked collection URI. Set the property with Context.getLikedUri(identifier).");
392
+ }
393
+ if (this.featuredCallbacks != null && this.featuredCallbacks.dispatcher != null) {
394
+ if (actor?.featuredId == null) logger$1.warn("You configured a featured collection dispatcher, but the actor does not have a featured property. Set the property with Context.getFeaturedUri(identifier).");
395
+ else if (actor.featuredId.href != context$1.getFeaturedUri(identifier).href) logger$1.warn("You configured a featured collection dispatcher, but the actor's featured property does not match the featured collection URI. Set the property with Context.getFeaturedUri(identifier).");
396
+ }
397
+ if (this.featuredTagsCallbacks != null && this.featuredTagsCallbacks.dispatcher != null) {
398
+ if (actor?.featuredTagsId == null) logger$1.warn("You configured a featured tags collection dispatcher, but the actor does not have a featuredTags property. Set the property with Context.getFeaturedTagsUri(identifier).");
399
+ else if (actor.featuredTagsId.href != context$1.getFeaturedTagsUri(identifier).href) logger$1.warn("You configured a featured tags collection dispatcher, but the actor's featuredTags property does not match the featured tags collection URI. Set the property with Context.getFeaturedTagsUri(identifier).");
400
+ }
401
+ if (this.router.has("inbox")) {
402
+ if (actor.inboxId == null) logger$1.warn("You configured inbox listeners, but the actor does not have an inbox property. Set the property with Context.getInboxUri(identifier).");
403
+ else if (actor.inboxId.href != context$1.getInboxUri(identifier).href) logger$1.warn("You configured inbox listeners, but the actor's inbox property does not match the inbox URI. Set the property with Context.getInboxUri(identifier).");
404
+ if (actor.endpoints == null || actor.endpoints.sharedInbox == null) logger$1.warn("You configured inbox listeners, but the actor does not have a endpoints.sharedInbox property. Set the property with Context.getInboxUri().");
405
+ else if (actor.endpoints.sharedInbox.href != context$1.getInboxUri().href) logger$1.warn("You configured inbox listeners, but the actor's endpoints.sharedInbox property does not match the shared inbox URI. Set the property with Context.getInboxUri().");
406
+ }
407
+ if (callbacks.keyPairsDispatcher != null) {
408
+ if (actor.publicKeyId == null) logger$1.warn("You configured a key pairs dispatcher, but the actor does not have a publicKey property. Set the property with Context.getActorKeyPairs(identifier).");
409
+ if (actor.assertionMethodId == null) logger$1.warn("You configured a key pairs dispatcher, but the actor does not have an assertionMethod property. Set the property with Context.getActorKeyPairs(identifier).");
410
+ }
411
+ return actor;
412
+ } };
413
+ this.actorCallbacks = callbacks;
414
+ const setters = {
415
+ setKeyPairsDispatcher: (dispatcher$1) => {
416
+ callbacks.keyPairsDispatcher = (ctx, identifier) => this._getTracer().startActiveSpan("activitypub.dispatch_actor_key_pairs", {
417
+ kind: SpanKind.SERVER,
418
+ attributes: {
419
+ "activitypub.actor.id": ctx.getActorUri(identifier).href,
420
+ "fedify.actor.identifier": identifier
421
+ }
422
+ }, async (span) => {
423
+ try {
424
+ return await dispatcher$1(ctx, identifier);
425
+ } catch (e) {
426
+ span.setStatus({
427
+ code: SpanStatusCode.ERROR,
428
+ message: String(e)
429
+ });
430
+ throw e;
431
+ } finally {
432
+ span.end();
433
+ }
434
+ });
435
+ return setters;
436
+ },
437
+ mapHandle(mapper) {
438
+ callbacks.handleMapper = mapper;
439
+ return setters;
440
+ },
441
+ mapAlias(mapper) {
442
+ callbacks.aliasMapper = mapper;
443
+ return setters;
444
+ },
445
+ authorize(predicate) {
446
+ callbacks.authorizePredicate = predicate;
447
+ return setters;
448
+ }
449
+ };
450
+ return setters;
451
+ }
452
+ setNodeInfoDispatcher(path, dispatcher) {
453
+ if (this.router.has("nodeInfo")) throw new RouterError("NodeInfo dispatcher already set.");
454
+ if (this.router.add(path, "nodeInfo").size !== 0) throw new RouterError("Path for NodeInfo dispatcher must have no variables.");
455
+ this.nodeInfoDispatcher = dispatcher;
456
+ }
457
+ setObjectDispatcher(cls, path, dispatcher) {
458
+ const routeName = `object:${cls.typeId.href}`;
459
+ if (this.router.has(routeName)) throw new RouterError(`Object dispatcher for ${cls.name} already set.`);
460
+ const variables = this.router.add(path, routeName);
461
+ if (variables.size < 1) throw new RouterError("Path for object dispatcher must have at least one variable.");
462
+ const callbacks = {
463
+ dispatcher: (ctx, values) => {
464
+ return this._getTracer().startActiveSpan("activitypub.dispatch_object", {
465
+ kind: SpanKind.SERVER,
466
+ attributes: {
467
+ "fedify.object.type": cls.typeId.href,
468
+ ...globalThis.Object.fromEntries(globalThis.Object.entries(values).map(([k, v]) => [`fedify.object.values.${k}`, v]))
469
+ }
470
+ }, async (span) => {
471
+ try {
472
+ const object = await dispatcher(ctx, values);
473
+ span.setAttribute("activitypub.object.id", (object?.id ?? ctx.getObjectUri(cls, values)).href);
474
+ if (object == null) span.setStatus({ code: SpanStatusCode.ERROR });
475
+ else span.setAttribute("activitypub.object.type", getTypeId(object).href);
476
+ return object;
477
+ } catch (e) {
478
+ span.setStatus({
479
+ code: SpanStatusCode.ERROR,
480
+ message: String(e)
481
+ });
482
+ throw e;
483
+ } finally {
484
+ span.end();
485
+ }
486
+ });
487
+ },
488
+ parameters: variables
489
+ };
490
+ this.objectCallbacks[cls.typeId.href] = callbacks;
491
+ this.objectTypeIds[cls.typeId.href] = cls;
492
+ const setters = { authorize(predicate) {
493
+ callbacks.authorizePredicate = predicate;
494
+ return setters;
495
+ } };
496
+ return setters;
497
+ }
498
+ setInboxDispatcher(path, dispatcher) {
499
+ if (this.inboxCallbacks != null) throw new RouterError("Inbox dispatcher already set.");
500
+ if (this.router.has("inbox")) {
501
+ if (this.inboxPath !== path) throw new RouterError("Inbox dispatcher path must match inbox listener path.");
502
+ } else {
503
+ const variables = this.router.add(path, "inbox");
504
+ if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for inbox dispatcher must have one variable: {identifier}");
505
+ if (variables.has("handle")) getLogger([
506
+ "fedify",
507
+ "federation",
508
+ "inbox"
509
+ ]).warn("The {{handle}} variable in the inbox dispatcher path is deprecated. Use {{identifier}} instead.");
510
+ this.inboxPath = path;
199
511
  }
200
- });
201
- }
202
- async function handleWebFingerInternal(request, { context: context$1, host, actorDispatcher, actorHandleMapper, actorAliasMapper, onNotFound, span }) {
203
- if (actorDispatcher == null) return await onNotFound(request);
204
- const resource = context$1.url.searchParams.get("resource");
205
- if (resource == null) return new Response("Missing resource parameter.", { status: 400 });
206
- span?.setAttribute("webfinger.resource", resource);
207
- let resourceUrl;
208
- try {
209
- resourceUrl = new URL(resource);
210
- } catch (e) {
211
- if (e instanceof TypeError) return new Response("Invalid resource URL.", { status: 400 });
212
- throw e;
512
+ const callbacks = { dispatcher };
513
+ this.inboxCallbacks = callbacks;
514
+ const setters = {
515
+ setCounter(counter) {
516
+ callbacks.counter = counter;
517
+ return setters;
518
+ },
519
+ setFirstCursor(cursor) {
520
+ callbacks.firstCursor = cursor;
521
+ return setters;
522
+ },
523
+ setLastCursor(cursor) {
524
+ callbacks.lastCursor = cursor;
525
+ return setters;
526
+ },
527
+ authorize(predicate) {
528
+ callbacks.authorizePredicate = predicate;
529
+ return setters;
530
+ }
531
+ };
532
+ return setters;
213
533
  }
214
- span?.setAttribute("webfinger.resource.scheme", resourceUrl.protocol.replace(/:$/, ""));
215
- if (actorDispatcher == null) {
216
- logger.error("Actor dispatcher is not set.");
217
- return await onNotFound(request);
534
+ setOutboxDispatcher(path, dispatcher) {
535
+ if (this.router.has("outbox")) throw new RouterError("Outbox dispatcher already set.");
536
+ const variables = this.router.add(path, "outbox");
537
+ if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for outbox dispatcher must have one variable: {identifier}");
538
+ if (variables.has("handle")) getLogger([
539
+ "fedify",
540
+ "federation",
541
+ "outbox"
542
+ ]).warn("The {{handle}} variable in the outbox dispatcher path is deprecated. Use {{identifier}} instead.");
543
+ const callbacks = { dispatcher };
544
+ this.outboxCallbacks = callbacks;
545
+ const setters = {
546
+ setCounter(counter) {
547
+ callbacks.counter = counter;
548
+ return setters;
549
+ },
550
+ setFirstCursor(cursor) {
551
+ callbacks.firstCursor = cursor;
552
+ return setters;
553
+ },
554
+ setLastCursor(cursor) {
555
+ callbacks.lastCursor = cursor;
556
+ return setters;
557
+ },
558
+ authorize(predicate) {
559
+ callbacks.authorizePredicate = predicate;
560
+ return setters;
561
+ }
562
+ };
563
+ return setters;
218
564
  }
219
- async function mapUsernameToIdentifier(username) {
220
- if (actorHandleMapper == null) {
221
- logger.error("No actor handle mapper is set; use the WebFinger username {username} as the actor's internal identifier.", { username });
222
- return username;
223
- }
224
- const identifier$1 = await actorHandleMapper(context$1, username);
225
- if (identifier$1 == null) {
226
- logger.error("Actor {username} not found.", { username });
227
- return null;
228
- }
229
- return identifier$1;
565
+ setFollowingDispatcher(path, dispatcher) {
566
+ if (this.router.has("following")) throw new RouterError("Following collection dispatcher already set.");
567
+ const variables = this.router.add(path, "following");
568
+ if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for following collection dispatcher must have one variable: {identifier}");
569
+ if (variables.has("handle")) getLogger([
570
+ "fedify",
571
+ "federation",
572
+ "collection"
573
+ ]).warn("The {{handle}} variable in the following collection dispatcher path is deprecated. Use {{identifier}} instead.");
574
+ const callbacks = { dispatcher };
575
+ this.followingCallbacks = callbacks;
576
+ const setters = {
577
+ setCounter(counter) {
578
+ callbacks.counter = counter;
579
+ return setters;
580
+ },
581
+ setFirstCursor(cursor) {
582
+ callbacks.firstCursor = cursor;
583
+ return setters;
584
+ },
585
+ setLastCursor(cursor) {
586
+ callbacks.lastCursor = cursor;
587
+ return setters;
588
+ },
589
+ authorize(predicate) {
590
+ callbacks.authorizePredicate = predicate;
591
+ return setters;
592
+ }
593
+ };
594
+ return setters;
230
595
  }
231
- let identifier = null;
232
- const uriParsed = context$1.parseUri(resourceUrl);
233
- if (uriParsed?.type != "actor") {
234
- const match = /^acct:([^@]+)@([^@]+)$/.exec(resource);
235
- if (match == null) {
236
- const result = await actorAliasMapper?.(context$1, resourceUrl);
237
- if (result == null) return await onNotFound(request);
238
- if ("identifier" in result) identifier = result.identifier;
239
- else identifier = await mapUsernameToIdentifier(result.username);
240
- } else {
241
- const portMatch = /:\d+$/.exec(match[2]);
242
- const normalizedHost = portMatch == null ? domainToASCII(match[2].toLowerCase()) : domainToASCII(match[2].substring(0, portMatch.index).toLowerCase()) + portMatch[0];
243
- if (normalizedHost != context$1.url.host && normalizedHost != host) return await onNotFound(request);
244
- else {
245
- identifier = await mapUsernameToIdentifier(match[1]);
246
- resourceUrl = new URL(`acct:${match[1]}@${normalizedHost}`);
596
+ setFollowersDispatcher(path, dispatcher) {
597
+ if (this.router.has("followers")) throw new RouterError("Followers collection dispatcher already set.");
598
+ const variables = this.router.add(path, "followers");
599
+ if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for followers collection dispatcher must have one variable: {identifier}");
600
+ if (variables.has("handle")) getLogger([
601
+ "fedify",
602
+ "federation",
603
+ "collection"
604
+ ]).warn("The {{handle}} variable in the followers collection dispatcher path is deprecated. Use {{identifier}} instead.");
605
+ const callbacks = { dispatcher };
606
+ this.followersCallbacks = callbacks;
607
+ const setters = {
608
+ setCounter(counter) {
609
+ callbacks.counter = counter;
610
+ return setters;
611
+ },
612
+ setFirstCursor(cursor) {
613
+ callbacks.firstCursor = cursor;
614
+ return setters;
615
+ },
616
+ setLastCursor(cursor) {
617
+ callbacks.lastCursor = cursor;
618
+ return setters;
619
+ },
620
+ authorize(predicate) {
621
+ callbacks.authorizePredicate = predicate;
622
+ return setters;
247
623
  }
248
- }
249
- } else identifier = uriParsed.identifier;
250
- if (identifier == null) return await onNotFound(request);
251
- const actor = await actorDispatcher(context$1, identifier);
252
- if (actor == null) {
253
- logger.error("Actor {identifier} not found.", { identifier });
254
- return await onNotFound(request);
624
+ };
625
+ return setters;
255
626
  }
256
- const links = [{
257
- rel: "self",
258
- href: context$1.getActorUri(identifier).href,
259
- type: "application/activity+json"
260
- }];
261
- for (const url of actor.urls) if (url instanceof Link && url.href != null) links.push({
262
- rel: url.rel ?? "http://webfinger.net/rel/profile-page",
263
- href: url.href.href,
264
- type: url.mediaType == null ? void 0 : url.mediaType
265
- });
266
- else if (url instanceof URL) links.push({
267
- rel: "http://webfinger.net/rel/profile-page",
268
- href: url.href
269
- });
270
- for await (const image of actor.getIcons()) {
271
- if (image.url?.href == null) continue;
272
- const link = {
273
- rel: "http://webfinger.net/rel/avatar",
274
- href: image.url.href.toString()
627
+ setLikedDispatcher(path, dispatcher) {
628
+ if (this.router.has("liked")) throw new RouterError("Liked collection dispatcher already set.");
629
+ const variables = this.router.add(path, "liked");
630
+ if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for liked collection dispatcher must have one variable: {identifier}");
631
+ if (variables.has("handle")) getLogger([
632
+ "fedify",
633
+ "federation",
634
+ "collection"
635
+ ]).warn("The {{handle}} variable in the liked collection dispatcher path is deprecated. Use {{identifier}} instead.");
636
+ const callbacks = { dispatcher };
637
+ this.likedCallbacks = callbacks;
638
+ const setters = {
639
+ setCounter(counter) {
640
+ callbacks.counter = counter;
641
+ return setters;
642
+ },
643
+ setFirstCursor(cursor) {
644
+ callbacks.firstCursor = cursor;
645
+ return setters;
646
+ },
647
+ setLastCursor(cursor) {
648
+ callbacks.lastCursor = cursor;
649
+ return setters;
650
+ },
651
+ authorize(predicate) {
652
+ callbacks.authorizePredicate = predicate;
653
+ return setters;
654
+ }
275
655
  };
276
- if (image.mediaType != null) link.type = image.mediaType;
277
- links.push(link);
656
+ return setters;
657
+ }
658
+ setFeaturedDispatcher(path, dispatcher) {
659
+ if (this.router.has("featured")) throw new RouterError("Featured collection dispatcher already set.");
660
+ const variables = this.router.add(path, "featured");
661
+ if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for featured collection dispatcher must have one variable: {identifier}");
662
+ if (variables.has("handle")) getLogger([
663
+ "fedify",
664
+ "federation",
665
+ "collection"
666
+ ]).warn("The {{handle}} variable in the featured collection dispatcher path is deprecated. Use {{identifier}} instead.");
667
+ const callbacks = { dispatcher };
668
+ this.featuredCallbacks = callbacks;
669
+ const setters = {
670
+ setCounter(counter) {
671
+ callbacks.counter = counter;
672
+ return setters;
673
+ },
674
+ setFirstCursor(cursor) {
675
+ callbacks.firstCursor = cursor;
676
+ return setters;
677
+ },
678
+ setLastCursor(cursor) {
679
+ callbacks.lastCursor = cursor;
680
+ return setters;
681
+ },
682
+ authorize(predicate) {
683
+ callbacks.authorizePredicate = predicate;
684
+ return setters;
685
+ }
686
+ };
687
+ return setters;
688
+ }
689
+ setFeaturedTagsDispatcher(path, dispatcher) {
690
+ if (this.router.has("featuredTags")) throw new RouterError("Featured tags collection dispatcher already set.");
691
+ const variables = this.router.add(path, "featuredTags");
692
+ if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for featured tags collection dispatcher must have one variable: {identifier}");
693
+ if (variables.has("handle")) getLogger([
694
+ "fedify",
695
+ "federation",
696
+ "collection"
697
+ ]).warn("The {{handle}} variable in the featured tags collection dispatcher path is deprecated. Use {{identifier}} instead.");
698
+ const callbacks = { dispatcher };
699
+ this.featuredTagsCallbacks = callbacks;
700
+ const setters = {
701
+ setCounter(counter) {
702
+ callbacks.counter = counter;
703
+ return setters;
704
+ },
705
+ setFirstCursor(cursor) {
706
+ callbacks.firstCursor = cursor;
707
+ return setters;
708
+ },
709
+ setLastCursor(cursor) {
710
+ callbacks.lastCursor = cursor;
711
+ return setters;
712
+ },
713
+ authorize(predicate) {
714
+ callbacks.authorizePredicate = predicate;
715
+ return setters;
716
+ }
717
+ };
718
+ return setters;
719
+ }
720
+ setInboxListeners(inboxPath, sharedInboxPath) {
721
+ if (this.inboxListeners != null) throw new RouterError("Inbox listeners already set.");
722
+ if (this.router.has("inbox")) {
723
+ if (this.inboxPath !== inboxPath) throw new RouterError("Inbox listener path must match inbox dispatcher path.");
724
+ } else {
725
+ const variables = this.router.add(inboxPath, "inbox");
726
+ if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for inbox must have one variable: {identifier}");
727
+ this.inboxPath = inboxPath;
728
+ if (variables.has("handle")) getLogger([
729
+ "fedify",
730
+ "federation",
731
+ "inbox"
732
+ ]).warn("The {{handle}} variable in the inbox path is deprecated. Use {{identifier}} instead.");
733
+ }
734
+ if (sharedInboxPath != null) {
735
+ if (this.router.add(sharedInboxPath, "sharedInbox").size !== 0) throw new RouterError("Path for shared inbox must have no variables.");
736
+ }
737
+ const listeners = this.inboxListeners = new InboxListenerSet();
738
+ const setters = {
739
+ on(type, listener) {
740
+ listeners.add(type, listener);
741
+ return setters;
742
+ },
743
+ onError: (handler) => {
744
+ this.inboxErrorHandler = handler;
745
+ return setters;
746
+ },
747
+ setSharedKeyDispatcher: (dispatcher) => {
748
+ this.sharedInboxKeyDispatcher = dispatcher;
749
+ return setters;
750
+ }
751
+ };
752
+ return setters;
753
+ }
754
+ };
755
+ /**
756
+ * Creates a new {@link FederationBuilder} instance.
757
+ * @returns A new {@link FederationBuilder} instance.
758
+ * @since 1.6.0
759
+ */
760
+ function createFederationBuilder() {
761
+ return new FederationBuilderImpl();
762
+ }
763
+
764
+ //#endregion
765
+ //#region federation/collection.ts
766
+ /**
767
+ * Calculates the [partial follower collection digest][1].
768
+ *
769
+ * [1]: https://w3id.org/fep/8fcf#partial-follower-collection-digest
770
+ * @param uris The URIs to calculate the digest. Duplicate URIs are ignored.
771
+ * @returns The digest.
772
+ */
773
+ async function digest(uris) {
774
+ const processed = /* @__PURE__ */ new Set();
775
+ const encoder = new TextEncoder();
776
+ const result = new Uint8Array(32);
777
+ for (const uri of uris) {
778
+ const u = uri instanceof URL ? uri.href : uri;
779
+ if (processed.has(u)) continue;
780
+ processed.add(u);
781
+ const encoded = encoder.encode(u);
782
+ const digest$1 = new Uint8Array(await crypto.subtle.digest("SHA-256", encoded));
783
+ for (let i = 0; i < 32; i++) result[i] ^= digest$1[i];
784
+ }
785
+ return result;
786
+ }
787
+ /**
788
+ * Builds [`Collection-Synchronization`][1] header content.
789
+ *
790
+ * [1]: https://w3id.org/fep/8fcf#the-collection-synchronization-http-header
791
+ *
792
+ * @param collectionId The sender's followers collection URI.
793
+ * @param actorIds The actor URIs to digest.
794
+ * @returns The header content.
795
+ */
796
+ async function buildCollectionSynchronizationHeader(collectionId, actorIds) {
797
+ const [anyActorId] = actorIds;
798
+ const baseUrl = new URL(anyActorId);
799
+ const url = new URL(collectionId);
800
+ url.searchParams.set("base-url", `${baseUrl.origin}/`);
801
+ return `collectionId="${collectionId}", url="${url}", digest="${encodeHex(await digest(actorIds))}"`;
802
+ }
803
+
804
+ //#endregion
805
+ //#region federation/keycache.ts
806
+ var KvKeyCache = class {
807
+ kv;
808
+ prefix;
809
+ options;
810
+ nullKeys;
811
+ constructor(kv, prefix, options = {}) {
812
+ this.kv = kv;
813
+ this.prefix = prefix;
814
+ this.nullKeys = /* @__PURE__ */ new Set();
815
+ this.options = options;
278
816
  }
279
- const aliases = [];
280
- if (resourceUrl.protocol != "acct:" && actor.preferredUsername != null) {
281
- aliases.push(`acct:${actor.preferredUsername}@${host ?? context$1.url.host}`);
282
- if (host != null && host !== context$1.url.host) aliases.push(`acct:${actor.preferredUsername}@${context$1.url.host}`);
817
+ async get(keyId) {
818
+ if (this.nullKeys.has(keyId.href)) return null;
819
+ const serialized = await this.kv.get([...this.prefix, keyId.href]);
820
+ if (serialized == null) return void 0;
821
+ try {
822
+ return await CryptographicKey.fromJsonLd(serialized, this.options);
823
+ } catch {
824
+ try {
825
+ return await Multikey.fromJsonLd(serialized, this.options);
826
+ } catch {
827
+ await this.kv.delete([...this.prefix, keyId.href]);
828
+ return;
829
+ }
830
+ }
283
831
  }
284
- if (resourceUrl.href !== context$1.getActorUri(identifier).href) aliases.push(context$1.getActorUri(identifier).href);
285
- if (resourceUrl.protocol === "acct:" && host != null && host !== context$1.url.host && !resourceUrl.href.endsWith(`@${host}`)) {
286
- const username = resourceUrl.href.replace(/^acct:/, "").replace(/@.*$/, "");
287
- aliases.push(`acct:${username}@${host}`);
832
+ async set(keyId, key) {
833
+ if (key == null) {
834
+ this.nullKeys.add(keyId.href);
835
+ await this.kv.delete([...this.prefix, keyId.href]);
836
+ return;
837
+ }
838
+ this.nullKeys.delete(keyId.href);
839
+ const serialized = await key.toJsonLd(this.options);
840
+ await this.kv.set([...this.prefix, keyId.href], serialized);
288
841
  }
289
- const jrd = {
290
- subject: resourceUrl.href,
291
- aliases,
292
- links
293
- };
294
- return new Response(JSON.stringify(jrd), { headers: {
295
- "Content-Type": "application/jrd+json",
296
- "Access-Control-Allow-Origin": "*"
297
- } });
298
- }
842
+ };
299
843
 
300
844
  //#endregion
301
845
  //#region federation/negotiation.ts
@@ -364,18 +908,18 @@ function acceptsJsonLd(request) {
364
908
  return types.includes("application/activity+json") || types.includes("application/ld+json") || types.includes("application/json");
365
909
  }
366
910
  async function handleActor(request, { identifier, context: context$1, actorDispatcher, authorizePredicate, onNotFound, onNotAcceptable, onUnauthorized }) {
367
- const logger$2 = getLogger([
911
+ const logger$1 = getLogger([
368
912
  "fedify",
369
913
  "federation",
370
914
  "actor"
371
915
  ]);
372
916
  if (actorDispatcher == null) {
373
- logger$2.debug("Actor dispatcher is not set.", { identifier });
917
+ logger$1.debug("Actor dispatcher is not set.", { identifier });
374
918
  return await onNotFound(request);
375
919
  }
376
920
  const actor = await actorDispatcher(context$1, identifier);
377
921
  if (actor == null) {
378
- logger$2.debug("Actor {identifier} not found.", { identifier });
922
+ logger$1.debug("Actor {identifier} not found.", { identifier });
379
923
  return await onNotFound(request);
380
924
  }
381
925
  if (!acceptsJsonLd(request)) return await onNotAcceptable(request);
@@ -621,13 +1165,13 @@ async function handleInbox(request, options) {
621
1165
  });
622
1166
  }
623
1167
  async function handleInboxInternal(request, { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider }, span) {
624
- const logger$2 = getLogger([
1168
+ const logger$1 = getLogger([
625
1169
  "fedify",
626
1170
  "federation",
627
1171
  "inbox"
628
1172
  ]);
629
1173
  if (actorDispatcher == null) {
630
- logger$2.error("Actor dispatcher is not set.", { recipient });
1174
+ logger$1.error("Actor dispatcher is not set.", { recipient });
631
1175
  span.setStatus({
632
1176
  code: SpanStatusCode.ERROR,
633
1177
  message: "Actor dispatcher is not set."
@@ -635,7 +1179,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
635
1179
  return await onNotFound(request);
636
1180
  } else if (recipient != null) {
637
1181
  if (await actorDispatcher(ctx, recipient) == null) {
638
- logger$2.error("Actor {recipient} not found.", { recipient });
1182
+ logger$1.error("Actor {recipient} not found.", { recipient });
639
1183
  span.setStatus({
640
1184
  code: SpanStatusCode.ERROR,
641
1185
  message: `Actor ${recipient} not found.`
@@ -644,7 +1188,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
644
1188
  }
645
1189
  }
646
1190
  if (request.bodyUsed) {
647
- logger$2.error("Request body has already been read.", { recipient });
1191
+ logger$1.error("Request body has already been read.", { recipient });
648
1192
  span.setStatus({
649
1193
  code: SpanStatusCode.ERROR,
650
1194
  message: "Request body has already been read."
@@ -654,7 +1198,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
654
1198
  headers: { "Content-Type": "text/plain; charset=utf-8" }
655
1199
  });
656
1200
  } else if (request.body?.locked) {
657
- logger$2.error("Request body is locked.", { recipient });
1201
+ logger$1.error("Request body is locked.", { recipient });
658
1202
  span.setStatus({
659
1203
  code: SpanStatusCode.ERROR,
660
1204
  message: "Request body is locked."
@@ -668,14 +1212,14 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
668
1212
  try {
669
1213
  json = await request.clone().json();
670
1214
  } catch (error) {
671
- logger$2.error("Failed to parse JSON:\n{error}", {
1215
+ logger$1.error("Failed to parse JSON:\n{error}", {
672
1216
  recipient,
673
1217
  error
674
1218
  });
675
1219
  try {
676
1220
  await inboxErrorHandler?.(ctx, error);
677
1221
  } catch (error$1) {
678
- logger$2.error("An unexpected error occurred in inbox error handler:\n{error}", {
1222
+ logger$1.error("An unexpected error occurred in inbox error handler:\n{error}", {
679
1223
  error: error$1,
680
1224
  activity: json,
681
1225
  recipient
@@ -701,7 +1245,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
701
1245
  });
702
1246
  } catch (error) {
703
1247
  if (error instanceof Error && error.name === "jsonld.SyntaxError") {
704
- logger$2.error("Failed to parse JSON-LD:\n{error}", {
1248
+ logger$1.error("Failed to parse JSON-LD:\n{error}", {
705
1249
  recipient,
706
1250
  error
707
1251
  });
@@ -715,13 +1259,13 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
715
1259
  const jsonWithoutSig = detachSignature(json);
716
1260
  let activity = null;
717
1261
  if (ldSigVerified) {
718
- logger$2.debug("Linked Data Signatures are verified.", {
1262
+ logger$1.debug("Linked Data Signatures are verified.", {
719
1263
  recipient,
720
1264
  json
721
1265
  });
722
1266
  activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
723
1267
  } else {
724
- logger$2.debug("Linked Data Signatures are not verified.", {
1268
+ logger$1.debug("Linked Data Signatures are not verified.", {
725
1269
  recipient,
726
1270
  json
727
1271
  });
@@ -733,7 +1277,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
733
1277
  tracerProvider
734
1278
  });
735
1279
  } catch (error) {
736
- logger$2.error("Failed to parse activity:\n{error}", {
1280
+ logger$1.error("Failed to parse activity:\n{error}", {
737
1281
  recipient,
738
1282
  activity: json,
739
1283
  error
@@ -741,7 +1285,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
741
1285
  try {
742
1286
  await inboxErrorHandler?.(ctx, error);
743
1287
  } catch (error$1) {
744
- logger$2.error("An unexpected error occurred in inbox error handler:\n{error}", {
1288
+ logger$1.error("An unexpected error occurred in inbox error handler:\n{error}", {
745
1289
  error: error$1,
746
1290
  activity: json,
747
1291
  recipient
@@ -756,11 +1300,11 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
756
1300
  headers: { "Content-Type": "text/plain; charset=utf-8" }
757
1301
  });
758
1302
  }
759
- if (activity == null) logger$2.debug("Object Integrity Proofs are not verified.", {
1303
+ if (activity == null) logger$1.debug("Object Integrity Proofs are not verified.", {
760
1304
  recipient,
761
1305
  activity: json
762
1306
  });
763
- else logger$2.debug("Object Integrity Proofs are verified.", {
1307
+ else logger$1.debug("Object Integrity Proofs are verified.", {
764
1308
  recipient,
765
1309
  activity: json
766
1310
  });
@@ -776,7 +1320,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
776
1320
  tracerProvider
777
1321
  });
778
1322
  if (key == null) {
779
- logger$2.error("Failed to verify the request's HTTP Signatures.", { recipient });
1323
+ logger$1.error("Failed to verify the request's HTTP Signatures.", { recipient });
780
1324
  span.setStatus({
781
1325
  code: SpanStatusCode.ERROR,
782
1326
  message: `Failed to verify the request's HTTP Signatures.`
@@ -785,7 +1329,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
785
1329
  status: 401,
786
1330
  headers: { "Content-Type": "text/plain; charset=utf-8" }
787
1331
  });
788
- } else logger$2.debug("HTTP Signatures are verified.", { recipient });
1332
+ } else logger$1.debug("HTTP Signatures are verified.", { recipient });
789
1333
  httpSigKey = key;
790
1334
  }
791
1335
  activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
@@ -793,7 +1337,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
793
1337
  if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
794
1338
  span.setAttribute("activitypub.activity.type", getTypeId(activity).href);
795
1339
  if (httpSigKey != null && !await doesActorOwnKey(activity, httpSigKey, ctx)) {
796
- logger$2.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
1340
+ logger$1.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
797
1341
  activity: json,
798
1342
  recipient,
799
1343
  keyId: httpSigKey.id?.href,
@@ -874,6 +1418,320 @@ async function respondWithObjectIfAcceptable(object, request, options) {
874
1418
  return response;
875
1419
  }
876
1420
 
1421
+ //#endregion
1422
+ //#region nodeinfo/handler.ts
1423
+ /**
1424
+ * Handles a NodeInfo request. You would not typically call this function
1425
+ * directly, but instead use {@link Federation.handle} method.
1426
+ * @param request The NodeInfo request to handle.
1427
+ * @param parameters The parameters for handling the request.
1428
+ * @returns The response to the request.
1429
+ */
1430
+ async function handleNodeInfo(_request, { context: context$1, nodeInfoDispatcher }) {
1431
+ const promise = nodeInfoDispatcher(context$1);
1432
+ const json = nodeInfoToJson(promise instanceof Promise ? await promise : promise);
1433
+ return new Response(JSON.stringify(json), { headers: { "Content-Type": "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\"" } });
1434
+ }
1435
+ /**
1436
+ * Handles a request to `/.well-known/nodeinfo`. You would not typically call
1437
+ * this function directly, but instead use {@link Federation.handle} method.
1438
+ * @param request The request to handle.
1439
+ * @param context The request context.
1440
+ * @returns The response to the request.
1441
+ */
1442
+ function handleNodeInfoJrd(_request, context$1) {
1443
+ const links = [];
1444
+ try {
1445
+ links.push({
1446
+ rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
1447
+ href: context$1.getNodeInfoUri().href,
1448
+ type: "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\""
1449
+ });
1450
+ } catch (e) {
1451
+ if (!(e instanceof RouterError)) throw e;
1452
+ }
1453
+ const jrd = { links };
1454
+ const response = new Response(JSON.stringify(jrd), { headers: { "Content-Type": "application/jrd+json" } });
1455
+ return Promise.resolve(response);
1456
+ }
1457
+
1458
+ //#endregion
1459
+ //#region webfinger/handler.ts
1460
+ const logger = getLogger([
1461
+ "fedify",
1462
+ "webfinger",
1463
+ "server"
1464
+ ]);
1465
+ /**
1466
+ * Handles a WebFinger request. You would not typically call this function
1467
+ * directly, but instead use {@link Federation.fetch} method.
1468
+ * @param request The WebFinger request to handle.
1469
+ * @param parameters The parameters for handling the request.
1470
+ * @returns The response to the request.
1471
+ */
1472
+ async function handleWebFinger(request, options) {
1473
+ if (options.tracer == null) return await handleWebFingerInternal(request, options);
1474
+ return await options.tracer.startActiveSpan("webfinger.handle", { kind: SpanKind.SERVER }, async (span) => {
1475
+ try {
1476
+ const response = await handleWebFingerInternal(request, options);
1477
+ span.setStatus({ code: response.ok ? SpanStatusCode.UNSET : SpanStatusCode.ERROR });
1478
+ return response;
1479
+ } catch (error) {
1480
+ span.setStatus({
1481
+ code: SpanStatusCode.ERROR,
1482
+ message: String(error)
1483
+ });
1484
+ throw error;
1485
+ } finally {
1486
+ span.end();
1487
+ }
1488
+ });
1489
+ }
1490
+ async function handleWebFingerInternal(request, { context: context$1, host, actorDispatcher, actorHandleMapper, actorAliasMapper, onNotFound, span }) {
1491
+ if (actorDispatcher == null) return await onNotFound(request);
1492
+ const resource = context$1.url.searchParams.get("resource");
1493
+ if (resource == null) return new Response("Missing resource parameter.", { status: 400 });
1494
+ span?.setAttribute("webfinger.resource", resource);
1495
+ let resourceUrl;
1496
+ try {
1497
+ resourceUrl = new URL(resource);
1498
+ } catch (e) {
1499
+ if (e instanceof TypeError) return new Response("Invalid resource URL.", { status: 400 });
1500
+ throw e;
1501
+ }
1502
+ span?.setAttribute("webfinger.resource.scheme", resourceUrl.protocol.replace(/:$/, ""));
1503
+ if (actorDispatcher == null) {
1504
+ logger.error("Actor dispatcher is not set.");
1505
+ return await onNotFound(request);
1506
+ }
1507
+ async function mapUsernameToIdentifier(username) {
1508
+ if (actorHandleMapper == null) {
1509
+ logger.error("No actor handle mapper is set; use the WebFinger username {username} as the actor's internal identifier.", { username });
1510
+ return username;
1511
+ }
1512
+ const identifier$1 = await actorHandleMapper(context$1, username);
1513
+ if (identifier$1 == null) {
1514
+ logger.error("Actor {username} not found.", { username });
1515
+ return null;
1516
+ }
1517
+ return identifier$1;
1518
+ }
1519
+ let identifier = null;
1520
+ const uriParsed = context$1.parseUri(resourceUrl);
1521
+ if (uriParsed?.type != "actor") {
1522
+ const match = /^acct:([^@]+)@([^@]+)$/.exec(resource);
1523
+ if (match == null) {
1524
+ const result = await actorAliasMapper?.(context$1, resourceUrl);
1525
+ if (result == null) return await onNotFound(request);
1526
+ if ("identifier" in result) identifier = result.identifier;
1527
+ else identifier = await mapUsernameToIdentifier(result.username);
1528
+ } else {
1529
+ const portMatch = /:\d+$/.exec(match[2]);
1530
+ const normalizedHost = portMatch == null ? domainToASCII(match[2].toLowerCase()) : domainToASCII(match[2].substring(0, portMatch.index).toLowerCase()) + portMatch[0];
1531
+ if (normalizedHost != context$1.url.host && normalizedHost != host) return await onNotFound(request);
1532
+ else {
1533
+ identifier = await mapUsernameToIdentifier(match[1]);
1534
+ resourceUrl = new URL(`acct:${match[1]}@${normalizedHost}`);
1535
+ }
1536
+ }
1537
+ } else identifier = uriParsed.identifier;
1538
+ if (identifier == null) return await onNotFound(request);
1539
+ const actor = await actorDispatcher(context$1, identifier);
1540
+ if (actor == null) {
1541
+ logger.error("Actor {identifier} not found.", { identifier });
1542
+ return await onNotFound(request);
1543
+ }
1544
+ const links = [{
1545
+ rel: "self",
1546
+ href: context$1.getActorUri(identifier).href,
1547
+ type: "application/activity+json"
1548
+ }];
1549
+ for (const url of actor.urls) if (url instanceof Link && url.href != null) links.push({
1550
+ rel: url.rel ?? "http://webfinger.net/rel/profile-page",
1551
+ href: url.href.href,
1552
+ type: url.mediaType == null ? void 0 : url.mediaType
1553
+ });
1554
+ else if (url instanceof URL) links.push({
1555
+ rel: "http://webfinger.net/rel/profile-page",
1556
+ href: url.href
1557
+ });
1558
+ for await (const image of actor.getIcons()) {
1559
+ if (image.url?.href == null) continue;
1560
+ const link = {
1561
+ rel: "http://webfinger.net/rel/avatar",
1562
+ href: image.url.href.toString()
1563
+ };
1564
+ if (image.mediaType != null) link.type = image.mediaType;
1565
+ links.push(link);
1566
+ }
1567
+ const aliases = [];
1568
+ if (resourceUrl.protocol != "acct:" && actor.preferredUsername != null) {
1569
+ aliases.push(`acct:${actor.preferredUsername}@${host ?? context$1.url.host}`);
1570
+ if (host != null && host !== context$1.url.host) aliases.push(`acct:${actor.preferredUsername}@${context$1.url.host}`);
1571
+ }
1572
+ if (resourceUrl.href !== context$1.getActorUri(identifier).href) aliases.push(context$1.getActorUri(identifier).href);
1573
+ if (resourceUrl.protocol === "acct:" && host != null && host !== context$1.url.host && !resourceUrl.href.endsWith(`@${host}`)) {
1574
+ const username = resourceUrl.href.replace(/^acct:/, "").replace(/@.*$/, "");
1575
+ aliases.push(`acct:${username}@${host}`);
1576
+ }
1577
+ const jrd = {
1578
+ subject: resourceUrl.href,
1579
+ aliases,
1580
+ links
1581
+ };
1582
+ return new Response(JSON.stringify(jrd), { headers: {
1583
+ "Content-Type": "application/jrd+json",
1584
+ "Access-Control-Allow-Origin": "*"
1585
+ } });
1586
+ }
1587
+
1588
+ //#endregion
1589
+ //#region federation/retry.ts
1590
+ /**
1591
+ * Creates an exponential backoff retry policy. The delay between retries
1592
+ * starts at the `initialDelay` and is multiplied by the `factor` for each
1593
+ * subsequent retry, up to the `maxDelay`. The policy will give up after
1594
+ * `maxAttempts` attempts. The actual delay is randomized to avoid
1595
+ * synchronization (jitter).
1596
+ * @param options The options for the policy.
1597
+ * @returns The retry policy.
1598
+ * @since 0.12.0
1599
+ */
1600
+ function createExponentialBackoffPolicy(options = {}) {
1601
+ const initialDelay = Temporal.Duration.from(options.initialDelay ?? { seconds: 1 });
1602
+ const maxDelay = Temporal.Duration.from(options.maxDelay ?? { hours: 12 });
1603
+ const maxAttempts = options.maxAttempts ?? 10;
1604
+ const factor = options.factor ?? 2;
1605
+ const jitter = options.jitter ?? true;
1606
+ return ({ attempts }) => {
1607
+ if (attempts >= maxAttempts) return null;
1608
+ let milliseconds = initialDelay.total("millisecond");
1609
+ milliseconds *= factor ** attempts;
1610
+ if (jitter) {
1611
+ milliseconds *= 1 + Math.random();
1612
+ milliseconds = Math.round(milliseconds);
1613
+ }
1614
+ const delay$1 = Temporal.Duration.from({ milliseconds });
1615
+ return Temporal.Duration.compare(delay$1, maxDelay) > 0 ? maxDelay : delay$1;
1616
+ };
1617
+ }
1618
+
1619
+ //#endregion
1620
+ //#region federation/send.ts
1621
+ /**
1622
+ * Extracts the inbox URLs from recipients.
1623
+ * @param parameters The parameters to extract the inboxes.
1624
+ * See also {@link ExtractInboxesParameters}.
1625
+ * @returns The inboxes as a map of inbox URL to actor URIs.
1626
+ */
1627
+ function extractInboxes({ recipients, preferSharedInbox, excludeBaseUris }) {
1628
+ const inboxes = {};
1629
+ for (const recipient of recipients) {
1630
+ let inbox;
1631
+ let sharedInbox = false;
1632
+ if (preferSharedInbox && recipient.endpoints?.sharedInbox != null) {
1633
+ inbox = recipient.endpoints.sharedInbox;
1634
+ sharedInbox = true;
1635
+ } else inbox = recipient.inboxId;
1636
+ if (inbox != null && recipient.id != null) {
1637
+ if (excludeBaseUris != null && excludeBaseUris.some((u) => u.origin === inbox?.origin)) continue;
1638
+ inboxes[inbox.href] ??= {
1639
+ actorIds: /* @__PURE__ */ new Set(),
1640
+ sharedInbox
1641
+ };
1642
+ inboxes[inbox.href].actorIds.add(recipient.id.href);
1643
+ }
1644
+ }
1645
+ return inboxes;
1646
+ }
1647
+ /**
1648
+ * Sends an {@link Activity} to an inbox.
1649
+ *
1650
+ * @param parameters The parameters for sending the activity.
1651
+ * See also {@link SendActivityParameters}.
1652
+ * @throws {Error} If the activity fails to send.
1653
+ */
1654
+ function sendActivity(options) {
1655
+ const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
1656
+ return tracerProvider.getTracer(name, version).startActiveSpan("activitypub.send_activity", {
1657
+ kind: SpanKind.CLIENT,
1658
+ attributes: { "activitypub.shared_inbox": options.sharedInbox ?? false }
1659
+ }, async (span) => {
1660
+ if (options.activityId != null) span.setAttribute("activitypub.activity.id", options.activityId);
1661
+ if (options.activityType != null) span.setAttribute("activitypub.activity.type", options.activityType);
1662
+ try {
1663
+ await sendActivityInternal({
1664
+ ...options,
1665
+ tracerProvider
1666
+ });
1667
+ } catch (e) {
1668
+ span.setStatus({
1669
+ code: SpanStatusCode.ERROR,
1670
+ message: String(e)
1671
+ });
1672
+ throw e;
1673
+ } finally {
1674
+ span.end();
1675
+ }
1676
+ });
1677
+ }
1678
+ async function sendActivityInternal({ activity, activityId, keys, inbox, headers, specDeterminer, tracerProvider }) {
1679
+ const logger$1 = getLogger([
1680
+ "fedify",
1681
+ "federation",
1682
+ "outbox"
1683
+ ]);
1684
+ headers = new Headers(headers);
1685
+ headers.set("Content-Type", "application/activity+json");
1686
+ const request = new Request(inbox, {
1687
+ method: "POST",
1688
+ headers,
1689
+ body: JSON.stringify(activity)
1690
+ });
1691
+ let rsaKey = null;
1692
+ for (const key of keys) if (key.privateKey.algorithm.name === "RSASSA-PKCS1-v1_5") {
1693
+ rsaKey = key;
1694
+ break;
1695
+ }
1696
+ if (rsaKey == null) logger$1.warn("No supported key found to sign the request to {inbox}. The request will be sent without a signature. In order to sign the request, at least one RSASSA-PKCS1-v1_5 key must be provided.", {
1697
+ inbox: inbox.href,
1698
+ keys: keys.map((pair) => ({
1699
+ keyId: pair.keyId.href,
1700
+ privateKey: pair.privateKey
1701
+ }))
1702
+ });
1703
+ let response;
1704
+ try {
1705
+ response = rsaKey == null ? await fetch(request) : await doubleKnock(request, rsaKey, {
1706
+ tracerProvider,
1707
+ specDeterminer
1708
+ });
1709
+ } catch (error) {
1710
+ logger$1.error("Failed to send activity {activityId} to {inbox}:\n{error}", {
1711
+ activityId,
1712
+ inbox: inbox.href,
1713
+ error
1714
+ });
1715
+ throw error;
1716
+ }
1717
+ if (!response.ok) {
1718
+ let error;
1719
+ try {
1720
+ error = await response.text();
1721
+ } catch (_) {
1722
+ error = "";
1723
+ }
1724
+ logger$1.error("Failed to send activity {activityId} to {inbox} ({status} {statusText}):\n{error}", {
1725
+ activityId,
1726
+ inbox: inbox.href,
1727
+ status: response.status,
1728
+ statusText: response.statusText,
1729
+ error
1730
+ });
1731
+ throw new Error(`Failed to send activity ${activityId} to ${inbox.href} (${response.status} ${response.statusText}):\n${error}`);
1732
+ }
1733
+ }
1734
+
877
1735
  //#endregion
878
1736
  //#region federation/middleware.ts
879
1737
  /**
@@ -911,7 +1769,7 @@ var FederationImpl = class extends FederationBuilderImpl {
911
1769
  firstKnock;
912
1770
  constructor(options) {
913
1771
  super();
914
- const logger$2 = getLogger(["fedify", "federation"]);
1772
+ const logger$1 = getLogger(["fedify", "federation"]);
915
1773
  this.kv = options.kv;
916
1774
  this.kvPrefixes = {
917
1775
  activityIdempotence: ["_fedify", "activityIdempotence"],
@@ -968,7 +1826,7 @@ var FederationImpl = class extends FederationBuilderImpl {
968
1826
  if (options.documentLoader != null) {
969
1827
  if (options.documentLoaderFactory != null) throw new TypeError("Cannot set both documentLoader and documentLoaderFactory options at a time; use documentLoaderFactory only.");
970
1828
  this.documentLoaderFactory = () => options.documentLoader;
971
- logger$2.warn("The documentLoader option is deprecated; use documentLoaderFactory option instead.");
1829
+ logger$1.warn("The documentLoader option is deprecated; use documentLoaderFactory option instead.");
972
1830
  } else this.documentLoaderFactory = options.documentLoaderFactory ?? ((opts) => {
973
1831
  return kvCache({
974
1832
  loader: getDocumentLoader({
@@ -982,7 +1840,7 @@ var FederationImpl = class extends FederationBuilderImpl {
982
1840
  if (options.contextLoader != null) {
983
1841
  if (options.contextLoaderFactory != null) throw new TypeError("Cannot set both contextLoader and contextLoaderFactory options at a time; use contextLoaderFactory only.");
984
1842
  this.contextLoaderFactory = () => options.contextLoader;
985
- logger$2.warn("The contextLoader option is deprecated; use contextLoaderFactory option instead.");
1843
+ logger$1.warn("The contextLoader option is deprecated; use contextLoaderFactory option instead.");
986
1844
  } else this.contextLoaderFactory = options.contextLoaderFactory ?? this.documentLoaderFactory;
987
1845
  this.authenticatedDocumentLoaderFactory = options.authenticatedDocumentLoaderFactory ?? ((identity) => getAuthenticatedDocumentLoader(identity, {
988
1846
  allowPrivateAddress,
@@ -1009,24 +1867,24 @@ var FederationImpl = class extends FederationBuilderImpl {
1009
1867
  }
1010
1868
  async _startQueueInternal(ctxData, signal, queue) {
1011
1869
  if (this.inboxQueue == null && this.outboxQueue == null) return;
1012
- const logger$2 = getLogger([
1870
+ const logger$1 = getLogger([
1013
1871
  "fedify",
1014
1872
  "federation",
1015
1873
  "queue"
1016
1874
  ]);
1017
1875
  const promises = [];
1018
1876
  if (this.inboxQueue != null && (queue == null || queue === "inbox") && !this.inboxQueueStarted) {
1019
- logger$2.debug("Starting an inbox task worker.");
1877
+ logger$1.debug("Starting an inbox task worker.");
1020
1878
  this.inboxQueueStarted = true;
1021
1879
  promises.push(this.inboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
1022
1880
  }
1023
1881
  if (this.outboxQueue != null && this.outboxQueue !== this.inboxQueue && (queue == null || queue === "outbox") && !this.outboxQueueStarted) {
1024
- logger$2.debug("Starting an outbox task worker.");
1882
+ logger$1.debug("Starting an outbox task worker.");
1025
1883
  this.outboxQueueStarted = true;
1026
1884
  promises.push(this.outboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
1027
1885
  }
1028
1886
  if (this.fanoutQueue != null && this.fanoutQueue !== this.inboxQueue && this.fanoutQueue !== this.outboxQueue && (queue == null || queue === "fanout") && !this.fanoutQueueStarted) {
1029
- logger$2.debug("Starting a fanout task worker.");
1887
+ logger$1.debug("Starting a fanout task worker.");
1030
1888
  this.fanoutQueueStarted = true;
1031
1889
  promises.push(this.fanoutQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
1032
1890
  }
@@ -1125,7 +1983,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1125
1983
  });
1126
1984
  }
1127
1985
  async #listenOutboxMessage(_, message, span) {
1128
- const logger$2 = getLogger([
1986
+ const logger$1 = getLogger([
1129
1987
  "fedify",
1130
1988
  "federation",
1131
1989
  "outbox"
@@ -1174,41 +2032,41 @@ var FederationImpl = class extends FederationBuilderImpl {
1174
2032
  try {
1175
2033
  this.onOutboxError?.(error, activity);
1176
2034
  } catch (error$1) {
1177
- logger$2.error("An unexpected error occurred in onError handler:\n{error}", {
2035
+ logger$1.error("An unexpected error occurred in onError handler:\n{error}", {
1178
2036
  ...logData,
1179
2037
  error: error$1
1180
2038
  });
1181
2039
  }
1182
2040
  if (this.outboxQueue?.nativeRetrial) {
1183
- logger$2.error("Failed to send activity {activityId} to {inbox}; backend will handle retry:\n{error}", {
2041
+ logger$1.error("Failed to send activity {activityId} to {inbox}; backend will handle retry:\n{error}", {
1184
2042
  ...logData,
1185
2043
  error
1186
2044
  });
1187
2045
  throw error;
1188
2046
  }
1189
- const delay = this.outboxRetryPolicy({
2047
+ const delay$1 = this.outboxRetryPolicy({
1190
2048
  elapsedTime: Temporal.Instant.from(message.started).until(Temporal.Now.instant()),
1191
2049
  attempts: message.attempt
1192
2050
  });
1193
- if (delay != null) {
1194
- logger$2.error("Failed to send activity {activityId} to {inbox} (attempt #{attempt}); retry...:\n{error}", {
2051
+ if (delay$1 != null) {
2052
+ logger$1.error("Failed to send activity {activityId} to {inbox} (attempt #{attempt}); retry...:\n{error}", {
1195
2053
  ...logData,
1196
2054
  error
1197
2055
  });
1198
2056
  await this.outboxQueue?.enqueue({
1199
2057
  ...message,
1200
2058
  attempt: message.attempt + 1
1201
- }, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
1202
- } else logger$2.error("Failed to send activity {activityId} to {inbox} after {attempt} attempts; giving up:\n{error}", {
2059
+ }, { delay: Temporal.Duration.compare(delay$1, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay$1 });
2060
+ } else logger$1.error("Failed to send activity {activityId} to {inbox} after {attempt} attempts; giving up:\n{error}", {
1203
2061
  ...logData,
1204
2062
  error
1205
2063
  });
1206
2064
  return;
1207
2065
  }
1208
- logger$2.info("Successfully sent activity {activityId} to {inbox}.", { ...logData });
2066
+ logger$1.info("Successfully sent activity {activityId} to {inbox}.", { ...logData });
1209
2067
  }
1210
2068
  async #listenInboxMessage(ctxData, message, span) {
1211
- const logger$2 = getLogger([
2069
+ const logger$1 = getLogger([
1212
2070
  "fedify",
1213
2071
  "federation",
1214
2072
  "inbox"
@@ -1230,7 +2088,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1230
2088
  ];
1231
2089
  if (cacheKey != null) {
1232
2090
  if (await this.kv.get(cacheKey) === true) {
1233
- logger$2.debug("Activity {activityId} has already been processed.", {
2091
+ logger$1.debug("Activity {activityId} has already been processed.", {
1234
2092
  activityId: activity.id?.href,
1235
2093
  activity: message.activity,
1236
2094
  recipient: message.identifier
@@ -1241,7 +2099,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1241
2099
  await this._getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span$1) => {
1242
2100
  const dispatched = this.inboxListeners?.dispatchWithClass(activity);
1243
2101
  if (dispatched == null) {
1244
- logger$2.error("Unsupported activity type:\n{activity}", {
2102
+ logger$1.error("Unsupported activity type:\n{activity}", {
1245
2103
  activityId: activity.id?.href,
1246
2104
  activity: message.activity,
1247
2105
  recipient: message.identifier,
@@ -1262,7 +2120,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1262
2120
  try {
1263
2121
  await this.inboxErrorHandler?.(context$1, error);
1264
2122
  } catch (error$1) {
1265
- logger$2.error("An unexpected error occurred in inbox error handler:\n{error}", {
2123
+ logger$1.error("An unexpected error occurred in inbox error handler:\n{error}", {
1266
2124
  error: error$1,
1267
2125
  trial: message.attempt,
1268
2126
  activityId: activity.id?.href,
@@ -1271,7 +2129,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1271
2129
  });
1272
2130
  }
1273
2131
  if (this.inboxQueue?.nativeRetrial) {
1274
- logger$2.error("Failed to process the incoming activity {activityId}; backend will handle retry:\n{error}", {
2132
+ logger$1.error("Failed to process the incoming activity {activityId}; backend will handle retry:\n{error}", {
1275
2133
  error,
1276
2134
  activityId: activity.id?.href,
1277
2135
  activity: message.activity,
@@ -1284,12 +2142,12 @@ var FederationImpl = class extends FederationBuilderImpl {
1284
2142
  span$1.end();
1285
2143
  throw error;
1286
2144
  }
1287
- const delay = this.inboxRetryPolicy({
2145
+ const delay$1 = this.inboxRetryPolicy({
1288
2146
  elapsedTime: Temporal.Instant.from(message.started).until(Temporal.Now.instant()),
1289
2147
  attempts: message.attempt
1290
2148
  });
1291
- if (delay != null) {
1292
- logger$2.error("Failed to process the incoming activity {activityId} (attempt #{attempt}); retry...:\n{error}", {
2149
+ if (delay$1 != null) {
2150
+ logger$1.error("Failed to process the incoming activity {activityId} (attempt #{attempt}); retry...:\n{error}", {
1293
2151
  error,
1294
2152
  attempt: message.attempt,
1295
2153
  activityId: activity.id?.href,
@@ -1299,8 +2157,8 @@ var FederationImpl = class extends FederationBuilderImpl {
1299
2157
  await this.inboxQueue?.enqueue({
1300
2158
  ...message,
1301
2159
  attempt: message.attempt + 1
1302
- }, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
1303
- } else logger$2.error("Failed to process the incoming activity {activityId} after {trial} attempts; giving up:\n{error}", {
2160
+ }, { delay: Temporal.Duration.compare(delay$1, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay$1 });
2161
+ } else logger$1.error("Failed to process the incoming activity {activityId} after {trial} attempts; giving up:\n{error}", {
1304
2162
  error,
1305
2163
  activityId: activity.id?.href,
1306
2164
  activity: message.activity,
@@ -1314,7 +2172,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1314
2172
  return;
1315
2173
  }
1316
2174
  if (cacheKey != null) await this.kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
1317
- logger$2.info("Activity {activityId} has been processed.", {
2175
+ logger$1.info("Activity {activityId} has been processed.", {
1318
2176
  activityId: activity.id?.href,
1319
2177
  activity: message.activity,
1320
2178
  recipient: message.identifier
@@ -1363,7 +2221,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1363
2221
  };
1364
2222
  }
1365
2223
  async sendActivity(keys, inboxes, activity, options) {
1366
- const logger$2 = getLogger([
2224
+ const logger$1 = getLogger([
1367
2225
  "fedify",
1368
2226
  "federation",
1369
2227
  "outbox"
@@ -1397,7 +2255,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1397
2255
  format: "compact",
1398
2256
  contextLoader
1399
2257
  });
1400
- if (rsaKey == null) logger$2.warn("No supported key found to create a Linked Data signature for the activity {activityId}. The activity will be sent without a Linked Data signature. In order to create a Linked Data signature, at least one RSASSA-PKCS1-v1_5 key must be provided.", {
2258
+ if (rsaKey == null) logger$1.warn("No supported key found to create a Linked Data signature for the activity {activityId}. The activity will be sent without a Linked Data signature. In order to create a Linked Data signature, at least one RSASSA-PKCS1-v1_5 key must be provided.", {
1401
2259
  activityId,
1402
2260
  keys: keys.map((pair) => ({
1403
2261
  keyId: pair.keyId.href,
@@ -1408,7 +2266,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1408
2266
  contextLoader,
1409
2267
  tracerProvider: this.tracerProvider
1410
2268
  });
1411
- if (!proofCreated) logger$2.warn("No supported key found to create a proof for the activity {activityId}. The activity will be sent without a proof. In order to create a proof, at least one Ed25519 key must be provided.", {
2269
+ if (!proofCreated) logger$1.warn("No supported key found to create a proof for the activity {activityId}. The activity will be sent without a proof. In order to create a proof, at least one Ed25519 key must be provided.", {
1412
2270
  activityId,
1413
2271
  keys: keys.map((pair) => ({
1414
2272
  keyId: pair.keyId.href,
@@ -1416,11 +2274,11 @@ var FederationImpl = class extends FederationBuilderImpl {
1416
2274
  }))
1417
2275
  });
1418
2276
  if (immediate || this.outboxQueue == null) {
1419
- if (immediate) logger$2.debug("Sending activity immediately without queue since immediate option is set.", {
2277
+ if (immediate) logger$1.debug("Sending activity immediately without queue since immediate option is set.", {
1420
2278
  activityId: activity.id.href,
1421
2279
  activity: jsonLd
1422
2280
  });
1423
- else logger$2.debug("Sending activity immediately without queue since queue is not set.", {
2281
+ else logger$1.debug("Sending activity immediately without queue since queue is not set.", {
1424
2282
  activityId: activity.id.href,
1425
2283
  activity: jsonLd
1426
2284
  });
@@ -1439,7 +2297,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1439
2297
  await Promise.all(promises);
1440
2298
  return;
1441
2299
  }
1442
- logger$2.debug("Enqueuing activity {activityId} to send later.", {
2300
+ logger$1.debug("Enqueuing activity {activityId} to send later.", {
1443
2301
  activityId: activity.id.href,
1444
2302
  activity: jsonLd
1445
2303
  });
@@ -1478,7 +2336,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1478
2336
  const promises = messages.map((m) => outboxQueue.enqueue(m));
1479
2337
  const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
1480
2338
  if (errors.length > 0) {
1481
- logger$2.error("Failed to enqueue activity {activityId} to send later: {errors}", {
2339
+ logger$1.error("Failed to enqueue activity {activityId} to send later: {errors}", {
1482
2340
  activityId: activity.id.href,
1483
2341
  errors
1484
2342
  });
@@ -1488,7 +2346,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1488
2346
  } else try {
1489
2347
  await outboxQueue.enqueueMany(messages);
1490
2348
  } catch (error) {
1491
- logger$2.error("Failed to enqueue activity {activityId} to send later: {error}", {
2349
+ logger$1.error("Failed to enqueue activity {activityId} to send later: {error}", {
1492
2350
  activityId: activity.id.href,
1493
2351
  error
1494
2352
  });
@@ -1505,7 +2363,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1505
2363
  [ATTR_URL_FULL]: request.url
1506
2364
  }
1507
2365
  }, async (span) => {
1508
- const logger$2 = getLogger([
2366
+ const logger$1 = getLogger([
1509
2367
  "fedify",
1510
2368
  "federation",
1511
2369
  "http"
@@ -1524,7 +2382,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1524
2382
  message: `${error}`
1525
2383
  });
1526
2384
  span.end();
1527
- logger$2.error("An error occurred while serving request {method} {url}: {error}", {
2385
+ logger$1.error("An error occurred while serving request {method} {url}: {error}", {
1528
2386
  method: request.method,
1529
2387
  url: request.url,
1530
2388
  error
@@ -1548,9 +2406,9 @@ var FederationImpl = class extends FederationBuilderImpl {
1548
2406
  url: request.url,
1549
2407
  status: response.status
1550
2408
  };
1551
- if (response.status >= 500) logger$2.error(logTpl, values);
1552
- else if (response.status >= 400) logger$2.warn(logTpl, values);
1553
- else logger$2.info(logTpl, values);
2409
+ if (response.status >= 500) logger$1.error(logTpl, values);
2410
+ else if (response.status >= 400) logger$1.warn(logTpl, values);
2411
+ else logger$1.info(logTpl, values);
1554
2412
  return response;
1555
2413
  });
1556
2414
  });
@@ -1867,13 +2725,13 @@ var ContextImpl = class ContextImpl {
1867
2725
  if (uri == null) return null;
1868
2726
  if (uri.origin !== this.origin && uri.origin !== this.canonicalOrigin) return null;
1869
2727
  const route = this.federation.router.route(uri.pathname);
1870
- const logger$2 = getLogger(["fedify", "federation"]);
2728
+ const logger$1 = getLogger(["fedify", "federation"]);
1871
2729
  if (route == null) return null;
1872
2730
  else if (route.name === "sharedInbox") return {
1873
2731
  type: "inbox",
1874
2732
  identifier: void 0,
1875
2733
  get handle() {
1876
- logger$2.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
2734
+ logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
1877
2735
  }
1878
2736
  };
1879
2737
  const identifier = "identifier" in route.values ? route.values.identifier : route.values.handle;
@@ -1881,7 +2739,7 @@ var ContextImpl = class ContextImpl {
1881
2739
  type: "actor",
1882
2740
  identifier,
1883
2741
  get handle() {
1884
- logger$2.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
2742
+ logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
1885
2743
  return identifier;
1886
2744
  }
1887
2745
  };
@@ -1897,7 +2755,7 @@ var ContextImpl = class ContextImpl {
1897
2755
  type: "inbox",
1898
2756
  identifier,
1899
2757
  get handle() {
1900
- logger$2.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
2758
+ logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
1901
2759
  return identifier;
1902
2760
  }
1903
2761
  };
@@ -1905,7 +2763,7 @@ var ContextImpl = class ContextImpl {
1905
2763
  type: "outbox",
1906
2764
  identifier,
1907
2765
  get handle() {
1908
- logger$2.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
2766
+ logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
1909
2767
  return identifier;
1910
2768
  }
1911
2769
  };
@@ -1913,7 +2771,7 @@ var ContextImpl = class ContextImpl {
1913
2771
  type: "following",
1914
2772
  identifier,
1915
2773
  get handle() {
1916
- logger$2.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
2774
+ logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
1917
2775
  return identifier;
1918
2776
  }
1919
2777
  };
@@ -1921,7 +2779,7 @@ var ContextImpl = class ContextImpl {
1921
2779
  type: "followers",
1922
2780
  identifier,
1923
2781
  get handle() {
1924
- logger$2.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
2782
+ logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
1925
2783
  return identifier;
1926
2784
  }
1927
2785
  };
@@ -1929,7 +2787,7 @@ var ContextImpl = class ContextImpl {
1929
2787
  type: "liked",
1930
2788
  identifier,
1931
2789
  get handle() {
1932
- logger$2.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
2790
+ logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
1933
2791
  return identifier;
1934
2792
  }
1935
2793
  };
@@ -1937,7 +2795,7 @@ var ContextImpl = class ContextImpl {
1937
2795
  type: "featured",
1938
2796
  identifier,
1939
2797
  get handle() {
1940
- logger$2.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
2798
+ logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
1941
2799
  return identifier;
1942
2800
  }
1943
2801
  };
@@ -1945,19 +2803,19 @@ var ContextImpl = class ContextImpl {
1945
2803
  type: "featuredTags",
1946
2804
  identifier,
1947
2805
  get handle() {
1948
- logger$2.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
2806
+ logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
1949
2807
  return identifier;
1950
2808
  }
1951
2809
  };
1952
2810
  return null;
1953
2811
  }
1954
2812
  async getActorKeyPairs(identifier) {
1955
- const logger$2 = getLogger([
2813
+ const logger$1 = getLogger([
1956
2814
  "fedify",
1957
2815
  "federation",
1958
2816
  "actor"
1959
2817
  ]);
1960
- if (this.invokedFromActorKeyPairsDispatcher != null) logger$2.warn("Context.getActorKeyPairs({getActorKeyPairsIdentifier}) method is invoked from the actor key pairs dispatcher ({actorKeyPairsDispatcherIdentifier}); this may cause an infinite loop.", {
2818
+ if (this.invokedFromActorKeyPairsDispatcher != null) logger$1.warn("Context.getActorKeyPairs({getActorKeyPairsIdentifier}) method is invoked from the actor key pairs dispatcher ({actorKeyPairsDispatcherIdentifier}); this may cause an infinite loop.", {
1961
2819
  getActorKeyPairsIdentifier: identifier,
1962
2820
  actorKeyPairsDispatcherIdentifier: this.invokedFromActorKeyPairsDispatcher.identifier
1963
2821
  });
@@ -1965,7 +2823,7 @@ var ContextImpl = class ContextImpl {
1965
2823
  try {
1966
2824
  keyPairs = await this.getKeyPairsFromIdentifier(identifier);
1967
2825
  } catch (_) {
1968
- logger$2.warn("No actor key pairs dispatcher registered.");
2826
+ logger$1.warn("No actor key pairs dispatcher registered.");
1969
2827
  return [];
1970
2828
  }
1971
2829
  const owner = this.getActorUri(identifier);
@@ -1989,7 +2847,7 @@ var ContextImpl = class ContextImpl {
1989
2847
  return result;
1990
2848
  }
1991
2849
  async getKeyPairsFromIdentifier(identifier) {
1992
- const logger$2 = getLogger([
2850
+ const logger$1 = getLogger([
1993
2851
  "fedify",
1994
2852
  "federation",
1995
2853
  "actor"
@@ -2000,7 +2858,7 @@ var ContextImpl = class ContextImpl {
2000
2858
  handle: identifier
2001
2859
  });
2002
2860
  if (path == null) {
2003
- logger$2.warn("No actor dispatcher registered.");
2861
+ logger$1.warn("No actor dispatcher registered.");
2004
2862
  return [];
2005
2863
  }
2006
2864
  const actorUri = new URL(path, this.canonicalOrigin);
@@ -2008,7 +2866,7 @@ var ContextImpl = class ContextImpl {
2008
2866
  ...this,
2009
2867
  invokedFromActorKeyPairsDispatcher: { identifier }
2010
2868
  }), identifier);
2011
- if (keyPairs.length < 1) logger$2.warn("No key pairs found for actor {identifier}.", { identifier });
2869
+ if (keyPairs.length < 1) logger$1.warn("No key pairs found for actor {identifier}.", { identifier });
2012
2870
  let i = 0;
2013
2871
  const result = [];
2014
2872
  for (const keyPair of keyPairs) {
@@ -2123,7 +2981,7 @@ var ContextImpl = class ContextImpl {
2123
2981
  });
2124
2982
  }
2125
2983
  async sendActivityInternal(sender, recipients, activity, options, span) {
2126
- const logger$2 = getLogger([
2984
+ const logger$1 = getLogger([
2127
2985
  "fedify",
2128
2986
  "federation",
2129
2987
  "outbox"
@@ -2137,7 +2995,7 @@ var ContextImpl = class ContextImpl {
2137
2995
  if ("username" in sender) username = sender.username;
2138
2996
  else {
2139
2997
  username = sender.handle;
2140
- logger$2.warn("The \"handle\" property for the sender parameter is deprecated; use \"identifier\" or \"username\" instead.", { sender });
2998
+ logger$1.warn("The \"handle\" property for the sender parameter is deprecated; use \"identifier\" or \"username\" instead.", { sender });
2141
2999
  }
2142
3000
  if (this.federation.actorCallbacks?.handleMapper == null) identifier = username;
2143
3001
  else {
@@ -2174,7 +3032,7 @@ var ContextImpl = class ContextImpl {
2174
3032
  for (const activityTransformer of this.federation.activityTransformers) activity = activityTransformer(activity, this);
2175
3033
  span?.setAttribute("activitypub.activity.id", activity?.id?.href ?? "");
2176
3034
  if (activity.actorId == null) {
2177
- logger$2.error("Activity {activityId} to send does not have an actor.", {
3035
+ logger$1.error("Activity {activityId} to send does not have an actor.", {
2178
3036
  activity,
2179
3037
  activityId: activity?.id?.href
2180
3038
  });
@@ -2185,7 +3043,7 @@ var ContextImpl = class ContextImpl {
2185
3043
  preferSharedInbox: options.preferSharedInbox,
2186
3044
  excludeBaseUris: options.excludeBaseUris
2187
3045
  });
2188
- logger$2.debug("Sending activity {activityId} to inboxes:\n{inboxes}", {
3046
+ logger$1.debug("Sending activity {activityId} to inboxes:\n{inboxes}", {
2189
3047
  inboxes: globalThis.Object.keys(inboxes),
2190
3048
  activityId: activity.id?.href,
2191
3049
  activity
@@ -2271,7 +3129,7 @@ var ContextImpl = class ContextImpl {
2271
3129
  });
2272
3130
  }
2273
3131
  async routeActivityInternal(recipient, activity, options = {}, span) {
2274
- const logger$2 = getLogger([
3132
+ const logger$1 = getLogger([
2275
3133
  "fedify",
2276
3134
  "federation",
2277
3135
  "inbox"
@@ -2285,12 +3143,12 @@ var ContextImpl = class ContextImpl {
2285
3143
  tracerProvider: options.tracerProvider ?? this.tracerProvider,
2286
3144
  keyCache
2287
3145
  }) == null) {
2288
- logger$2.debug("Object Integrity Proofs are not verified.", {
3146
+ logger$1.debug("Object Integrity Proofs are not verified.", {
2289
3147
  recipient,
2290
3148
  activity: json
2291
3149
  });
2292
3150
  if (activity.id == null) {
2293
- logger$2.debug("Activity is missing an ID; unable to fetch.", {
3151
+ logger$1.debug("Activity is missing an ID; unable to fetch.", {
2294
3152
  recipient,
2295
3153
  activity: json
2296
3154
  });
@@ -2298,26 +3156,26 @@ var ContextImpl = class ContextImpl {
2298
3156
  }
2299
3157
  const fetched = await this.lookupObject(activity.id, options);
2300
3158
  if (fetched == null) {
2301
- logger$2.debug("Failed to fetch the remote activity object {activityId}.", {
3159
+ logger$1.debug("Failed to fetch the remote activity object {activityId}.", {
2302
3160
  recipient,
2303
3161
  activity: json,
2304
3162
  activityId: activity.id.href
2305
3163
  });
2306
3164
  return false;
2307
3165
  } else if (!(fetched instanceof Activity)) {
2308
- logger$2.debug("Fetched object is not an Activity.", {
3166
+ logger$1.debug("Fetched object is not an Activity.", {
2309
3167
  recipient,
2310
3168
  activity: await fetched.toJsonLd({ contextLoader })
2311
3169
  });
2312
3170
  return false;
2313
3171
  } else if (fetched.id?.href !== activity.id.href) {
2314
- logger$2.debug("Fetched activity object has a different ID; failed to verify.", {
3172
+ logger$1.debug("Fetched activity object has a different ID; failed to verify.", {
2315
3173
  recipient,
2316
3174
  activity: await fetched.toJsonLd({ contextLoader })
2317
3175
  });
2318
3176
  return false;
2319
3177
  } else if (fetched.actorIds.length < 1) {
2320
- logger$2.debug("Fetched activity object is missing an actor; unable to verify.", {
3178
+ logger$1.debug("Fetched activity object is missing an actor; unable to verify.", {
2321
3179
  recipient,
2322
3180
  activity: await fetched.toJsonLd({ contextLoader })
2323
3181
  });
@@ -2325,15 +3183,15 @@ var ContextImpl = class ContextImpl {
2325
3183
  }
2326
3184
  const activityId = fetched.id;
2327
3185
  if (!fetched.actorIds.every((actor) => actor.origin === activityId.origin)) {
2328
- logger$2.debug("Fetched activity object has actors from different origins; unable to verify.", {
3186
+ logger$1.debug("Fetched activity object has actors from different origins; unable to verify.", {
2329
3187
  recipient,
2330
3188
  activity: await fetched.toJsonLd({ contextLoader })
2331
3189
  });
2332
3190
  return false;
2333
3191
  }
2334
- logger$2.debug("Successfully fetched the remote activity object {activityId}; ignore the original activity and use the fetched one, which is trustworthy.");
3192
+ logger$1.debug("Successfully fetched the remote activity object {activityId}; ignore the original activity and use the fetched one, which is trustworthy.");
2335
3193
  activity = fetched;
2336
- } else logger$2.debug("Object Integrity Proofs are verified.", {
3194
+ } else logger$1.debug("Object Integrity Proofs are verified.", {
2337
3195
  recipient,
2338
3196
  activity: json
2339
3197
  });
@@ -2477,7 +3335,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
2477
3335
  });
2478
3336
  }
2479
3337
  async forwardActivityInternal(forwarder, recipients, options) {
2480
- const logger$2 = getLogger([
3338
+ const logger$1 = getLogger([
2481
3339
  "fedify",
2482
3340
  "federation",
2483
3341
  "inbox"
@@ -2491,7 +3349,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
2491
3349
  if ("username" in forwarder) username = forwarder.username;
2492
3350
  else {
2493
3351
  username = forwarder.handle;
2494
- logger$2.warn("The \"handle\" property for the forwarder parameter is deprecated; use \"identifier\" or \"username\" instead.", { forwarder });
3352
+ logger$1.warn("The \"handle\" property for the forwarder parameter is deprecated; use \"identifier\" or \"username\" instead.", { forwarder });
2495
3353
  }
2496
3354
  if (this.federation.actorCallbacks?.handleMapper == null) identifier = username;
2497
3355
  else {
@@ -2515,7 +3373,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
2515
3373
  }
2516
3374
  if (!hasProof) {
2517
3375
  if (options?.skipIfUnsigned) return;
2518
- logger$2.warn("The received activity {activityId} is not signed; even if it is forwarded to other servers as is, it may not be accepted by them due to the lack of a signature/proof.");
3376
+ logger$1.warn("The received activity {activityId} is not signed; even if it is forwarded to other servers as is, it may not be accepted by them due to the lack of a signature/proof.");
2519
3377
  }
2520
3378
  }
2521
3379
  if (recipients === "followers") {
@@ -2529,14 +3387,14 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
2529
3387
  preferSharedInbox: options?.preferSharedInbox,
2530
3388
  excludeBaseUris: options?.excludeBaseUris
2531
3389
  });
2532
- logger$2.debug("Forwarding activity {activityId} to inboxes:\n{inboxes}", {
3390
+ logger$1.debug("Forwarding activity {activityId} to inboxes:\n{inboxes}", {
2533
3391
  inboxes: globalThis.Object.keys(inboxes),
2534
3392
  activityId: this.activityId,
2535
3393
  activity: this.activity
2536
3394
  });
2537
3395
  if (options?.immediate || this.federation.outboxQueue == null) {
2538
- if (options?.immediate) logger$2.debug("Forwarding activity immediately without queue since immediate option is set.");
2539
- else logger$2.debug("Forwarding activity immediately without queue since queue is not set.");
3396
+ if (options?.immediate) logger$1.debug("Forwarding activity immediately without queue since immediate option is set.");
3397
+ else logger$1.debug("Forwarding activity immediately without queue since queue is not set.");
2540
3398
  const promises = [];
2541
3399
  for (const inbox in inboxes) promises.push(sendActivity({
2542
3400
  keys,
@@ -2551,7 +3409,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
2551
3409
  await Promise.all(promises);
2552
3410
  return;
2553
3411
  }
2554
- logger$2.debug("Enqueuing activity {activityId} to forward later.", {
3412
+ logger$1.debug("Enqueuing activity {activityId} to forward later.", {
2555
3413
  activityId: this.activityId,
2556
3414
  activity: this.activity
2557
3415
  });
@@ -2589,7 +3447,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
2589
3447
  const promises = messages.map((m) => outboxQueue.enqueue(m));
2590
3448
  const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
2591
3449
  if (errors.length > 0) {
2592
- logger$2.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
3450
+ logger$1.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
2593
3451
  activityId: this.activityId,
2594
3452
  errors
2595
3453
  });
@@ -2599,7 +3457,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
2599
3457
  } else try {
2600
3458
  await outboxQueue.enqueueMany(messages);
2601
3459
  } catch (error) {
2602
- logger$2.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
3460
+ logger$1.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
2603
3461
  activityId: this.activityId,
2604
3462
  error
2605
3463
  });
@@ -2658,4 +3516,4 @@ function getRequestId(request) {
2658
3516
  }
2659
3517
 
2660
3518
  //#endregion
2661
- export { autoIdAssigner as _, createFederation as a, handleCollection as c, respondWithObject as d, respondWithObjectIfAcceptable as f, actorDehydrator as g, handleNodeInfoJrd as h, KvSpecDeterminer as i, handleInbox as l, handleNodeInfo as m, FederationImpl as n, acceptsJsonLd as o, handleWebFinger as p, InboxContextImpl as r, handleActor as s, ContextImpl as t, handleObject as u };
3519
+ export { createFederation as a, respondWithObjectIfAcceptable as c, createFederationBuilder as d, Router$1 as f, KvSpecDeterminer as i, buildCollectionSynchronizationHeader as l, FederationImpl as n, createExponentialBackoffPolicy as o, RouterError as p, InboxContextImpl as r, respondWithObject as s, ContextImpl as t, digest as u };