@fedify/fedify 2.0.7 → 2.0.9
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.
- package/dist/{assert-MZs1qjMx.js → assert-ddO5KLpe.mjs} +5 -9
- package/dist/{assert_equals-DSbWqCm3.js → assert_equals-Ew3jOFa3.mjs} +55 -69
- package/dist/{assert_instance_of-DHz7EHNU.js → assert_instance_of-C4Ri6VuN.mjs} +5 -9
- package/dist/{assert_not_equals-C80BG-_5.js → assert_not_equals--wG9hV7u.mjs} +6 -13
- package/dist/{assert_rejects-Ce45JcFg.js → assert_rejects-B-qJtC9Z.mjs} +6 -11
- package/dist/{assert_throws-BNXdRGWP.js → assert_throws-4NwKEy2q.mjs} +5 -10
- package/dist/{builder-DA7Qgx_F.js → builder-DDoQaGOu.mjs} +32 -41
- package/dist/{chunk-CGaQZ11T.cjs → chunk-DDcVe30Y.cjs} +23 -24
- package/dist/{chunk-DJNbSFdH.js → chunk-nlSIicah.js} +8 -8
- package/dist/{client-CoCIaTNO.js → client-A1UrnX6I.mjs} +9 -13
- package/dist/{client-BxMZiQaD.d.ts → client-AtlibPOU.d.ts} +1 -1
- package/dist/{client-C97KOq3x.d.cts → client-z-8dc-e1.d.cts} +1 -1
- package/dist/{collection-CcnIw1qY.js → collection-ChgDTHLz.mjs} +7 -12
- package/dist/compat/mod.cjs +5 -8
- package/dist/compat/mod.d.cts +78 -6
- package/dist/compat/mod.d.ts +78 -6
- package/dist/compat/mod.js +4 -8
- package/dist/compat/transformers.test.mjs +62 -0
- package/dist/{context-D3QkEtZd.d.cts → context-CNIt-Qn7.d.cts} +9 -18
- package/dist/{context-DZJhUmzF.d.ts → context-Dyg7P1qW.d.ts} +9 -18
- package/dist/{context-pa9aIrwp.js → context-Juj6bdHC.mjs} +7 -11
- package/dist/deno-CuVDEdyj.mjs +8 -0
- package/dist/{docloader-CJeSPcS_.js → docloader-BPq9yzC_.mjs} +8 -14
- package/dist/{esm-nLm00z9V.js → esm-DVILvP5e.mjs} +50 -89
- package/dist/federation/builder.test.d.mts +2 -0
- package/dist/federation/{builder.test.js → builder.test.mjs} +19 -38
- package/dist/federation/collection.test.d.mts +2 -0
- package/dist/federation/collection.test.mjs +21 -0
- package/dist/federation/handler.test.d.mts +2 -0
- package/dist/federation/{handler.test.js → handler.test.mjs} +26 -56
- package/dist/federation/idempotency.test.d.mts +2 -0
- package/dist/federation/{idempotency.test.js → idempotency.test.mjs} +31 -62
- package/dist/federation/inbox.test.d.mts +2 -0
- package/dist/federation/{inbox.test.js → inbox.test.mjs} +8 -12
- package/dist/federation/keycache.test.d.mts +2 -0
- package/dist/federation/{keycache.test.js → keycache.test.mjs} +13 -13
- package/dist/federation/kv.test.d.mts +2 -0
- package/dist/federation/{kv.test.js → kv.test.mjs} +11 -22
- package/dist/federation/middleware.test.d.mts +2 -0
- package/dist/federation/{middleware.test.js → middleware.test.mjs} +146 -225
- package/dist/federation/mod.cjs +327 -16
- package/dist/federation/mod.d.cts +3 -6
- package/dist/federation/mod.d.ts +3 -6
- package/dist/federation/mod.js +322 -13
- package/dist/federation/mq.test.d.mts +2 -0
- package/dist/federation/{mq.test.js → mq.test.mjs} +21 -35
- package/dist/federation/negotiation.test.d.mts +2 -0
- package/dist/federation/{negotiation.test.js → negotiation.test.mjs} +9 -16
- package/dist/federation/retry.test.d.mts +2 -0
- package/dist/federation/{retry.test.js → retry.test.mjs} +8 -11
- package/dist/federation/router.test.d.mts +2 -0
- package/dist/federation/{router.test.js → router.test.mjs} +11 -16
- package/dist/federation/send.test.d.mts +2 -0
- package/dist/federation/{send.test.js → send.test.mjs} +22 -29
- package/dist/federation/webfinger.test.d.mts +2 -0
- package/dist/federation/{webfinger.test.js → webfinger.test.mjs} +22 -55
- package/dist/{http-DkHdFfrc.d.ts → http-B2wiNmSo.d.ts} +1 -6
- package/dist/{http-B3vAjAtl.js → http-Bz7avX57.js} +39 -159
- package/dist/{http-Cz3MlXAZ.d.cts → http-C_tEAiZj.d.cts} +1 -6
- package/dist/{http-CjaLjnRN.js → http-DI213UHg.mjs} +31 -35
- package/dist/{http-CQ7TiYUI.cjs → http-DKBDoudA.cjs} +119 -233
- package/dist/{inbox-B33isX44.js → inbox-Bdn-CSRd.mjs} +18 -26
- package/dist/{key-Cga1p73u.js → key-DzJf84o7.mjs} +12 -19
- package/dist/{keycache-DRxpZ5r9.js → keycache-DaQ3ndaJ.mjs} +15 -10
- package/dist/{keys-ZbcByPg9.js → keys-CtZLJq76.mjs} +5 -9
- package/dist/{kv-QzKcOQgP.js → kv-BrZHNugx.mjs} +6 -10
- package/dist/{kv-BL4nlICN.d.cts → kv-CbLNp3zQ.d.cts} +1 -1
- package/dist/{kv-DXEUEP6z.d.ts → kv-GFYnFoOl.d.ts} +1 -1
- package/dist/{kv-cache-CFdy0BpZ.js → kv-cache-DBd7BezJ.js} +6 -13
- package/dist/{kv-cache--qyREO7e.cjs → kv-cache-Dj1Q7TiW.cjs} +27 -34
- package/dist/{kv-cache-El7We5sy.js → kv-cache-OWmRLHir.mjs} +4 -8
- package/dist/{ld-BWSOukKj.js → ld-DczS1fLK.mjs} +17 -31
- package/dist/middleware-B5CiOImA.mjs +5 -0
- package/dist/{middleware-CP7JdsGq.js → middleware-BKNu57ZI.js} +331 -365
- package/dist/middleware-C36TOX-2.cjs +4 -0
- package/dist/{middleware-Scz2k9eL.cjs → middleware-CyjmpK70.cjs} +523 -565
- package/dist/{middleware-BI1VCuPT.js → middleware-DoHz9oIo.mjs} +260 -292
- package/dist/{mod-DPkRU3EK.d.cts → mod-1xhgsHef.d.cts} +2 -2
- package/dist/{mod-DUWcVv49.d.ts → mod-BGtYJZKu.d.ts} +2 -2
- package/dist/{mod-DXsQakeS.d.cts → mod-Bld7oeqf.d.cts} +3 -3
- package/dist/{mod-DnSsduJF.d.ts → mod-BnAKGh2w.d.ts} +2 -2
- package/dist/{mod-CwZXZJ9d.d.ts → mod-DTOUyCce.d.ts} +3 -3
- package/dist/{mod-Di3W5OdP.d.cts → mod-DWoQffTD.d.cts} +2 -2
- package/dist/mod.cjs +29 -68
- package/dist/mod.d.cts +11 -14
- package/dist/mod.d.ts +11 -15
- package/dist/mod.js +17 -65
- package/dist/{negotiation-5NPJL6zp.js → negotiation-BehA2uul.mjs} +7 -11
- package/dist/nodeinfo/client.test.d.mts +2 -0
- package/dist/nodeinfo/{client.test.js → client.test.mjs} +22 -40
- package/dist/nodeinfo/handler.test.d.mts +2 -0
- package/dist/nodeinfo/{handler.test.js → handler.test.mjs} +13 -42
- package/dist/nodeinfo/mod.cjs +5 -8
- package/dist/nodeinfo/mod.d.cts +2 -3
- package/dist/nodeinfo/mod.d.ts +2 -3
- package/dist/nodeinfo/mod.js +4 -8
- package/dist/nodeinfo/types.test.d.mts +2 -0
- package/dist/nodeinfo/{types.test.js → types.test.mjs} +9 -16
- package/dist/otel/exporter.test.d.mts +2 -0
- package/dist/otel/{exporter.test.js → exporter.test.mjs} +117 -169
- package/dist/otel/mod.cjs +15 -20
- package/dist/otel/mod.d.cts +2 -2
- package/dist/otel/mod.d.ts +2 -2
- package/dist/otel/mod.js +8 -14
- package/dist/{owner-gd0Q9FuU.d.ts → owner-74ARJ5TL.d.ts} +1 -1
- package/dist/{owner-1AbPBOOZ.d.cts → owner-CptqhsOy.d.cts} +1 -1
- package/dist/{owner-HASxJJP1.js → owner-DXMGUEOr.mjs} +11 -16
- package/dist/{proof-BwfRl5J4.js → proof-C-7NljBU.js} +33 -59
- package/dist/{proof-BXt2Oi8t.js → proof-CEOujj0L.mjs} +21 -33
- package/dist/{proof-BYZ4hcgN.cjs → proof-DMu-6A_w.cjs} +133 -157
- package/dist/{retry-D4GJ670a.js → retry-Ddbq3AcK.mjs} +4 -7
- package/dist/{router-D9eI0s4b.js → router-CrMLXoOr.mjs} +4 -8
- package/dist/runtime/mod.cjs +11 -13
- package/dist/runtime/mod.d.cts +6 -2
- package/dist/runtime/mod.d.ts +0 -1
- package/dist/runtime/mod.js +4 -7
- package/dist/{send-BF3omx5-.js → send-DIfrLTB_.mjs} +8 -13
- package/dist/sig/http.test.d.mts +2 -0
- package/dist/sig/{http.test.js → http.test.mjs} +160 -199
- package/dist/sig/key.test.d.mts +2 -0
- package/dist/sig/{key.test.js → key.test.mjs} +11 -18
- package/dist/sig/ld.test.d.mts +2 -0
- package/dist/sig/{ld.test.js → ld.test.mjs} +22 -35
- package/dist/sig/mod.cjs +6 -9
- package/dist/sig/mod.d.cts +3 -3
- package/dist/sig/mod.d.ts +3 -3
- package/dist/sig/mod.js +5 -9
- package/dist/sig/owner.test.d.mts +2 -0
- package/dist/sig/{owner.test.js → owner.test.mjs} +19 -34
- package/dist/sig/proof.test.d.mts +2 -0
- package/dist/sig/{proof.test.js → proof.test.mjs} +16 -27
- package/dist/{std__assert-DWivtrGR.js → std__assert-Duiq_YC9.mjs} +12 -24
- package/dist/testing/{mod.d.ts → mod.d.mts} +26 -78
- package/dist/testing/mod.mjs +6 -0
- package/dist/{transformers-3g8GZwkZ.cjs → transformers-NeAONrAq.cjs} +20 -25
- package/dist/{transformers-C3FLHUd6.js → transformers-ve6e2xcg.js} +3 -7
- package/dist/{types-CPz01LGH.js → types-C37hquWI.mjs} +4 -7
- package/dist/{types-Cd_hszr_.cjs → types-KC4QAoxe.cjs} +29 -34
- package/dist/{types-C93Ob9cU.js → types-hvL8ElAs.js} +8 -13
- package/dist/utils/docloader.test.d.mts +2 -0
- package/dist/utils/{docloader.test.js → docloader.test.mjs} +14 -24
- package/dist/utils/kv-cache.test.d.mts +2 -0
- package/dist/utils/{kv-cache.test.js → kv-cache.test.mjs} +25 -40
- package/dist/utils/mod.cjs +5 -9
- package/dist/utils/mod.d.cts +1 -3
- package/dist/utils/mod.d.ts +1 -3
- package/dist/utils/mod.js +4 -9
- package/dist/vocab/cjs.test.d.mts +2 -0
- package/dist/vocab/cjs.test.mjs +14 -0
- package/dist/vocab/mod.cjs +10 -12
- package/dist/vocab/mod.js +3 -5
- package/package.json +7 -7
- package/dist/compat/transformers.test.d.ts +0 -3
- package/dist/compat/transformers.test.js +0 -87
- package/dist/compat-Bb4NuTUO.js +0 -4
- package/dist/compat-DmDDELst.cjs +0 -4
- package/dist/deno-CbQK8e-e.js +0 -121
- package/dist/federation/builder.test.d.ts +0 -3
- package/dist/federation/collection.test.d.ts +0 -3
- package/dist/federation/collection.test.js +0 -32
- package/dist/federation/handler.test.d.ts +0 -3
- package/dist/federation/idempotency.test.d.ts +0 -3
- package/dist/federation/inbox.test.d.ts +0 -3
- package/dist/federation/keycache.test.d.ts +0 -3
- package/dist/federation/kv.test.d.ts +0 -3
- package/dist/federation/middleware.test.d.ts +0 -3
- package/dist/federation/mq.test.d.ts +0 -3
- package/dist/federation/negotiation.test.d.ts +0 -3
- package/dist/federation/retry.test.d.ts +0 -3
- package/dist/federation/router.test.d.ts +0 -3
- package/dist/federation/send.test.d.ts +0 -3
- package/dist/federation/webfinger.test.d.ts +0 -3
- package/dist/federation-Bp3HI26G.cjs +0 -350
- package/dist/federation-DaMfqRm4.js +0 -332
- package/dist/middleware-CcXQzfn8.cjs +0 -12
- package/dist/middleware-CoeaBowW.js +0 -12
- package/dist/middleware-vH2jFwC6.js +0 -26
- package/dist/mod-Bh8mqlYw.d.cts +0 -9
- package/dist/mod-D6HodEq7.d.ts +0 -7
- package/dist/mod-DVwHUI_x.d.cts +0 -80
- package/dist/mod-DosD6NsG.d.ts +0 -82
- package/dist/mod-gq_Xfdz8.d.cts +0 -1
- package/dist/nodeinfo/client.test.d.ts +0 -3
- package/dist/nodeinfo/handler.test.d.ts +0 -3
- package/dist/nodeinfo/types.test.d.ts +0 -3
- package/dist/nodeinfo-DoESQxq5.js +0 -4
- package/dist/nodeinfo-DuMYTpbZ.cjs +0 -4
- package/dist/otel/exporter.test.d.ts +0 -3
- package/dist/runtime-c2Njxsry.cjs +0 -17
- package/dist/runtime-poamPCMb.js +0 -13
- package/dist/sig/http.test.d.ts +0 -3
- package/dist/sig/key.test.d.ts +0 -3
- package/dist/sig/ld.test.d.ts +0 -3
- package/dist/sig/owner.test.d.ts +0 -3
- package/dist/sig/proof.test.d.ts +0 -3
- package/dist/sig-BNhspNOf.js +0 -4
- package/dist/sig-vX39WyWI.cjs +0 -4
- package/dist/testing/mod.js +0 -10
- package/dist/utils/docloader.test.d.ts +0 -3
- package/dist/utils/kv-cache.test.d.ts +0 -3
- package/dist/utils-BQ9KqEK9.cjs +0 -4
- package/dist/utils-Dn5OPdSW.js +0 -4
- /package/dist/{mod-AGjRfPjT.d.ts → compat/transformers.test.d.mts} +0 -0
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { getAuthenticatedDocumentLoader, kvCache } from "./kv-cache-CFdy0BpZ.js";
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
import { t as __exportAll } from "./chunk-nlSIicah.js";
|
|
4
|
+
import { r as getDefaultActivityTransformers } from "./transformers-ve6e2xcg.js";
|
|
5
|
+
import { c as validateCryptoKey, i as exportJwk, l as name, r as verifyRequest, s as importJwk, t as doubleKnock, u as version } from "./http-Bz7avX57.js";
|
|
6
|
+
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-C-7NljBU.js";
|
|
7
|
+
import { n as getNodeInfo, t as nodeInfoToJson } from "./types-hvL8ElAs.js";
|
|
8
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-DBd7BezJ.js";
|
|
10
9
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
11
10
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
12
11
|
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
@@ -14,11 +13,10 @@ import { cloneDeep } from "es-toolkit";
|
|
|
14
13
|
import { Router } from "uri-template-router";
|
|
15
14
|
import { parseTemplate } from "url-template";
|
|
16
15
|
import { encodeHex } from "byte-encodings/hex";
|
|
17
|
-
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";
|
|
18
16
|
import { getDocumentLoader } from "@fedify/vocab-runtime";
|
|
17
|
+
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";
|
|
19
18
|
import { lookupWebFinger } from "@fedify/webfinger";
|
|
20
19
|
import { domainToASCII } from "node:url";
|
|
21
|
-
|
|
22
20
|
//#region src/federation/inbox.ts
|
|
23
21
|
var InboxListenerSet = class InboxListenerSet {
|
|
24
22
|
#listeners;
|
|
@@ -54,7 +52,7 @@ var InboxListenerSet = class InboxListenerSet {
|
|
|
54
52
|
}
|
|
55
53
|
};
|
|
56
54
|
async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider, idempotencyStrategy }) {
|
|
57
|
-
const logger
|
|
55
|
+
const logger = getLogger([
|
|
58
56
|
"fedify",
|
|
59
57
|
"federation",
|
|
60
58
|
"inbox"
|
|
@@ -64,10 +62,8 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
64
62
|
const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
|
|
65
63
|
const strategy = idempotencyStrategy ?? "per-inbox";
|
|
66
64
|
let keyString;
|
|
67
|
-
if (typeof strategy === "function")
|
|
68
|
-
|
|
69
|
-
keyString = result;
|
|
70
|
-
} else switch (strategy) {
|
|
65
|
+
if (typeof strategy === "function") keyString = await strategy(inboxContext, activity);
|
|
66
|
+
else switch (strategy) {
|
|
71
67
|
case "global":
|
|
72
68
|
keyString = activity.id.href;
|
|
73
69
|
break;
|
|
@@ -82,9 +78,8 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
82
78
|
if (keyString != null) cacheKey = [...kvPrefixes.activityIdempotence, keyString];
|
|
83
79
|
}
|
|
84
80
|
if (cacheKey != null) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
logger$1.debug("Activity {activityId} has already been processed.", {
|
|
81
|
+
if (await kv.get(cacheKey) === true) {
|
|
82
|
+
logger.debug("Activity {activityId} has already been processed.", {
|
|
88
83
|
activityId: activity.id?.href,
|
|
89
84
|
activity: json,
|
|
90
85
|
recipient
|
|
@@ -97,7 +92,7 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
97
92
|
}
|
|
98
93
|
}
|
|
99
94
|
if (activity.actorId == null) {
|
|
100
|
-
logger
|
|
95
|
+
logger.error("Missing actor.", { activity: json });
|
|
101
96
|
span.setStatus({
|
|
102
97
|
code: SpanStatusCode.ERROR,
|
|
103
98
|
message: "Missing actor."
|
|
@@ -120,7 +115,7 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
120
115
|
traceContext: carrier
|
|
121
116
|
});
|
|
122
117
|
} catch (error) {
|
|
123
|
-
logger
|
|
118
|
+
logger.error("Failed to enqueue the incoming activity {activityId}:\n{error}", {
|
|
124
119
|
error,
|
|
125
120
|
activityId: activity.id?.href,
|
|
126
121
|
activity: json,
|
|
@@ -132,7 +127,7 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
132
127
|
});
|
|
133
128
|
throw error;
|
|
134
129
|
}
|
|
135
|
-
logger
|
|
130
|
+
logger.info("Activity {activityId} is enqueued.", {
|
|
136
131
|
activityId: activity.id?.href,
|
|
137
132
|
activity: json,
|
|
138
133
|
recipient
|
|
@@ -140,60 +135,58 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
140
135
|
return "enqueued";
|
|
141
136
|
}
|
|
142
137
|
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
143
|
-
|
|
144
|
-
return await tracer.startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span$1) => {
|
|
138
|
+
return await tracerProvider.getTracer(name, version).startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span) => {
|
|
145
139
|
const dispatched = inboxListeners?.dispatchWithClass(activity);
|
|
146
140
|
if (dispatched == null) {
|
|
147
|
-
logger
|
|
141
|
+
logger.error("Unsupported activity type:\n{activity}", {
|
|
148
142
|
activity: json,
|
|
149
143
|
recipient
|
|
150
144
|
});
|
|
151
|
-
span
|
|
145
|
+
span.setStatus({
|
|
152
146
|
code: SpanStatusCode.UNSET,
|
|
153
147
|
message: `Unsupported activity type: ${getTypeId(activity).href}`
|
|
154
148
|
});
|
|
155
|
-
span
|
|
149
|
+
span.end();
|
|
156
150
|
return "unsupportedActivity";
|
|
157
151
|
}
|
|
158
152
|
const { class: cls, listener } = dispatched;
|
|
159
|
-
span
|
|
153
|
+
span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
160
154
|
try {
|
|
161
155
|
await listener(inboxContextFactory(recipient, json, activity?.id?.href, getTypeId(activity).href), activity);
|
|
162
156
|
} catch (error) {
|
|
163
157
|
try {
|
|
164
158
|
await inboxErrorHandler?.(ctx, error);
|
|
165
|
-
} catch (error
|
|
166
|
-
logger
|
|
167
|
-
error
|
|
159
|
+
} catch (error) {
|
|
160
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
161
|
+
error,
|
|
168
162
|
activityId: activity.id?.href,
|
|
169
163
|
activity: json,
|
|
170
164
|
recipient
|
|
171
165
|
});
|
|
172
166
|
}
|
|
173
|
-
logger
|
|
167
|
+
logger.error("Failed to process the incoming activity {activityId}:\n{error}", {
|
|
174
168
|
error,
|
|
175
169
|
activityId: activity.id?.href,
|
|
176
170
|
activity: json,
|
|
177
171
|
recipient
|
|
178
172
|
});
|
|
179
|
-
span
|
|
173
|
+
span.setStatus({
|
|
180
174
|
code: SpanStatusCode.ERROR,
|
|
181
175
|
message: String(error)
|
|
182
176
|
});
|
|
183
|
-
span
|
|
177
|
+
span.end();
|
|
184
178
|
return "error";
|
|
185
179
|
}
|
|
186
180
|
if (cacheKey != null) await kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
|
|
187
|
-
logger
|
|
181
|
+
logger.info("Activity {activityId} has been processed.", {
|
|
188
182
|
activityId: activity.id?.href,
|
|
189
183
|
activity: json,
|
|
190
184
|
recipient
|
|
191
185
|
});
|
|
192
|
-
span
|
|
186
|
+
span.end();
|
|
193
187
|
return "success";
|
|
194
188
|
});
|
|
195
189
|
}
|
|
196
|
-
|
|
197
190
|
//#endregion
|
|
198
191
|
//#region src/federation/router.ts
|
|
199
192
|
function cloneInnerRouter(router) {
|
|
@@ -301,7 +294,6 @@ var RouterError = class extends Error {
|
|
|
301
294
|
this.name = "RouterError";
|
|
302
295
|
}
|
|
303
296
|
};
|
|
304
|
-
|
|
305
297
|
//#endregion
|
|
306
298
|
//#region src/federation/builder.ts
|
|
307
299
|
var FederationBuilderImpl = class {
|
|
@@ -338,8 +330,8 @@ var FederationBuilderImpl = class {
|
|
|
338
330
|
this.collectionTypeIds = {};
|
|
339
331
|
}
|
|
340
332
|
async build(options) {
|
|
341
|
-
const { FederationImpl
|
|
342
|
-
const f = new FederationImpl
|
|
333
|
+
const { FederationImpl } = await Promise.resolve().then(() => middleware_exports);
|
|
334
|
+
const f = new FederationImpl(options);
|
|
343
335
|
const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
|
|
344
336
|
f.router = this.router.clone();
|
|
345
337
|
f.router.trailingSlashInsensitive = trailingSlashInsensitiveValue;
|
|
@@ -365,23 +357,23 @@ var FederationBuilderImpl = class {
|
|
|
365
357
|
return f;
|
|
366
358
|
}
|
|
367
359
|
_getTracer() {
|
|
368
|
-
return trace.getTracer(
|
|
360
|
+
return trace.getTracer(name, version);
|
|
369
361
|
}
|
|
370
362
|
setActorDispatcher(path, dispatcher) {
|
|
371
363
|
if (this.router.has("actor")) throw new RouterError("Actor dispatcher already set.");
|
|
372
364
|
const variables = this.router.add(path, "actor");
|
|
373
365
|
if (variables.size !== 1 || !variables.has("identifier")) throw new RouterError("Path for actor dispatcher must have one variable: {identifier}");
|
|
374
|
-
const callbacks = { dispatcher: async (context
|
|
366
|
+
const callbacks = { dispatcher: async (context, identifier) => {
|
|
375
367
|
const actor = await this._getTracer().startActiveSpan("activitypub.dispatch_actor", {
|
|
376
368
|
kind: SpanKind.SERVER,
|
|
377
369
|
attributes: { "fedify.actor.identifier": identifier }
|
|
378
370
|
}, async (span) => {
|
|
379
371
|
try {
|
|
380
|
-
const actor
|
|
381
|
-
span.setAttribute("activitypub.actor.id", (actor
|
|
382
|
-
if (actor
|
|
383
|
-
else span.setAttribute("activitypub.actor.type", getTypeId(actor
|
|
384
|
-
return actor
|
|
372
|
+
const actor = await dispatcher(context, identifier);
|
|
373
|
+
span.setAttribute("activitypub.actor.id", (actor?.id ?? context.getActorUri(identifier)).href);
|
|
374
|
+
if (actor == null) span.setStatus({ code: SpanStatusCode.ERROR });
|
|
375
|
+
else span.setAttribute("activitypub.actor.type", getTypeId(actor).href);
|
|
376
|
+
return actor;
|
|
385
377
|
} catch (error) {
|
|
386
378
|
span.setStatus({
|
|
387
379
|
code: SpanStatusCode.ERROR,
|
|
@@ -393,52 +385,52 @@ var FederationBuilderImpl = class {
|
|
|
393
385
|
}
|
|
394
386
|
});
|
|
395
387
|
if (actor == null) return null;
|
|
396
|
-
const logger
|
|
388
|
+
const logger = getLogger([
|
|
397
389
|
"fedify",
|
|
398
390
|
"federation",
|
|
399
391
|
"actor"
|
|
400
392
|
]);
|
|
401
|
-
if (actor.id == null) logger
|
|
402
|
-
else if (actor.id.href != context
|
|
393
|
+
if (actor.id == null) logger.warn("Actor dispatcher returned an actor without an id property. Set the property with Context.getActorUri(identifier).");
|
|
394
|
+
else if (actor.id.href != context.getActorUri(identifier).href) logger.warn("Actor dispatcher returned an actor with an id property that does not match the actor URI. Set the property with Context.getActorUri(identifier).");
|
|
403
395
|
if (this.followingCallbacks != null && this.followingCallbacks.dispatcher != null) {
|
|
404
|
-
if (actor.followingId == null) logger
|
|
405
|
-
else if (actor.followingId.href != context
|
|
396
|
+
if (actor.followingId == null) logger.warn("You configured a following collection dispatcher, but the actor does not have a following property. Set the property with Context.getFollowingUri(identifier).");
|
|
397
|
+
else if (actor.followingId.href != context.getFollowingUri(identifier).href) logger.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).");
|
|
406
398
|
}
|
|
407
399
|
if (this.followersCallbacks != null && this.followersCallbacks.dispatcher != null) {
|
|
408
|
-
if (actor.followersId == null) logger
|
|
409
|
-
else if (actor.followersId.href != context
|
|
400
|
+
if (actor.followersId == null) logger.warn("You configured a followers collection dispatcher, but the actor does not have a followers property. Set the property with Context.getFollowersUri(identifier).");
|
|
401
|
+
else if (actor.followersId.href != context.getFollowersUri(identifier).href) logger.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).");
|
|
410
402
|
}
|
|
411
403
|
if (this.outboxCallbacks != null && this.outboxCallbacks.dispatcher != null) {
|
|
412
|
-
if (actor?.outboxId == null) logger
|
|
413
|
-
else if (actor.outboxId.href != context
|
|
404
|
+
if (actor?.outboxId == null) logger.warn("You configured an outbox collection dispatcher, but the actor does not have an outbox property. Set the property with Context.getOutboxUri(identifier).");
|
|
405
|
+
else if (actor.outboxId.href != context.getOutboxUri(identifier).href) logger.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).");
|
|
414
406
|
}
|
|
415
407
|
if (this.likedCallbacks != null && this.likedCallbacks.dispatcher != null) {
|
|
416
|
-
if (actor?.likedId == null) logger
|
|
417
|
-
else if (actor.likedId.href != context
|
|
408
|
+
if (actor?.likedId == null) logger.warn("You configured a liked collection dispatcher, but the actor does not have a liked property. Set the property with Context.getLikedUri(identifier).");
|
|
409
|
+
else if (actor.likedId.href != context.getLikedUri(identifier).href) logger.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).");
|
|
418
410
|
}
|
|
419
411
|
if (this.featuredCallbacks != null && this.featuredCallbacks.dispatcher != null) {
|
|
420
|
-
if (actor?.featuredId == null) logger
|
|
421
|
-
else if (actor.featuredId.href != context
|
|
412
|
+
if (actor?.featuredId == null) logger.warn("You configured a featured collection dispatcher, but the actor does not have a featured property. Set the property with Context.getFeaturedUri(identifier).");
|
|
413
|
+
else if (actor.featuredId.href != context.getFeaturedUri(identifier).href) logger.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).");
|
|
422
414
|
}
|
|
423
415
|
if (this.featuredTagsCallbacks != null && this.featuredTagsCallbacks.dispatcher != null) {
|
|
424
|
-
if (actor?.featuredTagsId == null) logger
|
|
425
|
-
else if (actor.featuredTagsId.href != context
|
|
416
|
+
if (actor?.featuredTagsId == null) logger.warn("You configured a featured tags collection dispatcher, but the actor does not have a featuredTags property. Set the property with Context.getFeaturedTagsUri(identifier).");
|
|
417
|
+
else if (actor.featuredTagsId.href != context.getFeaturedTagsUri(identifier).href) logger.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).");
|
|
426
418
|
}
|
|
427
419
|
if (this.router.has("inbox")) {
|
|
428
|
-
if (actor.inboxId == null) logger
|
|
429
|
-
else if (actor.inboxId.href != context
|
|
430
|
-
if (actor.endpoints == null || actor.endpoints.sharedInbox == null) logger
|
|
431
|
-
else if (actor.endpoints.sharedInbox.href != context
|
|
420
|
+
if (actor.inboxId == null) logger.warn("You configured inbox listeners, but the actor does not have an inbox property. Set the property with Context.getInboxUri(identifier).");
|
|
421
|
+
else if (actor.inboxId.href != context.getInboxUri(identifier).href) logger.warn("You configured inbox listeners, but the actor's inbox property does not match the inbox URI. Set the property with Context.getInboxUri(identifier).");
|
|
422
|
+
if (actor.endpoints == null || actor.endpoints.sharedInbox == null) logger.warn("You configured inbox listeners, but the actor does not have a endpoints.sharedInbox property. Set the property with Context.getInboxUri().");
|
|
423
|
+
else if (actor.endpoints.sharedInbox.href != context.getInboxUri().href) logger.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().");
|
|
432
424
|
}
|
|
433
425
|
if (callbacks.keyPairsDispatcher != null) {
|
|
434
|
-
if (actor.publicKeyId == null) logger
|
|
435
|
-
if (actor.assertionMethodId == null) logger
|
|
426
|
+
if (actor.publicKeyId == null) logger.warn("You configured a key pairs dispatcher, but the actor does not have a publicKey property. Set the property with Context.getActorKeyPairs(identifier).");
|
|
427
|
+
if (actor.assertionMethodId == null) logger.warn("You configured a key pairs dispatcher, but the actor does not have an assertionMethod property. Set the property with Context.getActorKeyPairs(identifier).");
|
|
436
428
|
}
|
|
437
429
|
return actor;
|
|
438
430
|
} };
|
|
439
431
|
this.actorCallbacks = callbacks;
|
|
440
432
|
const setters = {
|
|
441
|
-
setKeyPairsDispatcher: (dispatcher
|
|
433
|
+
setKeyPairsDispatcher: (dispatcher) => {
|
|
442
434
|
callbacks.keyPairsDispatcher = (ctx, identifier) => this._getTracer().startActiveSpan("activitypub.dispatch_actor_key_pairs", {
|
|
443
435
|
kind: SpanKind.SERVER,
|
|
444
436
|
attributes: {
|
|
@@ -447,7 +439,7 @@ var FederationBuilderImpl = class {
|
|
|
447
439
|
}
|
|
448
440
|
}, async (span) => {
|
|
449
441
|
try {
|
|
450
|
-
return await dispatcher
|
|
442
|
+
return await dispatcher(ctx, identifier);
|
|
451
443
|
} catch (e) {
|
|
452
444
|
span.setStatus({
|
|
453
445
|
code: SpanStatusCode.ERROR,
|
|
@@ -477,8 +469,7 @@ var FederationBuilderImpl = class {
|
|
|
477
469
|
}
|
|
478
470
|
setNodeInfoDispatcher(path, dispatcher) {
|
|
479
471
|
if (this.router.has("nodeInfo")) throw new RouterError("NodeInfo dispatcher already set.");
|
|
480
|
-
|
|
481
|
-
if (variables.size !== 0) throw new RouterError("Path for NodeInfo dispatcher must have no variables.");
|
|
472
|
+
if (this.router.add(path, "nodeInfo").size !== 0) throw new RouterError("Path for NodeInfo dispatcher must have no variables.");
|
|
482
473
|
this.nodeInfoDispatcher = dispatcher;
|
|
483
474
|
}
|
|
484
475
|
setWebFingerLinksDispatcher(dispatcher) {
|
|
@@ -491,8 +482,7 @@ var FederationBuilderImpl = class {
|
|
|
491
482
|
if (variables.size < 1) throw new RouterError("Path for object dispatcher must have at least one variable.");
|
|
492
483
|
const callbacks = {
|
|
493
484
|
dispatcher: (ctx, values) => {
|
|
494
|
-
|
|
495
|
-
return tracer.startActiveSpan("activitypub.dispatch_object", {
|
|
485
|
+
return this._getTracer().startActiveSpan("activitypub.dispatch_object", {
|
|
496
486
|
kind: SpanKind.SERVER,
|
|
497
487
|
attributes: {
|
|
498
488
|
"fedify.object.type": cls.typeId.href,
|
|
@@ -723,8 +713,7 @@ var FederationBuilderImpl = class {
|
|
|
723
713
|
this.inboxPath = inboxPath;
|
|
724
714
|
}
|
|
725
715
|
if (sharedInboxPath != null) {
|
|
726
|
-
|
|
727
|
-
if (siVars.size !== 0) throw new RouterError("Path for shared inbox must have no variables.");
|
|
716
|
+
if (this.router.add(sharedInboxPath, "sharedInbox").size !== 0) throw new RouterError("Path for shared inbox must have no variables.");
|
|
728
717
|
}
|
|
729
718
|
const listeners = this.inboxListeners = new InboxListenerSet();
|
|
730
719
|
const setters = {
|
|
@@ -758,8 +747,7 @@ var FederationBuilderImpl = class {
|
|
|
758
747
|
const routeName = `${collectionType}:${this.#uniqueCollectionId(name)}`;
|
|
759
748
|
if (this.router.has(routeName)) throw new RouterError(`Collection dispatcher for ${strName} already set.`);
|
|
760
749
|
if (this.collectionCallbacks[name] != null) throw new RouterError(`Collection dispatcher for ${strName} already set.`);
|
|
761
|
-
|
|
762
|
-
if (variables.size < 1) throw new RouterError("Path for collection dispatcher must have at least one variable.");
|
|
750
|
+
if (this.router.add(path, routeName).size < 1) throw new RouterError("Path for collection dispatcher must have at least one variable.");
|
|
763
751
|
const callbacks = { dispatcher };
|
|
764
752
|
this.collectionCallbacks[name] = callbacks;
|
|
765
753
|
this.collectionTypeIds[name] = itemType;
|
|
@@ -794,8 +782,7 @@ var FederationBuilderImpl = class {
|
|
|
794
782
|
getCollectionPath(name, values) {
|
|
795
783
|
if (!(name in this.collectionCallbacks)) return null;
|
|
796
784
|
const routeName = this.#uniqueCollectionId(name);
|
|
797
|
-
|
|
798
|
-
return path;
|
|
785
|
+
return this.router.build(`collection:${routeName}`, values) ?? this.router.build(`orderedCollection:${routeName}`, values);
|
|
799
786
|
}
|
|
800
787
|
setOutboxPermanentFailureHandler(handler) {
|
|
801
788
|
this.outboxPermanentFailureHandler = handler;
|
|
@@ -821,7 +808,6 @@ var FederationBuilderImpl = class {
|
|
|
821
808
|
function createFederationBuilder() {
|
|
822
809
|
return new FederationBuilderImpl();
|
|
823
810
|
}
|
|
824
|
-
|
|
825
811
|
//#endregion
|
|
826
812
|
//#region src/federation/collection.ts
|
|
827
813
|
/**
|
|
@@ -840,8 +826,8 @@ async function digest(uris) {
|
|
|
840
826
|
if (processed.has(u)) continue;
|
|
841
827
|
processed.add(u);
|
|
842
828
|
const encoded = encoder.encode(u);
|
|
843
|
-
const digest
|
|
844
|
-
for (let i = 0; i < 32; i++) result[i] ^= digest
|
|
829
|
+
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", encoded));
|
|
830
|
+
for (let i = 0; i < 32; i++) result[i] ^= digest[i];
|
|
845
831
|
}
|
|
846
832
|
return result;
|
|
847
833
|
}
|
|
@@ -859,12 +845,15 @@ async function buildCollectionSynchronizationHeader(collectionId, actorIds) {
|
|
|
859
845
|
const baseUrl = new URL(anyActorId);
|
|
860
846
|
const url = new URL(collectionId);
|
|
861
847
|
url.searchParams.set("base-url", `${baseUrl.origin}/`);
|
|
862
|
-
|
|
863
|
-
return `collectionId="${collectionId}", url="${url}", digest="${hash}"`;
|
|
848
|
+
return `collectionId="${collectionId}", url="${url}", digest="${encodeHex(await digest(actorIds))}"`;
|
|
864
849
|
}
|
|
865
|
-
|
|
866
850
|
//#endregion
|
|
867
851
|
//#region src/federation/keycache.ts
|
|
852
|
+
const NULL_KEY_CACHE_VALUE = { _fedify: "key-unavailable" };
|
|
853
|
+
const NULL_KEY_CACHE_TTL = Temporal.Duration.from({ minutes: 5 });
|
|
854
|
+
function isNullKeyCacheValue(value) {
|
|
855
|
+
return typeof value === "object" && value != null && "_fedify" in value && value._fedify === NULL_KEY_CACHE_VALUE._fedify;
|
|
856
|
+
}
|
|
868
857
|
var KvKeyCache = class {
|
|
869
858
|
kv;
|
|
870
859
|
prefix;
|
|
@@ -880,6 +869,10 @@ var KvKeyCache = class {
|
|
|
880
869
|
if (this.nullKeys.has(keyId.href)) return null;
|
|
881
870
|
const serialized = await this.kv.get([...this.prefix, keyId.href]);
|
|
882
871
|
if (serialized == null) return void 0;
|
|
872
|
+
if (isNullKeyCacheValue(serialized)) {
|
|
873
|
+
this.nullKeys.add(keyId.href);
|
|
874
|
+
return null;
|
|
875
|
+
}
|
|
883
876
|
try {
|
|
884
877
|
return await CryptographicKey.fromJsonLd(serialized, this.options);
|
|
885
878
|
} catch {
|
|
@@ -887,14 +880,14 @@ var KvKeyCache = class {
|
|
|
887
880
|
return await Multikey.fromJsonLd(serialized, this.options);
|
|
888
881
|
} catch {
|
|
889
882
|
await this.kv.delete([...this.prefix, keyId.href]);
|
|
890
|
-
return
|
|
883
|
+
return;
|
|
891
884
|
}
|
|
892
885
|
}
|
|
893
886
|
}
|
|
894
887
|
async set(keyId, key) {
|
|
895
888
|
if (key == null) {
|
|
896
889
|
this.nullKeys.add(keyId.href);
|
|
897
|
-
await this.kv.
|
|
890
|
+
await this.kv.set([...this.prefix, keyId.href], NULL_KEY_CACHE_VALUE, { ttl: NULL_KEY_CACHE_TTL });
|
|
898
891
|
return;
|
|
899
892
|
}
|
|
900
893
|
this.nullKeys.delete(keyId.href);
|
|
@@ -902,7 +895,6 @@ var KvKeyCache = class {
|
|
|
902
895
|
await this.kv.set([...this.prefix, keyId.href], serialized);
|
|
903
896
|
}
|
|
904
897
|
};
|
|
905
|
-
|
|
906
898
|
//#endregion
|
|
907
899
|
//#region src/federation/negotiation.ts
|
|
908
900
|
function compareSpecs(a, b) {
|
|
@@ -947,8 +939,8 @@ function parseMediaType(str, i) {
|
|
|
947
939
|
function parseAccept(accept) {
|
|
948
940
|
const accepts = accept.split(",").map((p) => p.trim());
|
|
949
941
|
const mediaTypes = [];
|
|
950
|
-
for (const [index, accept
|
|
951
|
-
const mediaType = parseMediaType(accept
|
|
942
|
+
for (const [index, accept] of accepts.entries()) {
|
|
943
|
+
const mediaType = parseMediaType(accept.trim(), index);
|
|
952
944
|
if (mediaType) mediaTypes.push(mediaType);
|
|
953
945
|
}
|
|
954
946
|
return mediaTypes;
|
|
@@ -957,8 +949,7 @@ function getFullType(spec) {
|
|
|
957
949
|
return `${spec.type}/${spec.subtype}`;
|
|
958
950
|
}
|
|
959
951
|
function preferredMediaTypes(accept) {
|
|
960
|
-
|
|
961
|
-
return accepts.filter(isQuality).sort(compareSpecs).map(getFullType);
|
|
952
|
+
return parseAccept(accept === void 0 ? "*/*" : accept ?? "").filter(isQuality).sort(compareSpecs).map(getFullType);
|
|
962
953
|
}
|
|
963
954
|
function acceptsJsonLd(request) {
|
|
964
955
|
const accept = request.headers.get("Accept");
|
|
@@ -967,7 +958,6 @@ function acceptsJsonLd(request) {
|
|
|
967
958
|
if (types[0] === "text/html" || types[0] === "application/xhtml+xml") return false;
|
|
968
959
|
return types.includes("application/activity+json") || types.includes("application/ld+json") || types.includes("application/json");
|
|
969
960
|
}
|
|
970
|
-
|
|
971
961
|
//#endregion
|
|
972
962
|
//#region src/federation/handler.ts
|
|
973
963
|
/**
|
|
@@ -977,25 +967,25 @@ function acceptsJsonLd(request) {
|
|
|
977
967
|
* @param parameters The parameters for handling the actor.
|
|
978
968
|
* @returns A promise that resolves to an HTTP response.
|
|
979
969
|
*/
|
|
980
|
-
async function handleActor(request, { identifier, context
|
|
981
|
-
const logger
|
|
970
|
+
async function handleActor(request, { identifier, context, actorDispatcher, authorizePredicate, onNotFound, onUnauthorized }) {
|
|
971
|
+
const logger = getLogger([
|
|
982
972
|
"fedify",
|
|
983
973
|
"federation",
|
|
984
974
|
"actor"
|
|
985
975
|
]);
|
|
986
976
|
if (actorDispatcher == null) {
|
|
987
|
-
logger
|
|
977
|
+
logger.debug("Actor dispatcher is not set.", { identifier });
|
|
988
978
|
return await onNotFound(request);
|
|
989
979
|
}
|
|
990
|
-
const actor = await actorDispatcher(context
|
|
980
|
+
const actor = await actorDispatcher(context, identifier);
|
|
991
981
|
if (actor == null) {
|
|
992
|
-
logger
|
|
982
|
+
logger.debug("Actor {identifier} not found.", { identifier });
|
|
993
983
|
return await onNotFound(request);
|
|
994
984
|
}
|
|
995
985
|
if (authorizePredicate != null) {
|
|
996
|
-
if (!await authorizePredicate(context
|
|
986
|
+
if (!await authorizePredicate(context, identifier)) return await onUnauthorized(request);
|
|
997
987
|
}
|
|
998
|
-
const jsonLd = await actor.toJsonLd(context
|
|
988
|
+
const jsonLd = await actor.toJsonLd(context);
|
|
999
989
|
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
1000
990
|
"Content-Type": "application/activity+json",
|
|
1001
991
|
Vary: "Accept"
|
|
@@ -1008,14 +998,14 @@ async function handleActor(request, { identifier, context: context$1, actorDispa
|
|
|
1008
998
|
* @param parameters The parameters for handling the object.
|
|
1009
999
|
* @returns A promise that resolves to an HTTP response.
|
|
1010
1000
|
*/
|
|
1011
|
-
async function handleObject(request, { values, context
|
|
1001
|
+
async function handleObject(request, { values, context, objectDispatcher, authorizePredicate, onNotFound, onUnauthorized }) {
|
|
1012
1002
|
if (objectDispatcher == null) return await onNotFound(request);
|
|
1013
|
-
const object = await objectDispatcher(context
|
|
1003
|
+
const object = await objectDispatcher(context, values);
|
|
1014
1004
|
if (object == null) return await onNotFound(request);
|
|
1015
1005
|
if (authorizePredicate != null) {
|
|
1016
|
-
if (!await authorizePredicate(context
|
|
1006
|
+
if (!await authorizePredicate(context, values)) return await onUnauthorized(request);
|
|
1017
1007
|
}
|
|
1018
|
-
const jsonLd = await object.toJsonLd(context
|
|
1008
|
+
const jsonLd = await object.toJsonLd(context);
|
|
1019
1009
|
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
1020
1010
|
"Content-Type": "application/activity+json",
|
|
1021
1011
|
Vary: "Accept"
|
|
@@ -1031,18 +1021,17 @@ async function handleObject(request, { values, context: context$1, objectDispatc
|
|
|
1031
1021
|
* @param parameters The parameters for handling the collection.
|
|
1032
1022
|
* @returns A promise that resolves to an HTTP response.
|
|
1033
1023
|
*/
|
|
1034
|
-
async function handleCollection(request, { name, identifier, uriGetter, filter, filterPredicate, context
|
|
1035
|
-
const spanName = name.trim().replace(/\s+/g, "_");
|
|
1024
|
+
async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, onUnauthorized, onNotFound }) {
|
|
1025
|
+
const spanName = name$1.trim().replace(/\s+/g, "_");
|
|
1036
1026
|
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
1037
|
-
const tracer = tracerProvider.getTracer(
|
|
1038
|
-
const
|
|
1039
|
-
const cursor = url.searchParams.get("cursor");
|
|
1027
|
+
const tracer = tracerProvider.getTracer(name, version);
|
|
1028
|
+
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1040
1029
|
if (collectionCallbacks == null) return await onNotFound(request);
|
|
1041
1030
|
let collection;
|
|
1042
1031
|
const baseUri = uriGetter(identifier);
|
|
1043
1032
|
if (cursor == null) {
|
|
1044
|
-
const firstCursor = await collectionCallbacks.firstCursor?.(context
|
|
1045
|
-
const totalItems = filter == null ? await collectionCallbacks.counter?.(context
|
|
1033
|
+
const firstCursor = await collectionCallbacks.firstCursor?.(context, identifier);
|
|
1034
|
+
const totalItems = filter == null ? await collectionCallbacks.counter?.(context, identifier) : void 0;
|
|
1046
1035
|
if (firstCursor == null) {
|
|
1047
1036
|
const itemsOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection ${spanName}`, {
|
|
1048
1037
|
kind: SpanKind.SERVER,
|
|
@@ -1053,7 +1042,7 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1053
1042
|
}, async (span) => {
|
|
1054
1043
|
if (totalItems != null) span.setAttribute("activitypub.collection.total_items", Number(totalItems));
|
|
1055
1044
|
try {
|
|
1056
|
-
const page = await collectionCallbacks.dispatcher(context
|
|
1045
|
+
const page = await collectionCallbacks.dispatcher(context, identifier, null, filter);
|
|
1057
1046
|
if (page == null) {
|
|
1058
1047
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1059
1048
|
return await onNotFound(request);
|
|
@@ -1075,15 +1064,15 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1075
1064
|
collection = new OrderedCollection({
|
|
1076
1065
|
id: baseUri,
|
|
1077
1066
|
totalItems: totalItems == null ? null : Number(totalItems),
|
|
1078
|
-
items: filterCollectionItems(itemsOrResponse, name, filterPredicate)
|
|
1067
|
+
items: filterCollectionItems(itemsOrResponse, name$1, filterPredicate)
|
|
1079
1068
|
});
|
|
1080
1069
|
} else {
|
|
1081
|
-
const lastCursor = await collectionCallbacks.lastCursor?.(context
|
|
1082
|
-
const first = new URL(context
|
|
1070
|
+
const lastCursor = await collectionCallbacks.lastCursor?.(context, identifier);
|
|
1071
|
+
const first = new URL(context.url);
|
|
1083
1072
|
first.searchParams.set("cursor", firstCursor);
|
|
1084
1073
|
let last = null;
|
|
1085
1074
|
if (lastCursor != null) {
|
|
1086
|
-
last = new URL(context
|
|
1075
|
+
last = new URL(context.url);
|
|
1087
1076
|
last.searchParams.set("cursor", lastCursor);
|
|
1088
1077
|
}
|
|
1089
1078
|
collection = new OrderedCollection({
|
|
@@ -1096,7 +1085,7 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1096
1085
|
} else {
|
|
1097
1086
|
const uri = new URL(baseUri);
|
|
1098
1087
|
uri.searchParams.set("cursor", cursor);
|
|
1099
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name}`, {
|
|
1088
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
|
|
1100
1089
|
kind: SpanKind.SERVER,
|
|
1101
1090
|
attributes: {
|
|
1102
1091
|
"activitypub.collection.id": uri.href,
|
|
@@ -1105,7 +1094,7 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1105
1094
|
}
|
|
1106
1095
|
}, async (span) => {
|
|
1107
1096
|
try {
|
|
1108
|
-
const page = await collectionCallbacks.dispatcher(context
|
|
1097
|
+
const page = await collectionCallbacks.dispatcher(context, identifier, cursor, filter);
|
|
1109
1098
|
if (page == null) {
|
|
1110
1099
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1111
1100
|
return await onNotFound(request);
|
|
@@ -1126,28 +1115,28 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1126
1115
|
const { items, prevCursor, nextCursor } = pageOrResponse;
|
|
1127
1116
|
let prev = null;
|
|
1128
1117
|
if (prevCursor != null) {
|
|
1129
|
-
prev = new URL(context
|
|
1118
|
+
prev = new URL(context.url);
|
|
1130
1119
|
prev.searchParams.set("cursor", prevCursor);
|
|
1131
1120
|
}
|
|
1132
1121
|
let next = null;
|
|
1133
1122
|
if (nextCursor != null) {
|
|
1134
|
-
next = new URL(context
|
|
1123
|
+
next = new URL(context.url);
|
|
1135
1124
|
next.searchParams.set("cursor", nextCursor);
|
|
1136
1125
|
}
|
|
1137
|
-
const partOf = new URL(context
|
|
1126
|
+
const partOf = new URL(context.url);
|
|
1138
1127
|
partOf.searchParams.delete("cursor");
|
|
1139
1128
|
collection = new OrderedCollectionPage({
|
|
1140
1129
|
id: uri,
|
|
1141
1130
|
prev,
|
|
1142
1131
|
next,
|
|
1143
|
-
items: filterCollectionItems(items, name, filterPredicate),
|
|
1132
|
+
items: filterCollectionItems(items, name$1, filterPredicate),
|
|
1144
1133
|
partOf
|
|
1145
1134
|
});
|
|
1146
1135
|
}
|
|
1147
1136
|
if (collectionCallbacks.authorizePredicate != null) {
|
|
1148
|
-
if (!await collectionCallbacks.authorizePredicate(context
|
|
1137
|
+
if (!await collectionCallbacks.authorizePredicate(context, identifier)) return await onUnauthorized(request);
|
|
1149
1138
|
}
|
|
1150
|
-
const jsonLd = await collection.toJsonLd(context
|
|
1139
|
+
const jsonLd = await collection.toJsonLd(context);
|
|
1151
1140
|
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
1152
1141
|
"Content-Type": "application/activity+json",
|
|
1153
1142
|
Vary: "Accept"
|
|
@@ -1192,9 +1181,7 @@ function filterCollectionItems(items, collectionName, filterPredicate) {
|
|
|
1192
1181
|
* @returns A promise that resolves to an HTTP response.
|
|
1193
1182
|
*/
|
|
1194
1183
|
async function handleInbox(request, options) {
|
|
1195
|
-
|
|
1196
|
-
const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
|
|
1197
|
-
return await tracer.startActiveSpan("activitypub.inbox", {
|
|
1184
|
+
return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("activitypub.inbox", {
|
|
1198
1185
|
kind: options.queue == null ? SpanKind.SERVER : SpanKind.PRODUCER,
|
|
1199
1186
|
attributes: { "activitypub.shared_inbox": options.recipient == null }
|
|
1200
1187
|
}, async (span) => {
|
|
@@ -1222,22 +1209,21 @@ async function handleInbox(request, options) {
|
|
|
1222
1209
|
*/
|
|
1223
1210
|
async function handleInboxInternal(request, parameters, span) {
|
|
1224
1211
|
const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider } = parameters;
|
|
1225
|
-
const logger
|
|
1212
|
+
const logger = getLogger([
|
|
1226
1213
|
"fedify",
|
|
1227
1214
|
"federation",
|
|
1228
1215
|
"inbox"
|
|
1229
1216
|
]);
|
|
1230
1217
|
if (actorDispatcher == null) {
|
|
1231
|
-
logger
|
|
1218
|
+
logger.error("Actor dispatcher is not set.", { recipient });
|
|
1232
1219
|
span.setStatus({
|
|
1233
1220
|
code: SpanStatusCode.ERROR,
|
|
1234
1221
|
message: "Actor dispatcher is not set."
|
|
1235
1222
|
});
|
|
1236
1223
|
return await onNotFound(request);
|
|
1237
1224
|
} else if (recipient != null) {
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
logger$1.error("Actor {recipient} not found.", { recipient });
|
|
1225
|
+
if (await actorDispatcher(ctx, recipient) == null) {
|
|
1226
|
+
logger.error("Actor {recipient} not found.", { recipient });
|
|
1241
1227
|
span.setStatus({
|
|
1242
1228
|
code: SpanStatusCode.ERROR,
|
|
1243
1229
|
message: `Actor ${recipient} not found.`
|
|
@@ -1246,7 +1232,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1246
1232
|
}
|
|
1247
1233
|
}
|
|
1248
1234
|
if (request.bodyUsed) {
|
|
1249
|
-
logger
|
|
1235
|
+
logger.error("Request body has already been read.", { recipient });
|
|
1250
1236
|
span.setStatus({
|
|
1251
1237
|
code: SpanStatusCode.ERROR,
|
|
1252
1238
|
message: "Request body has already been read."
|
|
@@ -1256,7 +1242,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1256
1242
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1257
1243
|
});
|
|
1258
1244
|
} else if (request.body?.locked) {
|
|
1259
|
-
logger
|
|
1245
|
+
logger.error("Request body is locked.", { recipient });
|
|
1260
1246
|
span.setStatus({
|
|
1261
1247
|
code: SpanStatusCode.ERROR,
|
|
1262
1248
|
message: "Request body is locked."
|
|
@@ -1270,15 +1256,15 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1270
1256
|
try {
|
|
1271
1257
|
json = await request.clone().json();
|
|
1272
1258
|
} catch (error) {
|
|
1273
|
-
logger
|
|
1259
|
+
logger.error("Failed to parse JSON:\n{error}", {
|
|
1274
1260
|
recipient,
|
|
1275
1261
|
error
|
|
1276
1262
|
});
|
|
1277
1263
|
try {
|
|
1278
1264
|
await inboxErrorHandler?.(ctx, error);
|
|
1279
|
-
} catch (error
|
|
1280
|
-
logger
|
|
1281
|
-
error
|
|
1265
|
+
} catch (error) {
|
|
1266
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
1267
|
+
error,
|
|
1282
1268
|
activity: json,
|
|
1283
1269
|
recipient
|
|
1284
1270
|
});
|
|
@@ -1303,7 +1289,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1303
1289
|
});
|
|
1304
1290
|
} catch (error) {
|
|
1305
1291
|
if (error instanceof Error && error.name === "jsonld.SyntaxError") {
|
|
1306
|
-
logger
|
|
1292
|
+
logger.error("Failed to parse JSON-LD:\n{error}", {
|
|
1307
1293
|
recipient,
|
|
1308
1294
|
error
|
|
1309
1295
|
});
|
|
@@ -1317,13 +1303,13 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1317
1303
|
const jsonWithoutSig = detachSignature(json);
|
|
1318
1304
|
let activity = null;
|
|
1319
1305
|
if (ldSigVerified) {
|
|
1320
|
-
logger
|
|
1306
|
+
logger.debug("Linked Data Signatures are verified.", {
|
|
1321
1307
|
recipient,
|
|
1322
1308
|
json
|
|
1323
1309
|
});
|
|
1324
1310
|
activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
|
|
1325
1311
|
} else {
|
|
1326
|
-
logger
|
|
1312
|
+
logger.debug("Linked Data Signatures are not verified.", {
|
|
1327
1313
|
recipient,
|
|
1328
1314
|
json
|
|
1329
1315
|
});
|
|
@@ -1335,16 +1321,16 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1335
1321
|
tracerProvider
|
|
1336
1322
|
});
|
|
1337
1323
|
} catch (error) {
|
|
1338
|
-
logger
|
|
1324
|
+
logger.error("Failed to parse activity:\n{error}", {
|
|
1339
1325
|
recipient,
|
|
1340
1326
|
activity: json,
|
|
1341
1327
|
error
|
|
1342
1328
|
});
|
|
1343
1329
|
try {
|
|
1344
1330
|
await inboxErrorHandler?.(ctx, error);
|
|
1345
|
-
} catch (error
|
|
1346
|
-
logger
|
|
1347
|
-
error
|
|
1331
|
+
} catch (error) {
|
|
1332
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
1333
|
+
error,
|
|
1348
1334
|
activity: json,
|
|
1349
1335
|
recipient
|
|
1350
1336
|
});
|
|
@@ -1358,11 +1344,11 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1358
1344
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1359
1345
|
});
|
|
1360
1346
|
}
|
|
1361
|
-
if (activity == null) logger
|
|
1347
|
+
if (activity == null) logger.debug("Object Integrity Proofs are not verified.", {
|
|
1362
1348
|
recipient,
|
|
1363
1349
|
activity: json
|
|
1364
1350
|
});
|
|
1365
|
-
else logger
|
|
1351
|
+
else logger.debug("Object Integrity Proofs are verified.", {
|
|
1366
1352
|
recipient,
|
|
1367
1353
|
activity: json
|
|
1368
1354
|
});
|
|
@@ -1378,17 +1364,16 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1378
1364
|
tracerProvider
|
|
1379
1365
|
});
|
|
1380
1366
|
if (key == null) {
|
|
1381
|
-
logger
|
|
1367
|
+
logger.error("Failed to verify the request's HTTP Signatures.", { recipient });
|
|
1382
1368
|
span.setStatus({
|
|
1383
1369
|
code: SpanStatusCode.ERROR,
|
|
1384
1370
|
message: `Failed to verify the request's HTTP Signatures.`
|
|
1385
1371
|
});
|
|
1386
|
-
|
|
1372
|
+
return new Response("Failed to verify the request signature.", {
|
|
1387
1373
|
status: 401,
|
|
1388
1374
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1389
1375
|
});
|
|
1390
|
-
|
|
1391
|
-
} else logger$1.debug("HTTP Signatures are verified.", { recipient });
|
|
1376
|
+
} else logger.debug("HTTP Signatures are verified.", { recipient });
|
|
1392
1377
|
httpSigKey = key;
|
|
1393
1378
|
}
|
|
1394
1379
|
activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
|
|
@@ -1403,7 +1388,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1403
1388
|
"http_signatures.key_id": httpSigKey?.id?.href ?? ""
|
|
1404
1389
|
});
|
|
1405
1390
|
if (httpSigKey != null && !await doesActorOwnKey(activity, httpSigKey, ctx)) {
|
|
1406
|
-
logger
|
|
1391
|
+
logger.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
|
|
1407
1392
|
activity: json,
|
|
1408
1393
|
recipient,
|
|
1409
1394
|
keyId: httpSigKey.id?.href,
|
|
@@ -1470,11 +1455,11 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1470
1455
|
* @since 1.8.0
|
|
1471
1456
|
*/
|
|
1472
1457
|
const handleCustomCollection = exceptWrapper(_handleCustomCollection);
|
|
1473
|
-
async function _handleCustomCollection(request, { name, values, context
|
|
1458
|
+
async function _handleCustomCollection(request, { name, values, context, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
1474
1459
|
verifyDefined(callbacks);
|
|
1475
|
-
await authIfNeeded(context
|
|
1460
|
+
await authIfNeeded(context, values, callbacks);
|
|
1476
1461
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1477
|
-
return await new CustomCollectionHandler(name, values, context
|
|
1462
|
+
return await new CustomCollectionHandler(name, values, context, callbacks, tracerProvider, Collection, CollectionPage, filterPredicate).fetchCollection(cursor).toJsonLd().then(respondAsActivity);
|
|
1478
1463
|
}
|
|
1479
1464
|
/**
|
|
1480
1465
|
* Handles an ordered collection request.
|
|
@@ -1488,11 +1473,11 @@ async function _handleCustomCollection(request, { name, values, context: context
|
|
|
1488
1473
|
* @since 1.8.0
|
|
1489
1474
|
*/
|
|
1490
1475
|
const handleOrderedCollection = exceptWrapper(_handleOrderedCollection);
|
|
1491
|
-
async function _handleOrderedCollection(request, { name, values, context
|
|
1476
|
+
async function _handleOrderedCollection(request, { name, values, context, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
1492
1477
|
verifyDefined(callbacks);
|
|
1493
|
-
await authIfNeeded(context
|
|
1478
|
+
await authIfNeeded(context, values, callbacks);
|
|
1494
1479
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1495
|
-
return await new CustomCollectionHandler(name, values, context
|
|
1480
|
+
return await new CustomCollectionHandler(name, values, context, callbacks, tracerProvider, OrderedCollection, OrderedCollectionPage, filterPredicate).fetchCollection(cursor).toJsonLd().then(respondAsActivity);
|
|
1496
1481
|
}
|
|
1497
1482
|
/**
|
|
1498
1483
|
* Handling custom collections with support for pagination and filtering.
|
|
@@ -1542,17 +1527,17 @@ var CustomCollectionHandler = class {
|
|
|
1542
1527
|
* @param CollectionPage The CollectionPage constructor.
|
|
1543
1528
|
* @param filterPredicate Optional filter predicate for items.
|
|
1544
1529
|
*/
|
|
1545
|
-
constructor(name, values, context
|
|
1546
|
-
this.name = name;
|
|
1530
|
+
constructor(name$2, values, context, callbacks, tracerProvider = trace.getTracerProvider(), Collection, CollectionPage, filterPredicate) {
|
|
1531
|
+
this.name = name$2;
|
|
1547
1532
|
this.values = values;
|
|
1548
|
-
this.context = context
|
|
1533
|
+
this.context = context;
|
|
1549
1534
|
this.callbacks = callbacks;
|
|
1550
1535
|
this.tracerProvider = tracerProvider;
|
|
1551
|
-
this.Collection = Collection
|
|
1552
|
-
this.CollectionPage = CollectionPage
|
|
1536
|
+
this.Collection = Collection;
|
|
1537
|
+
this.CollectionPage = CollectionPage;
|
|
1553
1538
|
this.filterPredicate = filterPredicate;
|
|
1554
1539
|
this.name = this.name.trim().replace(/\s+/g, "_");
|
|
1555
|
-
this.#tracer = this.tracerProvider.getTracer(
|
|
1540
|
+
this.#tracer = this.tracerProvider.getTracer(name, version);
|
|
1556
1541
|
this.#id = new URL(this.context.url);
|
|
1557
1542
|
this.#dispatcher = callbacks.dispatcher.bind(callbacks);
|
|
1558
1543
|
}
|
|
@@ -1581,8 +1566,8 @@ var CustomCollectionHandler = class {
|
|
|
1581
1566
|
*/
|
|
1582
1567
|
async getCollection(cursor = null) {
|
|
1583
1568
|
if (cursor !== null) {
|
|
1584
|
-
const props
|
|
1585
|
-
return new this.CollectionPage(props
|
|
1569
|
+
const props = await this.getPageProps(cursor);
|
|
1570
|
+
return new this.CollectionPage(props);
|
|
1586
1571
|
}
|
|
1587
1572
|
const firstCursor = await this.firstCursor;
|
|
1588
1573
|
const props = typeof firstCursor === "string" ? await this.getProps(firstCursor) : await this.getPropsWithoutCursor();
|
|
@@ -1730,7 +1715,7 @@ var CustomCollectionHandler = class {
|
|
|
1730
1715
|
* @param value The total items count or a promise that resolves to it.
|
|
1731
1716
|
*/
|
|
1732
1717
|
set totalItems(value) {
|
|
1733
|
-
const toNumber = (value
|
|
1718
|
+
const toNumber = (value) => value == null ? null : Number(value);
|
|
1734
1719
|
this.#totalItems = value instanceof Promise ? value.then(toNumber) : Promise.resolve(toNumber(value));
|
|
1735
1720
|
}
|
|
1736
1721
|
/**
|
|
@@ -1794,9 +1779,9 @@ const verifyDefined = (callbacks) => {
|
|
|
1794
1779
|
* @throws {UnauthorizedError} If authorization fails.
|
|
1795
1780
|
* @since 1.8.0
|
|
1796
1781
|
*/
|
|
1797
|
-
const authIfNeeded = async (context
|
|
1782
|
+
const authIfNeeded = async (context, values, { authorizePredicate: authorize = void 0 }) => {
|
|
1798
1783
|
if (authorize === void 0) return;
|
|
1799
|
-
if (!await authorize(context
|
|
1784
|
+
if (!await authorize(context, values)) throw new UnauthorizedError();
|
|
1800
1785
|
};
|
|
1801
1786
|
/**
|
|
1802
1787
|
* Appends a cursor parameter to a URL if the cursor exists.
|
|
@@ -1882,7 +1867,6 @@ async function respondWithObjectIfAcceptable(object, request, options) {
|
|
|
1882
1867
|
response.headers.set("Vary", "Accept");
|
|
1883
1868
|
return response;
|
|
1884
1869
|
}
|
|
1885
|
-
|
|
1886
1870
|
//#endregion
|
|
1887
1871
|
//#region src/nodeinfo/handler.ts
|
|
1888
1872
|
/**
|
|
@@ -1892,10 +1876,9 @@ async function respondWithObjectIfAcceptable(object, request, options) {
|
|
|
1892
1876
|
* @param parameters The parameters for handling the request.
|
|
1893
1877
|
* @returns The response to the request.
|
|
1894
1878
|
*/
|
|
1895
|
-
async function handleNodeInfo(_request, { context
|
|
1896
|
-
const promise = nodeInfoDispatcher(context
|
|
1897
|
-
const
|
|
1898
|
-
const json = nodeInfoToJson(nodeInfo);
|
|
1879
|
+
async function handleNodeInfo(_request, { context, nodeInfoDispatcher }) {
|
|
1880
|
+
const promise = nodeInfoDispatcher(context);
|
|
1881
|
+
const json = nodeInfoToJson(promise instanceof Promise ? await promise : promise);
|
|
1899
1882
|
return new Response(JSON.stringify(json), { headers: { "Content-Type": "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\"" } });
|
|
1900
1883
|
}
|
|
1901
1884
|
/**
|
|
@@ -1905,22 +1888,20 @@ async function handleNodeInfo(_request, { context: context$1, nodeInfoDispatcher
|
|
|
1905
1888
|
* @param context The request context.
|
|
1906
1889
|
* @returns The response to the request.
|
|
1907
1890
|
*/
|
|
1908
|
-
function handleNodeInfoJrd(_request, context
|
|
1891
|
+
function handleNodeInfoJrd(_request, context) {
|
|
1909
1892
|
const links = [];
|
|
1910
1893
|
try {
|
|
1911
1894
|
links.push({
|
|
1912
1895
|
rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
|
1913
|
-
href: context
|
|
1896
|
+
href: context.getNodeInfoUri().href,
|
|
1914
1897
|
type: "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\""
|
|
1915
1898
|
});
|
|
1916
1899
|
} catch (e) {
|
|
1917
1900
|
if (!(e instanceof RouterError)) throw e;
|
|
1918
1901
|
}
|
|
1919
|
-
const
|
|
1920
|
-
const response = new Response(JSON.stringify(jrd), { headers: { "Content-Type": "application/jrd+json" } });
|
|
1902
|
+
const response = new Response(JSON.stringify({ links }), { headers: { "Content-Type": "application/jrd+json" } });
|
|
1921
1903
|
return Promise.resolve(response);
|
|
1922
1904
|
}
|
|
1923
|
-
|
|
1924
1905
|
//#endregion
|
|
1925
1906
|
//#region src/federation/retry.ts
|
|
1926
1907
|
/**
|
|
@@ -1951,7 +1932,6 @@ function createExponentialBackoffPolicy(options = {}) {
|
|
|
1951
1932
|
return Temporal.Duration.compare(delay, maxDelay) > 0 ? maxDelay : delay;
|
|
1952
1933
|
};
|
|
1953
1934
|
}
|
|
1954
|
-
|
|
1955
1935
|
//#endregion
|
|
1956
1936
|
//#region src/federation/send.ts
|
|
1957
1937
|
/**
|
|
@@ -1989,8 +1969,7 @@ function extractInboxes({ recipients, preferSharedInbox, excludeBaseUris }) {
|
|
|
1989
1969
|
*/
|
|
1990
1970
|
function sendActivity(options) {
|
|
1991
1971
|
const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
|
|
1992
|
-
|
|
1993
|
-
return tracer.startActiveSpan("activitypub.send_activity", {
|
|
1972
|
+
return tracerProvider.getTracer(name, version).startActiveSpan("activitypub.send_activity", {
|
|
1994
1973
|
kind: SpanKind.CLIENT,
|
|
1995
1974
|
attributes: { "activitypub.shared_inbox": options.sharedInbox ?? false }
|
|
1996
1975
|
}, async (span) => {
|
|
@@ -2041,7 +2020,7 @@ async function readLimitedResponseBody(response, maxBytes) {
|
|
|
2041
2020
|
return result;
|
|
2042
2021
|
}
|
|
2043
2022
|
async function sendActivityInternal({ activity, activityId, keys, inbox, headers, specDeterminer, tracerProvider }, span) {
|
|
2044
|
-
const logger
|
|
2023
|
+
const logger = getLogger([
|
|
2045
2024
|
"fedify",
|
|
2046
2025
|
"federation",
|
|
2047
2026
|
"outbox"
|
|
@@ -2058,7 +2037,7 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
|
|
|
2058
2037
|
rsaKey = key;
|
|
2059
2038
|
break;
|
|
2060
2039
|
}
|
|
2061
|
-
if (rsaKey == null) logger
|
|
2040
|
+
if (rsaKey == null) logger.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.", {
|
|
2062
2041
|
inbox: inbox.href,
|
|
2063
2042
|
keys: keys.map((pair) => ({
|
|
2064
2043
|
keyId: pair.keyId.href,
|
|
@@ -2072,7 +2051,7 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
|
|
|
2072
2051
|
specDeterminer
|
|
2073
2052
|
});
|
|
2074
2053
|
} catch (error) {
|
|
2075
|
-
logger
|
|
2054
|
+
logger.error("Failed to send activity {activityId} to {inbox}:\n{error}", {
|
|
2076
2055
|
activityId,
|
|
2077
2056
|
inbox: inbox.href,
|
|
2078
2057
|
error
|
|
@@ -2086,7 +2065,7 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
|
|
|
2086
2065
|
} catch (_) {
|
|
2087
2066
|
error = "";
|
|
2088
2067
|
}
|
|
2089
|
-
logger
|
|
2068
|
+
logger.error("Failed to send activity {activityId} to {inbox} ({status} {statusText}):\n{error}", {
|
|
2090
2069
|
activityId,
|
|
2091
2070
|
inbox: inbox.href,
|
|
2092
2071
|
status: response.status,
|
|
@@ -2138,7 +2117,6 @@ var SendActivityError = class extends Error {
|
|
|
2138
2117
|
this.responseBody = responseBody;
|
|
2139
2118
|
}
|
|
2140
2119
|
};
|
|
2141
|
-
|
|
2142
2120
|
//#endregion
|
|
2143
2121
|
//#region src/federation/webfinger.ts
|
|
2144
2122
|
const logger = getLogger([
|
|
@@ -2171,12 +2149,12 @@ async function handleWebFinger(request, options) {
|
|
|
2171
2149
|
}
|
|
2172
2150
|
});
|
|
2173
2151
|
}
|
|
2174
|
-
async function handleWebFingerInternal(request, { context
|
|
2152
|
+
async function handleWebFingerInternal(request, { context, host, actorDispatcher, actorHandleMapper, actorAliasMapper, onNotFound, span, webFingerLinksDispatcher }) {
|
|
2175
2153
|
if (actorDispatcher == null) {
|
|
2176
2154
|
logger.error("Actor dispatcher is not set.");
|
|
2177
2155
|
return await onNotFound(request);
|
|
2178
2156
|
}
|
|
2179
|
-
const resource = context
|
|
2157
|
+
const resource = context.url.searchParams.get("resource");
|
|
2180
2158
|
if (resource == null) return new Response("Missing resource parameter.", { status: 400 });
|
|
2181
2159
|
span?.setAttribute("webfinger.resource", resource);
|
|
2182
2160
|
let resourceUrl;
|
|
@@ -2192,26 +2170,26 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
2192
2170
|
logger.error("No actor handle mapper is set; use the WebFinger username {username} as the actor's internal identifier.", { username });
|
|
2193
2171
|
return username;
|
|
2194
2172
|
}
|
|
2195
|
-
const identifier
|
|
2196
|
-
if (identifier
|
|
2173
|
+
const identifier = await actorHandleMapper(context, username);
|
|
2174
|
+
if (identifier == null) {
|
|
2197
2175
|
logger.error("Actor {username} not found.", { username });
|
|
2198
2176
|
return null;
|
|
2199
2177
|
}
|
|
2200
|
-
return identifier
|
|
2178
|
+
return identifier;
|
|
2201
2179
|
}
|
|
2202
2180
|
let identifier = null;
|
|
2203
|
-
const uriParsed = context
|
|
2181
|
+
const uriParsed = context.parseUri(resourceUrl);
|
|
2204
2182
|
if (uriParsed?.type != "actor") {
|
|
2205
2183
|
const match = /^acct:([^@]+)@([^@]+)$/.exec(resource);
|
|
2206
2184
|
if (match == null) {
|
|
2207
|
-
const result = await actorAliasMapper?.(context
|
|
2185
|
+
const result = await actorAliasMapper?.(context, resourceUrl);
|
|
2208
2186
|
if (result == null) return await onNotFound(request);
|
|
2209
2187
|
if ("identifier" in result) identifier = result.identifier;
|
|
2210
2188
|
else identifier = await mapUsernameToIdentifier(result.username);
|
|
2211
2189
|
} else {
|
|
2212
2190
|
const portMatch = /:\d+$/.exec(match[2]);
|
|
2213
2191
|
const normalizedHost = portMatch == null ? domainToASCII(match[2].toLowerCase()) : domainToASCII(match[2].substring(0, portMatch.index).toLowerCase()) + portMatch[0];
|
|
2214
|
-
if (normalizedHost != context
|
|
2192
|
+
if (normalizedHost != context.url.host && normalizedHost != host) return await onNotFound(request);
|
|
2215
2193
|
else {
|
|
2216
2194
|
identifier = await mapUsernameToIdentifier(match[1]);
|
|
2217
2195
|
resourceUrl = new URL(`acct:${match[1]}@${normalizedHost}`);
|
|
@@ -2219,14 +2197,14 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
2219
2197
|
}
|
|
2220
2198
|
} else identifier = uriParsed.identifier;
|
|
2221
2199
|
if (identifier == null) return await onNotFound(request);
|
|
2222
|
-
const actor = await actorDispatcher(context
|
|
2200
|
+
const actor = await actorDispatcher(context, identifier);
|
|
2223
2201
|
if (actor == null) {
|
|
2224
2202
|
logger.error("Actor {identifier} not found.", { identifier });
|
|
2225
2203
|
return await onNotFound(request);
|
|
2226
2204
|
}
|
|
2227
2205
|
const links = [{
|
|
2228
2206
|
rel: "self",
|
|
2229
|
-
href: context
|
|
2207
|
+
href: context.getActorUri(identifier).href,
|
|
2230
2208
|
type: "application/activity+json"
|
|
2231
2209
|
}];
|
|
2232
2210
|
for (const url of actor.urls) if (url instanceof Link && url.href != null) links.push({
|
|
@@ -2247,16 +2225,16 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
2247
2225
|
});
|
|
2248
2226
|
}
|
|
2249
2227
|
if (webFingerLinksDispatcher != null) {
|
|
2250
|
-
const customLinks = await webFingerLinksDispatcher(context
|
|
2228
|
+
const customLinks = await webFingerLinksDispatcher(context, resourceUrl);
|
|
2251
2229
|
if (customLinks != null) for (const link of customLinks) links.push(link);
|
|
2252
2230
|
}
|
|
2253
2231
|
const aliases = [];
|
|
2254
2232
|
if (resourceUrl.protocol != "acct:" && actor.preferredUsername != null) {
|
|
2255
|
-
aliases.push(`acct:${actor.preferredUsername}@${host ?? context
|
|
2256
|
-
if (host != null && host !== context
|
|
2233
|
+
aliases.push(`acct:${actor.preferredUsername}@${host ?? context.url.host}`);
|
|
2234
|
+
if (host != null && host !== context.url.host) aliases.push(`acct:${actor.preferredUsername}@${context.url.host}`);
|
|
2257
2235
|
}
|
|
2258
|
-
if (resourceUrl.href !== context
|
|
2259
|
-
if (resourceUrl.protocol === "acct:" && host != null && host !== context
|
|
2236
|
+
if (resourceUrl.href !== context.getActorUri(identifier).href) aliases.push(context.getActorUri(identifier).href);
|
|
2237
|
+
if (resourceUrl.protocol === "acct:" && host != null && host !== context.url.host && !resourceUrl.href.endsWith(`@${host}`)) {
|
|
2260
2238
|
const username = resourceUrl.href.replace(/^acct:/, "").replace(/@.*$/, "");
|
|
2261
2239
|
aliases.push(`acct:${username}@${host}`);
|
|
2262
2240
|
}
|
|
@@ -2270,9 +2248,15 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
2270
2248
|
"Access-Control-Allow-Origin": "*"
|
|
2271
2249
|
} });
|
|
2272
2250
|
}
|
|
2273
|
-
|
|
2274
2251
|
//#endregion
|
|
2275
2252
|
//#region src/federation/middleware.ts
|
|
2253
|
+
var middleware_exports = /* @__PURE__ */ __exportAll({
|
|
2254
|
+
ContextImpl: () => ContextImpl,
|
|
2255
|
+
FederationImpl: () => FederationImpl,
|
|
2256
|
+
InboxContextImpl: () => InboxContextImpl,
|
|
2257
|
+
KvSpecDeterminer: () => KvSpecDeterminer,
|
|
2258
|
+
createFederation: () => createFederation
|
|
2259
|
+
});
|
|
2276
2260
|
/**
|
|
2277
2261
|
* Create a new {@link Federation} instance.
|
|
2278
2262
|
* @param parameters Parameters for initializing the instance.
|
|
@@ -2398,28 +2382,28 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2398
2382
|
this.router.add("/.well-known/nodeinfo", "nodeInfoJrd");
|
|
2399
2383
|
}
|
|
2400
2384
|
_getTracer() {
|
|
2401
|
-
return this.tracerProvider.getTracer(
|
|
2385
|
+
return this.tracerProvider.getTracer(name, version);
|
|
2402
2386
|
}
|
|
2403
2387
|
async _startQueueInternal(ctxData, signal, queue) {
|
|
2404
2388
|
if (this.inboxQueue == null && this.outboxQueue == null) return;
|
|
2405
|
-
const logger
|
|
2389
|
+
const logger = getLogger([
|
|
2406
2390
|
"fedify",
|
|
2407
2391
|
"federation",
|
|
2408
2392
|
"queue"
|
|
2409
2393
|
]);
|
|
2410
2394
|
const promises = [];
|
|
2411
2395
|
if (this.inboxQueue != null && (queue == null || queue === "inbox") && !this.inboxQueueStarted) {
|
|
2412
|
-
logger
|
|
2396
|
+
logger.debug("Starting an inbox task worker.");
|
|
2413
2397
|
this.inboxQueueStarted = true;
|
|
2414
2398
|
promises.push(this.inboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
2415
2399
|
}
|
|
2416
2400
|
if (this.outboxQueue != null && this.outboxQueue !== this.inboxQueue && (queue == null || queue === "outbox") && !this.outboxQueueStarted) {
|
|
2417
|
-
logger
|
|
2401
|
+
logger.debug("Starting an outbox task worker.");
|
|
2418
2402
|
this.outboxQueueStarted = true;
|
|
2419
2403
|
promises.push(this.outboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
2420
2404
|
}
|
|
2421
2405
|
if (this.fanoutQueue != null && this.fanoutQueue !== this.inboxQueue && this.fanoutQueue !== this.outboxQueue && (queue == null || queue === "fanout") && !this.fanoutQueueStarted) {
|
|
2422
|
-
logger
|
|
2406
|
+
logger.debug("Starting a fanout task worker.");
|
|
2423
2407
|
this.fanoutQueueStarted = true;
|
|
2424
2408
|
promises.push(this.fanoutQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
2425
2409
|
}
|
|
@@ -2503,12 +2487,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2503
2487
|
});
|
|
2504
2488
|
}
|
|
2505
2489
|
async #listenFanoutMessage(data, message) {
|
|
2506
|
-
|
|
2490
|
+
getLogger([
|
|
2507
2491
|
"fedify",
|
|
2508
2492
|
"federation",
|
|
2509
2493
|
"fanout"
|
|
2510
|
-
])
|
|
2511
|
-
logger$1.debug("Fanning out activity {activityId} to {inboxes} inbox(es)...", {
|
|
2494
|
+
]).debug("Fanning out activity {activityId} to {inboxes} inbox(es)...", {
|
|
2512
2495
|
activityId: message.activityId,
|
|
2513
2496
|
inboxes: globalThis.Object.keys(message.inboxes).length
|
|
2514
2497
|
});
|
|
@@ -2527,18 +2510,18 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2527
2510
|
}),
|
|
2528
2511
|
tracerProvider: this.tracerProvider
|
|
2529
2512
|
});
|
|
2530
|
-
const context
|
|
2513
|
+
const context = this.#createContext(new URL(message.baseUrl), data, { documentLoader: this.documentLoaderFactory({
|
|
2531
2514
|
allowPrivateAddress: this.allowPrivateAddress,
|
|
2532
2515
|
userAgent: this.userAgent
|
|
2533
2516
|
}) });
|
|
2534
2517
|
await this.sendActivity(keys, message.inboxes, activity, {
|
|
2535
2518
|
collectionSync: message.collectionSync,
|
|
2536
2519
|
orderingKey: message.orderingKey,
|
|
2537
|
-
context
|
|
2520
|
+
context
|
|
2538
2521
|
});
|
|
2539
2522
|
}
|
|
2540
2523
|
async #listenOutboxMessage(_, message, span) {
|
|
2541
|
-
const logger
|
|
2524
|
+
const logger = getLogger([
|
|
2542
2525
|
"fedify",
|
|
2543
2526
|
"federation",
|
|
2544
2527
|
"outbox"
|
|
@@ -2586,14 +2569,14 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2586
2569
|
});
|
|
2587
2570
|
try {
|
|
2588
2571
|
await this.onOutboxError?.(error, activity);
|
|
2589
|
-
} catch (error
|
|
2590
|
-
logger
|
|
2572
|
+
} catch (error) {
|
|
2573
|
+
logger.error("An unexpected error occurred in onError handler:\n{error}", {
|
|
2591
2574
|
...logData,
|
|
2592
|
-
error
|
|
2575
|
+
error
|
|
2593
2576
|
});
|
|
2594
2577
|
}
|
|
2595
2578
|
if (error instanceof SendActivityError && this.permanentFailureStatusCodes.includes(error.statusCode)) {
|
|
2596
|
-
logger
|
|
2579
|
+
logger.warn("Permanent delivery failure for activity {activityId} to {inbox} ({status}); not retrying.", {
|
|
2597
2580
|
...logData,
|
|
2598
2581
|
status: error.statusCode
|
|
2599
2582
|
});
|
|
@@ -2609,13 +2592,13 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2609
2592
|
try {
|
|
2610
2593
|
return [new URL(id)];
|
|
2611
2594
|
} catch {
|
|
2612
|
-
logger
|
|
2595
|
+
logger.warn("Invalid actorId URL in OutboxMessage: {id}", { id });
|
|
2613
2596
|
return [];
|
|
2614
2597
|
}
|
|
2615
2598
|
})
|
|
2616
2599
|
});
|
|
2617
2600
|
} catch (handlerError) {
|
|
2618
|
-
logger
|
|
2601
|
+
logger.error("An unexpected error occurred in outboxPermanentFailureHandler:\n{error}", {
|
|
2619
2602
|
...logData,
|
|
2620
2603
|
error: handlerError
|
|
2621
2604
|
});
|
|
@@ -2624,7 +2607,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2624
2607
|
return;
|
|
2625
2608
|
}
|
|
2626
2609
|
if (this.outboxQueue?.nativeRetrial) {
|
|
2627
|
-
logger
|
|
2610
|
+
logger.error("Failed to send activity {activityId} to {inbox}; backend will handle retry:\n{error}", {
|
|
2628
2611
|
...logData,
|
|
2629
2612
|
error
|
|
2630
2613
|
});
|
|
@@ -2635,7 +2618,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2635
2618
|
attempts: message.attempt
|
|
2636
2619
|
});
|
|
2637
2620
|
if (delay != null) {
|
|
2638
|
-
logger
|
|
2621
|
+
logger.error("Failed to send activity {activityId} to {inbox} (attempt #{attempt}); retry...:\n{error}", {
|
|
2639
2622
|
...logData,
|
|
2640
2623
|
error
|
|
2641
2624
|
});
|
|
@@ -2643,39 +2626,38 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2643
2626
|
...message,
|
|
2644
2627
|
attempt: message.attempt + 1
|
|
2645
2628
|
}, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
2646
|
-
} else logger
|
|
2629
|
+
} else logger.error("Failed to send activity {activityId} to {inbox} after {attempt} attempts; giving up:\n{error}", {
|
|
2647
2630
|
...logData,
|
|
2648
2631
|
error
|
|
2649
2632
|
});
|
|
2650
2633
|
return;
|
|
2651
2634
|
}
|
|
2652
|
-
logger
|
|
2635
|
+
logger.info("Successfully sent activity {activityId} to {inbox}.", { ...logData });
|
|
2653
2636
|
}
|
|
2654
2637
|
async #listenInboxMessage(ctxData, message, span) {
|
|
2655
|
-
const logger
|
|
2638
|
+
const logger = getLogger([
|
|
2656
2639
|
"fedify",
|
|
2657
2640
|
"federation",
|
|
2658
2641
|
"inbox"
|
|
2659
2642
|
]);
|
|
2660
2643
|
const baseUrl = new URL(message.baseUrl);
|
|
2661
|
-
let context
|
|
2662
|
-
if (message.identifier != null) context
|
|
2644
|
+
let context = this.#createContext(baseUrl, ctxData);
|
|
2645
|
+
if (message.identifier != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: await context.getDocumentLoader({ identifier: message.identifier }) });
|
|
2663
2646
|
else if (this.sharedInboxKeyDispatcher != null) {
|
|
2664
|
-
const identity = await this.sharedInboxKeyDispatcher(context
|
|
2665
|
-
if (identity != null) context
|
|
2647
|
+
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
2648
|
+
if (identity != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
2666
2649
|
}
|
|
2667
|
-
const activity = await Activity.fromJsonLd(message.activity, context
|
|
2650
|
+
const activity = await Activity.fromJsonLd(message.activity, context);
|
|
2668
2651
|
span.setAttribute("activitypub.activity.type", getTypeId(activity).href);
|
|
2669
2652
|
if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
|
|
2670
2653
|
const cacheKey = activity.id == null ? null : [
|
|
2671
2654
|
...this.kvPrefixes.activityIdempotence,
|
|
2672
|
-
context
|
|
2655
|
+
context.origin,
|
|
2673
2656
|
activity.id.href
|
|
2674
2657
|
];
|
|
2675
2658
|
if (cacheKey != null) {
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
logger$1.debug("Activity {activityId} has already been processed.", {
|
|
2659
|
+
if (await this.kv.get(cacheKey) === true) {
|
|
2660
|
+
logger.debug("Activity {activityId} has already been processed.", {
|
|
2679
2661
|
activityId: activity.id?.href,
|
|
2680
2662
|
activity: message.activity,
|
|
2681
2663
|
recipient: message.identifier
|
|
@@ -2683,32 +2665,32 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2683
2665
|
return;
|
|
2684
2666
|
}
|
|
2685
2667
|
}
|
|
2686
|
-
await this._getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span
|
|
2668
|
+
await this._getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span) => {
|
|
2687
2669
|
const dispatched = this.inboxListeners?.dispatchWithClass(activity);
|
|
2688
2670
|
if (dispatched == null) {
|
|
2689
|
-
logger
|
|
2671
|
+
logger.error("Unsupported activity type:\n{activity}", {
|
|
2690
2672
|
activityId: activity.id?.href,
|
|
2691
2673
|
activity: message.activity,
|
|
2692
2674
|
recipient: message.identifier,
|
|
2693
2675
|
trial: message.attempt
|
|
2694
2676
|
});
|
|
2695
|
-
span
|
|
2677
|
+
span.setStatus({
|
|
2696
2678
|
code: SpanStatusCode.ERROR,
|
|
2697
2679
|
message: `Unsupported activity type: ${getTypeId(activity).href}`
|
|
2698
2680
|
});
|
|
2699
|
-
span
|
|
2681
|
+
span.end();
|
|
2700
2682
|
return;
|
|
2701
2683
|
}
|
|
2702
2684
|
const { class: cls, listener } = dispatched;
|
|
2703
|
-
span
|
|
2685
|
+
span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
2704
2686
|
try {
|
|
2705
|
-
await listener(context
|
|
2687
|
+
await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, getTypeId(activity).href), activity);
|
|
2706
2688
|
} catch (error) {
|
|
2707
2689
|
try {
|
|
2708
|
-
await this.inboxErrorHandler?.(context
|
|
2709
|
-
} catch (error
|
|
2710
|
-
logger
|
|
2711
|
-
error
|
|
2690
|
+
await this.inboxErrorHandler?.(context, error);
|
|
2691
|
+
} catch (error) {
|
|
2692
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
2693
|
+
error,
|
|
2712
2694
|
trial: message.attempt,
|
|
2713
2695
|
activityId: activity.id?.href,
|
|
2714
2696
|
activity: message.activity,
|
|
@@ -2716,17 +2698,17 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2716
2698
|
});
|
|
2717
2699
|
}
|
|
2718
2700
|
if (this.inboxQueue?.nativeRetrial) {
|
|
2719
|
-
logger
|
|
2701
|
+
logger.error("Failed to process the incoming activity {activityId}; backend will handle retry:\n{error}", {
|
|
2720
2702
|
error,
|
|
2721
2703
|
activityId: activity.id?.href,
|
|
2722
2704
|
activity: message.activity,
|
|
2723
2705
|
recipient: message.identifier
|
|
2724
2706
|
});
|
|
2725
|
-
span
|
|
2707
|
+
span.setStatus({
|
|
2726
2708
|
code: SpanStatusCode.ERROR,
|
|
2727
2709
|
message: String(error)
|
|
2728
2710
|
});
|
|
2729
|
-
span
|
|
2711
|
+
span.end();
|
|
2730
2712
|
throw error;
|
|
2731
2713
|
}
|
|
2732
2714
|
const delay = this.inboxRetryPolicy({
|
|
@@ -2734,7 +2716,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2734
2716
|
attempts: message.attempt
|
|
2735
2717
|
});
|
|
2736
2718
|
if (delay != null) {
|
|
2737
|
-
logger
|
|
2719
|
+
logger.error("Failed to process the incoming activity {activityId} (attempt #{attempt}); retry...:\n{error}", {
|
|
2738
2720
|
error,
|
|
2739
2721
|
attempt: message.attempt,
|
|
2740
2722
|
activityId: activity.id?.href,
|
|
@@ -2745,26 +2727,26 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2745
2727
|
...message,
|
|
2746
2728
|
attempt: message.attempt + 1
|
|
2747
2729
|
}, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
2748
|
-
} else logger
|
|
2730
|
+
} else logger.error("Failed to process the incoming activity {activityId} after {trial} attempts; giving up:\n{error}", {
|
|
2749
2731
|
error,
|
|
2750
2732
|
activityId: activity.id?.href,
|
|
2751
2733
|
activity: message.activity,
|
|
2752
2734
|
recipient: message.identifier
|
|
2753
2735
|
});
|
|
2754
|
-
span
|
|
2736
|
+
span.setStatus({
|
|
2755
2737
|
code: SpanStatusCode.ERROR,
|
|
2756
2738
|
message: String(error)
|
|
2757
2739
|
});
|
|
2758
|
-
span
|
|
2740
|
+
span.end();
|
|
2759
2741
|
return;
|
|
2760
2742
|
}
|
|
2761
2743
|
if (cacheKey != null) await this.kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
|
|
2762
|
-
logger
|
|
2744
|
+
logger.info("Activity {activityId} has been processed.", {
|
|
2763
2745
|
activityId: activity.id?.href,
|
|
2764
2746
|
activity: message.activity,
|
|
2765
2747
|
recipient: message.identifier
|
|
2766
2748
|
});
|
|
2767
|
-
span
|
|
2749
|
+
span.end();
|
|
2768
2750
|
});
|
|
2769
2751
|
}
|
|
2770
2752
|
startQueue(contextData, options = {}) {
|
|
@@ -2808,7 +2790,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2808
2790
|
};
|
|
2809
2791
|
}
|
|
2810
2792
|
async sendActivity(keys, inboxes, activity, options) {
|
|
2811
|
-
const logger
|
|
2793
|
+
const logger = getLogger([
|
|
2812
2794
|
"fedify",
|
|
2813
2795
|
"federation",
|
|
2814
2796
|
"outbox"
|
|
@@ -2842,7 +2824,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2842
2824
|
format: "compact",
|
|
2843
2825
|
contextLoader
|
|
2844
2826
|
});
|
|
2845
|
-
if (rsaKey == null) logger
|
|
2827
|
+
if (rsaKey == null) logger.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.", {
|
|
2846
2828
|
activityId,
|
|
2847
2829
|
keys: keys.map((pair) => ({
|
|
2848
2830
|
keyId: pair.keyId.href,
|
|
@@ -2853,7 +2835,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2853
2835
|
contextLoader,
|
|
2854
2836
|
tracerProvider: this.tracerProvider
|
|
2855
2837
|
});
|
|
2856
|
-
if (!proofCreated) logger
|
|
2838
|
+
if (!proofCreated) logger.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.", {
|
|
2857
2839
|
activityId,
|
|
2858
2840
|
keys: keys.map((pair) => ({
|
|
2859
2841
|
keyId: pair.keyId.href,
|
|
@@ -2861,11 +2843,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2861
2843
|
}))
|
|
2862
2844
|
});
|
|
2863
2845
|
if (immediate || this.outboxQueue == null) {
|
|
2864
|
-
if (immediate) logger
|
|
2846
|
+
if (immediate) logger.debug("Sending activity immediately without queue since immediate option is set.", {
|
|
2865
2847
|
activityId: activity.id.href,
|
|
2866
2848
|
activity: jsonLd
|
|
2867
2849
|
});
|
|
2868
|
-
else logger
|
|
2850
|
+
else logger.debug("Sending activity immediately without queue since queue is not set.", {
|
|
2869
2851
|
activityId: activity.id.href,
|
|
2870
2852
|
activity: jsonLd
|
|
2871
2853
|
});
|
|
@@ -2884,7 +2866,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2884
2866
|
await Promise.all(promises);
|
|
2885
2867
|
return;
|
|
2886
2868
|
}
|
|
2887
|
-
logger
|
|
2869
|
+
logger.debug("Enqueuing activity {activityId} to send later.", {
|
|
2888
2870
|
activityId: activity.id.href,
|
|
2889
2871
|
activity: jsonLd
|
|
2890
2872
|
});
|
|
@@ -2928,10 +2910,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2928
2910
|
const { outboxQueue } = this;
|
|
2929
2911
|
if (outboxQueue.enqueueMany == null) {
|
|
2930
2912
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
2931
|
-
const
|
|
2932
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2913
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2933
2914
|
if (errors.length > 0) {
|
|
2934
|
-
logger
|
|
2915
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
|
|
2935
2916
|
activityId: activity.id.href,
|
|
2936
2917
|
errors
|
|
2937
2918
|
});
|
|
@@ -2940,10 +2921,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2940
2921
|
}
|
|
2941
2922
|
} else if (orderingKey != null) {
|
|
2942
2923
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
2943
|
-
const
|
|
2944
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2924
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2945
2925
|
if (errors.length > 0) {
|
|
2946
|
-
logger
|
|
2926
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
|
|
2947
2927
|
activityId: activity.id.href,
|
|
2948
2928
|
errors
|
|
2949
2929
|
});
|
|
@@ -2953,7 +2933,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2953
2933
|
} else try {
|
|
2954
2934
|
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
2955
2935
|
} catch (error) {
|
|
2956
|
-
logger
|
|
2936
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {error}", {
|
|
2957
2937
|
activityId: activity.id.href,
|
|
2958
2938
|
error
|
|
2959
2939
|
});
|
|
@@ -2961,8 +2941,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2961
2941
|
}
|
|
2962
2942
|
}
|
|
2963
2943
|
fetch(request, options) {
|
|
2964
|
-
|
|
2965
|
-
return withContext({ requestId }, async () => {
|
|
2944
|
+
return withContext({ requestId: getRequestId(request) }, async () => {
|
|
2966
2945
|
const tracer = this._getTracer();
|
|
2967
2946
|
return await tracer.startActiveSpan(request.method, {
|
|
2968
2947
|
kind: SpanKind.SERVER,
|
|
@@ -2976,7 +2955,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2976
2955
|
traceId: spanCtx.traceId,
|
|
2977
2956
|
spanId: spanCtx.spanId
|
|
2978
2957
|
}, async () => {
|
|
2979
|
-
const logger
|
|
2958
|
+
const logger = getLogger([
|
|
2980
2959
|
"fedify",
|
|
2981
2960
|
"federation",
|
|
2982
2961
|
"http"
|
|
@@ -2996,7 +2975,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2996
2975
|
message: `${error}`
|
|
2997
2976
|
});
|
|
2998
2977
|
span.end();
|
|
2999
|
-
logger
|
|
2978
|
+
logger.error("An error occurred while serving request {method} {url}: {error}", {
|
|
3000
2979
|
method: request.method,
|
|
3001
2980
|
url: request.url,
|
|
3002
2981
|
error
|
|
@@ -3020,9 +2999,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3020
2999
|
url: request.url,
|
|
3021
3000
|
status: response.status
|
|
3022
3001
|
};
|
|
3023
|
-
if (response.status >= 500) logger
|
|
3024
|
-
else if (response.status >= 400) logger
|
|
3025
|
-
else logger
|
|
3002
|
+
if (response.status >= 500) logger.error(logTpl, values);
|
|
3003
|
+
else if (response.status >= 400) logger.warn(logTpl, values);
|
|
3004
|
+
else logger.info(logTpl, values);
|
|
3026
3005
|
return response;
|
|
3027
3006
|
});
|
|
3028
3007
|
});
|
|
@@ -3036,11 +3015,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3036
3015
|
const route = this.router.route(url.pathname);
|
|
3037
3016
|
if (route == null) return await onNotFound(request);
|
|
3038
3017
|
span.updateName(`${request.method} ${route.template}`);
|
|
3039
|
-
let context
|
|
3018
|
+
let context = this.#createContext(request, contextData);
|
|
3040
3019
|
const routeName = route.name.replace(/:.*$/, "");
|
|
3041
3020
|
switch (routeName) {
|
|
3042
3021
|
case "webfinger": return await handleWebFinger(request, {
|
|
3043
|
-
context
|
|
3022
|
+
context,
|
|
3044
3023
|
host: this.origin?.handleHost,
|
|
3045
3024
|
actorDispatcher: this.actorCallbacks?.dispatcher,
|
|
3046
3025
|
actorHandleMapper: this.actorCallbacks?.handleMapper,
|
|
@@ -3049,19 +3028,19 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3049
3028
|
onNotFound,
|
|
3050
3029
|
tracer
|
|
3051
3030
|
});
|
|
3052
|
-
case "nodeInfoJrd": return await handleNodeInfoJrd(request, context
|
|
3031
|
+
case "nodeInfoJrd": return await handleNodeInfoJrd(request, context);
|
|
3053
3032
|
case "nodeInfo": return await handleNodeInfo(request, {
|
|
3054
|
-
context
|
|
3033
|
+
context,
|
|
3055
3034
|
nodeInfoDispatcher: this.nodeInfoDispatcher
|
|
3056
3035
|
});
|
|
3057
3036
|
}
|
|
3058
3037
|
if (request.method !== "POST" && !acceptsJsonLd(request)) return await onNotAcceptable(request);
|
|
3059
3038
|
switch (routeName) {
|
|
3060
3039
|
case "actor":
|
|
3061
|
-
context
|
|
3040
|
+
context = this.#createContext(request, contextData, { invokedFromActorDispatcher: { identifier: route.values.identifier } });
|
|
3062
3041
|
return await handleActor(request, {
|
|
3063
3042
|
identifier: route.values.identifier,
|
|
3064
|
-
context
|
|
3043
|
+
context,
|
|
3065
3044
|
actorDispatcher: this.actorCallbacks?.dispatcher,
|
|
3066
3045
|
authorizePredicate: this.actorCallbacks?.authorizePredicate,
|
|
3067
3046
|
onUnauthorized,
|
|
@@ -3071,13 +3050,13 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3071
3050
|
const typeId = route.name.replace(/^object:/, "");
|
|
3072
3051
|
const callbacks = this.objectCallbacks[typeId];
|
|
3073
3052
|
const cls = this.objectTypeIds[typeId];
|
|
3074
|
-
context
|
|
3053
|
+
context = this.#createContext(request, contextData, { invokedFromObjectDispatcher: {
|
|
3075
3054
|
cls,
|
|
3076
3055
|
values: route.values
|
|
3077
3056
|
} });
|
|
3078
3057
|
return await handleObject(request, {
|
|
3079
3058
|
values: route.values,
|
|
3080
|
-
context
|
|
3059
|
+
context,
|
|
3081
3060
|
objectDispatcher: callbacks?.dispatcher,
|
|
3082
3061
|
authorizePredicate: callbacks?.authorizePredicate,
|
|
3083
3062
|
onUnauthorized,
|
|
@@ -3087,8 +3066,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3087
3066
|
case "outbox": return await handleCollection(request, {
|
|
3088
3067
|
name: "outbox",
|
|
3089
3068
|
identifier: route.values.identifier,
|
|
3090
|
-
uriGetter: context
|
|
3091
|
-
context
|
|
3069
|
+
uriGetter: context.getOutboxUri.bind(context),
|
|
3070
|
+
context,
|
|
3092
3071
|
collectionCallbacks: this.outboxCallbacks,
|
|
3093
3072
|
tracerProvider: this.tracerProvider,
|
|
3094
3073
|
onUnauthorized,
|
|
@@ -3098,24 +3077,24 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3098
3077
|
if (request.method !== "POST") return await handleCollection(request, {
|
|
3099
3078
|
name: "inbox",
|
|
3100
3079
|
identifier: route.values.identifier,
|
|
3101
|
-
uriGetter: context
|
|
3102
|
-
context
|
|
3080
|
+
uriGetter: context.getInboxUri.bind(context),
|
|
3081
|
+
context,
|
|
3103
3082
|
collectionCallbacks: this.inboxCallbacks,
|
|
3104
3083
|
tracerProvider: this.tracerProvider,
|
|
3105
3084
|
onUnauthorized,
|
|
3106
3085
|
onNotFound
|
|
3107
3086
|
});
|
|
3108
|
-
context
|
|
3087
|
+
context = this.#createContext(request, contextData, { documentLoader: await context.getDocumentLoader({ identifier: route.values.identifier }) });
|
|
3109
3088
|
case "sharedInbox":
|
|
3110
3089
|
if (routeName !== "inbox" && this.sharedInboxKeyDispatcher != null) {
|
|
3111
|
-
const identity = await this.sharedInboxKeyDispatcher(context
|
|
3112
|
-
if (identity != null) context
|
|
3090
|
+
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
3091
|
+
if (identity != null) context = this.#createContext(request, contextData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
3113
3092
|
}
|
|
3114
3093
|
if (!this.manuallyStartQueue) this._startQueueInternal(contextData);
|
|
3115
3094
|
return await handleInbox(request, {
|
|
3116
3095
|
recipient: route.values.identifier ?? null,
|
|
3117
|
-
context
|
|
3118
|
-
inboxContextFactory: context
|
|
3096
|
+
context,
|
|
3097
|
+
inboxContextFactory: context.toInboxContext.bind(context),
|
|
3119
3098
|
kv: this.kv,
|
|
3120
3099
|
kvPrefixes: this.kvPrefixes,
|
|
3121
3100
|
queue: this.inboxQueue,
|
|
@@ -3131,8 +3110,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3131
3110
|
case "following": return await handleCollection(request, {
|
|
3132
3111
|
name: "following",
|
|
3133
3112
|
identifier: route.values.identifier,
|
|
3134
|
-
uriGetter: context
|
|
3135
|
-
context
|
|
3113
|
+
uriGetter: context.getFollowingUri.bind(context),
|
|
3114
|
+
context,
|
|
3136
3115
|
collectionCallbacks: this.followingCallbacks,
|
|
3137
3116
|
tracerProvider: this.tracerProvider,
|
|
3138
3117
|
onUnauthorized,
|
|
@@ -3148,14 +3127,14 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3148
3127
|
return await handleCollection(request, {
|
|
3149
3128
|
name: "followers",
|
|
3150
3129
|
identifier: route.values.identifier,
|
|
3151
|
-
uriGetter: baseUrl == null ? context
|
|
3152
|
-
const uri = context
|
|
3130
|
+
uriGetter: baseUrl == null ? context.getFollowersUri.bind(context) : (identifier) => {
|
|
3131
|
+
const uri = context.getFollowersUri(identifier);
|
|
3153
3132
|
uri.searchParams.set("base-url", baseUrl);
|
|
3154
3133
|
return uri;
|
|
3155
3134
|
},
|
|
3156
|
-
context
|
|
3135
|
+
context,
|
|
3157
3136
|
filter: baseUrl != null ? new URL(baseUrl) : void 0,
|
|
3158
|
-
filterPredicate: baseUrl != null ? (i) => (i instanceof URL ? i.href : i.id?.href ?? "").startsWith(baseUrl) : void 0,
|
|
3137
|
+
filterPredicate: baseUrl != null ? ((i) => (i instanceof URL ? i.href : i.id?.href ?? "").startsWith(baseUrl)) : void 0,
|
|
3159
3138
|
collectionCallbacks: this.followersCallbacks,
|
|
3160
3139
|
tracerProvider: this.tracerProvider,
|
|
3161
3140
|
onUnauthorized,
|
|
@@ -3165,8 +3144,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3165
3144
|
case "liked": return await handleCollection(request, {
|
|
3166
3145
|
name: "liked",
|
|
3167
3146
|
identifier: route.values.identifier,
|
|
3168
|
-
uriGetter: context
|
|
3169
|
-
context
|
|
3147
|
+
uriGetter: context.getLikedUri.bind(context),
|
|
3148
|
+
context,
|
|
3170
3149
|
collectionCallbacks: this.likedCallbacks,
|
|
3171
3150
|
tracerProvider: this.tracerProvider,
|
|
3172
3151
|
onUnauthorized,
|
|
@@ -3175,8 +3154,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3175
3154
|
case "featured": return await handleCollection(request, {
|
|
3176
3155
|
name: "featured",
|
|
3177
3156
|
identifier: route.values.identifier,
|
|
3178
|
-
uriGetter: context
|
|
3179
|
-
context
|
|
3157
|
+
uriGetter: context.getFeaturedUri.bind(context),
|
|
3158
|
+
context,
|
|
3180
3159
|
collectionCallbacks: this.featuredCallbacks,
|
|
3181
3160
|
tracerProvider: this.tracerProvider,
|
|
3182
3161
|
onUnauthorized,
|
|
@@ -3185,8 +3164,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3185
3164
|
case "featuredTags": return await handleCollection(request, {
|
|
3186
3165
|
name: "featured tags",
|
|
3187
3166
|
identifier: route.values.identifier,
|
|
3188
|
-
uriGetter: context
|
|
3189
|
-
context
|
|
3167
|
+
uriGetter: context.getFeaturedTagsUri.bind(context),
|
|
3168
|
+
context,
|
|
3190
3169
|
collectionCallbacks: this.featuredTagsCallbacks,
|
|
3191
3170
|
tracerProvider: this.tracerProvider,
|
|
3192
3171
|
onUnauthorized,
|
|
@@ -3197,7 +3176,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3197
3176
|
const callbacks = this.collectionCallbacks[name];
|
|
3198
3177
|
return await handleCustomCollection(request, {
|
|
3199
3178
|
name,
|
|
3200
|
-
context
|
|
3179
|
+
context,
|
|
3201
3180
|
values: route.values,
|
|
3202
3181
|
collectionCallbacks: callbacks,
|
|
3203
3182
|
tracerProvider: this.tracerProvider,
|
|
@@ -3210,7 +3189,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3210
3189
|
const callbacks = this.collectionCallbacks[name];
|
|
3211
3190
|
return await handleOrderedCollection(request, {
|
|
3212
3191
|
name,
|
|
3213
|
-
context
|
|
3192
|
+
context,
|
|
3214
3193
|
values: route.values,
|
|
3215
3194
|
collectionCallbacks: callbacks,
|
|
3216
3195
|
tracerProvider: this.tracerProvider,
|
|
@@ -3301,9 +3280,9 @@ var ContextImpl = class ContextImpl {
|
|
|
3301
3280
|
}
|
|
3302
3281
|
getInboxUri(identifier) {
|
|
3303
3282
|
if (identifier == null) {
|
|
3304
|
-
const path
|
|
3305
|
-
if (path
|
|
3306
|
-
return new URL(path
|
|
3283
|
+
const path = this.federation.router.build("sharedInbox", {});
|
|
3284
|
+
if (path == null) throw new RouterError("No shared inbox path registered.");
|
|
3285
|
+
return new URL(path, this.canonicalOrigin);
|
|
3307
3286
|
}
|
|
3308
3287
|
const path = this.federation.router.build("inbox", { identifier });
|
|
3309
3288
|
if (path == null) throw new RouterError("No inbox path registered.");
|
|
@@ -3389,8 +3368,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3389
3368
|
type: "featuredTags",
|
|
3390
3369
|
identifier
|
|
3391
3370
|
};
|
|
3392
|
-
const
|
|
3393
|
-
const collectionRegex = /* @__PURE__ */ new RegExp(`^(${collectionTypes.join("|")}):(.*)$`);
|
|
3371
|
+
const collectionRegex = new RegExp(`^(${["collection", "orderedCollection"].join("|")}):(.*)$`);
|
|
3394
3372
|
const match = route.name.match(collectionRegex);
|
|
3395
3373
|
if (match !== null) {
|
|
3396
3374
|
const [, type, name] = match;
|
|
@@ -3406,12 +3384,12 @@ var ContextImpl = class ContextImpl {
|
|
|
3406
3384
|
return null;
|
|
3407
3385
|
}
|
|
3408
3386
|
async getActorKeyPairs(identifier) {
|
|
3409
|
-
const logger
|
|
3387
|
+
const logger = getLogger([
|
|
3410
3388
|
"fedify",
|
|
3411
3389
|
"federation",
|
|
3412
3390
|
"actor"
|
|
3413
3391
|
]);
|
|
3414
|
-
if (this.invokedFromActorKeyPairsDispatcher != null) logger
|
|
3392
|
+
if (this.invokedFromActorKeyPairsDispatcher != null) logger.warn("Context.getActorKeyPairs({getActorKeyPairsIdentifier}) method is invoked from the actor key pairs dispatcher ({actorKeyPairsDispatcherIdentifier}); this may cause an infinite loop.", {
|
|
3415
3393
|
getActorKeyPairsIdentifier: identifier,
|
|
3416
3394
|
actorKeyPairsDispatcherIdentifier: this.invokedFromActorKeyPairsDispatcher.identifier
|
|
3417
3395
|
});
|
|
@@ -3419,7 +3397,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3419
3397
|
try {
|
|
3420
3398
|
keyPairs = await this.getKeyPairsFromIdentifier(identifier);
|
|
3421
3399
|
} catch (_) {
|
|
3422
|
-
logger
|
|
3400
|
+
logger.warn("No actor key pairs dispatcher registered.");
|
|
3423
3401
|
return [];
|
|
3424
3402
|
}
|
|
3425
3403
|
const owner = this.getActorUri(identifier);
|
|
@@ -3443,7 +3421,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3443
3421
|
return result;
|
|
3444
3422
|
}
|
|
3445
3423
|
async getKeyPairsFromIdentifier(identifier) {
|
|
3446
|
-
const logger
|
|
3424
|
+
const logger = getLogger([
|
|
3447
3425
|
"fedify",
|
|
3448
3426
|
"federation",
|
|
3449
3427
|
"actor"
|
|
@@ -3454,7 +3432,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3454
3432
|
actorUri = this.getActorUri(identifier);
|
|
3455
3433
|
} catch (error) {
|
|
3456
3434
|
if (error instanceof RouterError) {
|
|
3457
|
-
logger
|
|
3435
|
+
logger.warn(error.message);
|
|
3458
3436
|
return [];
|
|
3459
3437
|
}
|
|
3460
3438
|
throw error;
|
|
@@ -3463,7 +3441,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3463
3441
|
...this,
|
|
3464
3442
|
invokedFromActorKeyPairsDispatcher: { identifier }
|
|
3465
3443
|
}), identifier);
|
|
3466
|
-
if (keyPairs.length < 1) logger
|
|
3444
|
+
if (keyPairs.length < 1) logger.warn("No key pairs found for actor {identifier}.", { identifier });
|
|
3467
3445
|
let i = 0;
|
|
3468
3446
|
const result = [];
|
|
3469
3447
|
for (const keyPair of keyPairs) {
|
|
@@ -3502,8 +3480,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3502
3480
|
} else identifierPromise = Promise.resolve(identity.identifier);
|
|
3503
3481
|
return identifierPromise.then((identifier) => {
|
|
3504
3482
|
if (identifier == null) return this.documentLoader;
|
|
3505
|
-
|
|
3506
|
-
return keyPair.then((pair) => pair == null ? this.documentLoader : this.federation.authenticatedDocumentLoaderFactory(pair));
|
|
3483
|
+
return this.getRsaKeyPairFromIdentifier(identifier).then((pair) => pair == null ? this.documentLoader : this.federation.authenticatedDocumentLoaderFactory(pair));
|
|
3507
3484
|
});
|
|
3508
3485
|
}
|
|
3509
3486
|
return this.federation.authenticatedDocumentLoaderFactory(identity);
|
|
@@ -3545,8 +3522,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3545
3522
|
});
|
|
3546
3523
|
}
|
|
3547
3524
|
sendActivity(sender, recipients, activity, options = {}) {
|
|
3548
|
-
|
|
3549
|
-
return tracer.startActiveSpan(this.federation.outboxQueue == null || options.immediate ? "activitypub.outbox" : "activitypub.fanout", {
|
|
3525
|
+
return this.tracerProvider.getTracer(name, version).startActiveSpan(this.federation.outboxQueue == null || options.immediate ? "activitypub.outbox" : "activitypub.fanout", {
|
|
3550
3526
|
kind: this.federation.outboxQueue == null || options.immediate ? SpanKind.CLIENT : SpanKind.PRODUCER,
|
|
3551
3527
|
attributes: {
|
|
3552
3528
|
"activitypub.activity.type": getTypeId(activity).href,
|
|
@@ -3571,7 +3547,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3571
3547
|
});
|
|
3572
3548
|
}
|
|
3573
3549
|
async sendActivityInternal(sender, recipients, activity, options, span) {
|
|
3574
|
-
const logger
|
|
3550
|
+
const logger = getLogger([
|
|
3575
3551
|
"fedify",
|
|
3576
3552
|
"federation",
|
|
3577
3553
|
"outbox"
|
|
@@ -3621,7 +3597,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3621
3597
|
for (const activityTransformer of this.federation.activityTransformers) activity = activityTransformer(activity, this);
|
|
3622
3598
|
span?.setAttribute("activitypub.activity.id", activity?.id?.href ?? "");
|
|
3623
3599
|
if (activity.actorId == null) {
|
|
3624
|
-
logger
|
|
3600
|
+
logger.error("Activity {activityId} to send does not have an actor.", {
|
|
3625
3601
|
activity,
|
|
3626
3602
|
activityId: activity?.id?.href
|
|
3627
3603
|
});
|
|
@@ -3632,7 +3608,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3632
3608
|
preferSharedInbox: options.preferSharedInbox,
|
|
3633
3609
|
excludeBaseUris: options.excludeBaseUris
|
|
3634
3610
|
});
|
|
3635
|
-
logger
|
|
3611
|
+
logger.debug("Sending activity {activityId} to inboxes:\n{inboxes}", {
|
|
3636
3612
|
inboxes: globalThis.Object.keys(inboxes),
|
|
3637
3613
|
activityId: activity.id?.href,
|
|
3638
3614
|
activity
|
|
@@ -3684,16 +3660,14 @@ var ContextImpl = class ContextImpl {
|
|
|
3684
3660
|
"outbox"
|
|
3685
3661
|
]).warn("Since the followers collection dispatcher returned null for no cursor (i.e., one-shot dispatcher), the pagination is used to fetch \"followers\". However, it is recommended to implement the one-shot dispatcher for better performance.", { identifier });
|
|
3686
3662
|
while (cursor != null) {
|
|
3687
|
-
const result
|
|
3688
|
-
if (result
|
|
3689
|
-
for (const recipient of result
|
|
3690
|
-
cursor = result
|
|
3663
|
+
const result = await this.federation.followersCallbacks.dispatcher(this, identifier, cursor);
|
|
3664
|
+
if (result == null) break;
|
|
3665
|
+
for (const recipient of result.items) yield recipient;
|
|
3666
|
+
cursor = result.nextCursor ?? null;
|
|
3691
3667
|
}
|
|
3692
3668
|
}
|
|
3693
3669
|
routeActivity(recipient, activity, options = {}) {
|
|
3694
|
-
|
|
3695
|
-
const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
|
|
3696
|
-
return tracer.startActiveSpan("activitypub.inbox", {
|
|
3670
|
+
return (this.tracerProvider ?? this.tracerProvider).getTracer(name, version).startActiveSpan("activitypub.inbox", {
|
|
3697
3671
|
kind: this.federation.inboxQueue == null || options.immediate ? SpanKind.INTERNAL : SpanKind.PRODUCER,
|
|
3698
3672
|
attributes: { "activitypub.activity.type": getTypeId(activity).href }
|
|
3699
3673
|
}, async (span) => {
|
|
@@ -3721,7 +3695,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3721
3695
|
});
|
|
3722
3696
|
}
|
|
3723
3697
|
async routeActivityInternal(recipient, activity, options = {}, span) {
|
|
3724
|
-
const logger
|
|
3698
|
+
const logger = getLogger([
|
|
3725
3699
|
"fedify",
|
|
3726
3700
|
"federation",
|
|
3727
3701
|
"inbox"
|
|
@@ -3729,19 +3703,18 @@ var ContextImpl = class ContextImpl {
|
|
|
3729
3703
|
const contextLoader = options.contextLoader ?? this.contextLoader;
|
|
3730
3704
|
const json = await activity.toJsonLd({ contextLoader });
|
|
3731
3705
|
const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, this);
|
|
3732
|
-
|
|
3706
|
+
if (await verifyObject(Activity, json, {
|
|
3733
3707
|
contextLoader,
|
|
3734
3708
|
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
3735
3709
|
tracerProvider: options.tracerProvider ?? this.tracerProvider,
|
|
3736
3710
|
keyCache
|
|
3737
|
-
})
|
|
3738
|
-
|
|
3739
|
-
logger$1.debug("Object Integrity Proofs are not verified.", {
|
|
3711
|
+
}) == null) {
|
|
3712
|
+
logger.debug("Object Integrity Proofs are not verified.", {
|
|
3740
3713
|
recipient,
|
|
3741
3714
|
activity: json
|
|
3742
3715
|
});
|
|
3743
3716
|
if (activity.id == null) {
|
|
3744
|
-
logger
|
|
3717
|
+
logger.debug("Activity is missing an ID; unable to fetch.", {
|
|
3745
3718
|
recipient,
|
|
3746
3719
|
activity: json
|
|
3747
3720
|
});
|
|
@@ -3749,26 +3722,26 @@ var ContextImpl = class ContextImpl {
|
|
|
3749
3722
|
}
|
|
3750
3723
|
const fetched = await this.lookupObject(activity.id, options);
|
|
3751
3724
|
if (fetched == null) {
|
|
3752
|
-
logger
|
|
3725
|
+
logger.debug("Failed to fetch the remote activity object {activityId}.", {
|
|
3753
3726
|
recipient,
|
|
3754
3727
|
activity: json,
|
|
3755
3728
|
activityId: activity.id.href
|
|
3756
3729
|
});
|
|
3757
3730
|
return false;
|
|
3758
3731
|
} else if (!(fetched instanceof Activity)) {
|
|
3759
|
-
logger
|
|
3732
|
+
logger.debug("Fetched object is not an Activity.", {
|
|
3760
3733
|
recipient,
|
|
3761
3734
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
3762
3735
|
});
|
|
3763
3736
|
return false;
|
|
3764
3737
|
} else if (fetched.id?.href !== activity.id.href) {
|
|
3765
|
-
logger
|
|
3738
|
+
logger.debug("Fetched activity object has a different ID; failed to verify.", {
|
|
3766
3739
|
recipient,
|
|
3767
3740
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
3768
3741
|
});
|
|
3769
3742
|
return false;
|
|
3770
3743
|
} else if (fetched.actorIds.length < 1) {
|
|
3771
|
-
logger
|
|
3744
|
+
logger.debug("Fetched activity object is missing an actor; unable to verify.", {
|
|
3772
3745
|
recipient,
|
|
3773
3746
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
3774
3747
|
});
|
|
@@ -3776,15 +3749,15 @@ var ContextImpl = class ContextImpl {
|
|
|
3776
3749
|
}
|
|
3777
3750
|
const activityId = fetched.id;
|
|
3778
3751
|
if (!fetched.actorIds.every((actor) => actor.origin === activityId.origin)) {
|
|
3779
|
-
logger
|
|
3752
|
+
logger.debug("Fetched activity object has actors from different origins; unable to verify.", {
|
|
3780
3753
|
recipient,
|
|
3781
3754
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
3782
3755
|
});
|
|
3783
3756
|
return false;
|
|
3784
3757
|
}
|
|
3785
|
-
logger
|
|
3758
|
+
logger.debug("Successfully fetched the remote activity object {activityId}; ignore the original activity and use the fetched one, which is trustworthy.");
|
|
3786
3759
|
activity = fetched;
|
|
3787
|
-
} else logger
|
|
3760
|
+
} else logger.debug("Object Integrity Proofs are verified.", {
|
|
3788
3761
|
recipient,
|
|
3789
3762
|
activity: json
|
|
3790
3763
|
});
|
|
@@ -3910,8 +3883,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3910
3883
|
});
|
|
3911
3884
|
}
|
|
3912
3885
|
forwardActivity(forwarder, recipients, options) {
|
|
3913
|
-
|
|
3914
|
-
return tracer.startActiveSpan("activitypub.outbox", {
|
|
3886
|
+
return this.tracerProvider.getTracer(name, version).startActiveSpan("activitypub.outbox", {
|
|
3915
3887
|
kind: this.federation.outboxQueue == null || options?.immediate ? SpanKind.CLIENT : SpanKind.PRODUCER,
|
|
3916
3888
|
attributes: { "activitypub.activity.type": this.activityType }
|
|
3917
3889
|
}, async (span) => {
|
|
@@ -3930,7 +3902,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3930
3902
|
});
|
|
3931
3903
|
}
|
|
3932
3904
|
async forwardActivityInternal(forwarder, recipients, options) {
|
|
3933
|
-
const logger
|
|
3905
|
+
const logger = getLogger([
|
|
3934
3906
|
"fedify",
|
|
3935
3907
|
"federation",
|
|
3936
3908
|
"inbox"
|
|
@@ -3957,14 +3929,13 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3957
3929
|
if (!hasSignature(this.activity)) {
|
|
3958
3930
|
let hasProof;
|
|
3959
3931
|
try {
|
|
3960
|
-
|
|
3961
|
-
hasProof = await activity.getProof() != null;
|
|
3932
|
+
hasProof = await (await Activity.fromJsonLd(this.activity, this)).getProof() != null;
|
|
3962
3933
|
} catch {
|
|
3963
3934
|
hasProof = false;
|
|
3964
3935
|
}
|
|
3965
3936
|
if (!hasProof) {
|
|
3966
3937
|
if (options?.skipIfUnsigned) return;
|
|
3967
|
-
logger
|
|
3938
|
+
logger.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.");
|
|
3968
3939
|
}
|
|
3969
3940
|
}
|
|
3970
3941
|
if (recipients === "followers") {
|
|
@@ -3978,14 +3949,14 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3978
3949
|
preferSharedInbox: options?.preferSharedInbox,
|
|
3979
3950
|
excludeBaseUris: options?.excludeBaseUris
|
|
3980
3951
|
});
|
|
3981
|
-
logger
|
|
3952
|
+
logger.debug("Forwarding activity {activityId} to inboxes:\n{inboxes}", {
|
|
3982
3953
|
inboxes: globalThis.Object.keys(inboxes),
|
|
3983
3954
|
activityId: this.activityId,
|
|
3984
3955
|
activity: this.activity
|
|
3985
3956
|
});
|
|
3986
3957
|
if (options?.immediate || this.federation.outboxQueue == null) {
|
|
3987
|
-
if (options?.immediate) logger
|
|
3988
|
-
else logger
|
|
3958
|
+
if (options?.immediate) logger.debug("Forwarding activity immediately without queue since immediate option is set.");
|
|
3959
|
+
else logger.debug("Forwarding activity immediately without queue since queue is not set.");
|
|
3989
3960
|
const promises = [];
|
|
3990
3961
|
for (const inbox in inboxes) promises.push(sendActivity({
|
|
3991
3962
|
keys,
|
|
@@ -4000,7 +3971,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
4000
3971
|
await Promise.all(promises);
|
|
4001
3972
|
return;
|
|
4002
3973
|
}
|
|
4003
|
-
logger
|
|
3974
|
+
logger.debug("Enqueuing activity {activityId} to forward later.", {
|
|
4004
3975
|
activityId: this.activityId,
|
|
4005
3976
|
activity: this.activity
|
|
4006
3977
|
});
|
|
@@ -4042,10 +4013,9 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
4042
4013
|
const { outboxQueue } = this.federation;
|
|
4043
4014
|
if (outboxQueue.enqueueMany == null) {
|
|
4044
4015
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
4045
|
-
const
|
|
4046
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
4016
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
4047
4017
|
if (errors.length > 0) {
|
|
4048
|
-
logger
|
|
4018
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
|
|
4049
4019
|
activityId: this.activityId,
|
|
4050
4020
|
errors
|
|
4051
4021
|
});
|
|
@@ -4054,10 +4024,9 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
4054
4024
|
}
|
|
4055
4025
|
} else if (orderingKey != null) {
|
|
4056
4026
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
4057
|
-
const
|
|
4058
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
4027
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
4059
4028
|
if (errors.length > 0) {
|
|
4060
|
-
logger
|
|
4029
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
|
|
4061
4030
|
activityId: this.activityId,
|
|
4062
4031
|
errors
|
|
4063
4032
|
});
|
|
@@ -4067,7 +4036,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
4067
4036
|
} else try {
|
|
4068
4037
|
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
4069
4038
|
} catch (error) {
|
|
4070
|
-
logger
|
|
4039
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
|
|
4071
4040
|
activityId: this.activityId,
|
|
4072
4041
|
error
|
|
4073
4042
|
});
|
|
@@ -4122,10 +4091,7 @@ function unauthorized(_request) {
|
|
|
4122
4091
|
function getRequestId(request) {
|
|
4123
4092
|
const traceId = request.headers.get("X-Request-Id") || request.headers.get("X-Correlation-Id") || request.headers.get("Traceparent")?.split("-")[1];
|
|
4124
4093
|
if (traceId != null) return traceId;
|
|
4125
|
-
|
|
4126
|
-
const random = Math.random().toString(36).slice(2, 8);
|
|
4127
|
-
return `req_${timestamp}${random}`;
|
|
4094
|
+
return `req_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
|
4128
4095
|
}
|
|
4129
|
-
|
|
4130
4096
|
//#endregion
|
|
4131
|
-
export {
|
|
4097
|
+
export { createExponentialBackoffPolicy as a, buildCollectionSynchronizationHeader as c, Router$1 as d, RouterError as f, SendActivityError as i, digest as l, middleware_exports as n, respondWithObject as o, handleWebFinger as r, respondWithObjectIfAcceptable as s, createFederation as t, createFederationBuilder as u };
|