@fedify/fedify 2.4.0-dev.2071 → 2.4.0-dev.2073
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/{builder-DVQ0yhKJ.mjs → builder-CVHpPAjK.mjs} +2 -2
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{compound-proof-KmXDfWFp.mjs → compound-proof-B5Skp-vE.mjs} +1 -1
- package/dist/{context-DsB9kF6q.d.ts → context-BSywYspi.d.ts} +109 -1
- package/dist/{context-DijrgHDe.d.cts → context-CZjZYXFC.d.cts} +109 -1
- package/dist/{context-DG5QeQ8W.mjs → context-DlZhxdFT.mjs} +2 -1
- package/dist/{deno-B-NtYZVW.mjs → deno-LYTbBhYV.mjs} +1 -1
- package/dist/{docloader-C6yOVoaF.mjs → docloader-C0SWQylk.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/compound-fanout.test.mjs +3 -3
- package/dist/federation/handler-compound-proof.test.mjs +4 -4
- package/dist/federation/handler.test.mjs +6 -6
- package/dist/federation/hashlink-media.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +8 -8
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +3 -3
- package/dist/federation/mod.d.ts +3 -3
- package/dist/federation/mod.js +1 -1
- package/dist/federation/outgoing-proof.test.mjs +5 -5
- package/dist/federation/portable-gateway-keys.test.mjs +4 -4
- package/dist/federation/portable-inbox.test.d.mts +2 -0
- package/dist/federation/portable-inbox.test.mjs +546 -0
- package/dist/federation/portable.test.mjs +3 -3
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/tasks/enqueue.test.mjs +2 -2
- package/dist/federation/tasks/tasks.test.mjs +3 -3
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +2 -2
- package/dist/{federation-CUiHc7dP.cjs → federation-B1aeTKKN.cjs} +468 -88
- package/dist/{http-DKWi8RjI.mjs → http-C7qHlv-b.mjs} +4 -4
- package/dist/{http-CuLWIJdf.cjs → http-DGk8XI38.cjs} +1 -1
- package/dist/{http-BoWBwC0g.js → http-vfTpzGEq.js} +1 -1
- package/dist/{key-lfcx_NaE.mjs → key-BYXnTGro.mjs} +2 -2
- package/dist/{kv-cache-BdnmnAVc.js → kv-cache-DCJuwdnB.js} +1 -1
- package/dist/{kv-cache-d8EjO29d.mjs → kv-cache-DEH5jyND.mjs} +1 -1
- package/dist/{kv-cache-DE8kSNQU.cjs → kv-cache-DvqkKNIj.cjs} +1 -1
- package/dist/{ld-jyjdrWjG.mjs → ld-DT3e2hOv.mjs} +3 -3
- package/dist/{metrics-B5Rei-HC.mjs → metrics-DvlvYpq_.mjs} +1 -1
- package/dist/{middleware-CdVnCDXD.mjs → middleware-BJcez_E3.mjs} +1 -1
- package/dist/{middleware-CAObohey.js → middleware-CCbyUF4c.js} +417 -38
- package/dist/{middleware-CPx4ZWwt.mjs → middleware-CpyCNOW_.mjs} +423 -48
- package/dist/{mod-DMkflQdF.d.ts → mod-B2h2KY0q.d.ts} +1 -1
- package/dist/{mod-DTAaBwiY.d.cts → mod-JzkaEXsi.d.cts} +1 -1
- package/dist/mod.cjs +5 -5
- package/dist/mod.d.cts +4 -4
- package/dist/mod.d.ts +4 -4
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/handler.test.mjs +2 -2
- package/dist/{owner-ByqNQVaa.mjs → owner-CDsVeZI7.mjs} +3 -3
- package/dist/{owner-BXufwAzm.cjs → owner-DCIH7Iq0.cjs} +1 -1
- package/dist/{owner-1TFakcTF.js → owner-DfGz0cXm.js} +1 -1
- package/dist/{portable-key-Cw_ow5vn.mjs → portable-key-DCyKGCQd.mjs} +2 -2
- package/dist/{proof-B6gwdhN5.mjs → proof-CxsVG6vM.mjs} +4 -4
- package/dist/{send-DsK7xevO.mjs → send-BZJ7NsVV.mjs} +8 -4
- package/dist/sig/compound-proof-discovery.test.mjs +1 -1
- package/dist/sig/compound-proof-producer.test.mjs +1 -1
- package/dist/sig/compound-proof-verification.test.mjs +2 -2
- package/dist/sig/compound-proof.test.mjs +2 -2
- package/dist/sig/http.test.mjs +2 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +3 -3
- package/dist/sig/mod.js +3 -3
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/portable-collection.test.mjs +2 -2
- package/dist/sig/portable-key.test.mjs +3 -3
- package/dist/sig/proof.test.mjs +3 -3
- package/dist/{sig-TTn9wYrE.cjs → sig-C6TnADze.cjs} +2 -2
- package/dist/{sig-BR_Z6mpY.js → sig-Cs9_ecdh.js} +2 -2
- package/dist/{temporal-Bw5jtrBY.mjs → temporal-CLzSfIOV.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/testing/mod.d.mts +108 -0
- package/dist/testing/mod.mjs +2 -2
- package/dist/{testing-By1YYsIK.mjs → testing-CO_cEvQc.mjs} +1 -1
- package/dist/utils/docloader.test.mjs +2 -2
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +6 -6
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-
|
|
4
|
+
import { n as version, t as name } from "./deno-LYTbBhYV.mjs";
|
|
5
|
+
import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-DvlvYpq_.mjs";
|
|
6
6
|
import { t as formatAcceptSignature } from "./accept-CPVqki78.mjs";
|
|
7
|
-
import { d as hasPortableActor, f as isCompatibleKeyId, m as isPortableUri, o as importJwk, s as validateCryptoKey, t as exportJwk, u as getGatewayKeyBase } from "./key-
|
|
7
|
+
import { d as hasPortableActor, f as isCompatibleKeyId, m as isPortableUri, o as importJwk, s as validateCryptoKey, t as exportJwk, u as getGatewayKeyBase } from "./key-BYXnTGro.mjs";
|
|
8
8
|
import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-4IJqPYos.mjs";
|
|
9
|
-
import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-
|
|
10
|
-
import { a as verifyObject, n as hasProofLike, o as verifyPortableObjectProof, r as signObject } from "./proof-
|
|
11
|
-
import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-
|
|
12
|
-
import { t as getAuthenticatedDocumentLoader } from "./docloader-
|
|
13
|
-
import { n as kvCache } from "./kv-cache-
|
|
9
|
+
import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-DT3e2hOv.mjs";
|
|
10
|
+
import { a as verifyObject, n as hasProofLike, o as verifyPortableObjectProof, r as signObject } from "./proof-CxsVG6vM.mjs";
|
|
11
|
+
import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-C7qHlv-b.mjs";
|
|
12
|
+
import { t as getAuthenticatedDocumentLoader } from "./docloader-C0SWQylk.mjs";
|
|
13
|
+
import { n as kvCache } from "./kv-cache-DEH5jyND.mjs";
|
|
14
14
|
import { d as readBoundedText, l as BodyTooLargeError, t as getNodeInfo, u as MAX_BODY_SIZE } from "./client-DpnpgjyX.mjs";
|
|
15
15
|
import { t as nodeInfoToJson } from "./types-DE_LV1JB.mjs";
|
|
16
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-
|
|
17
|
-
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-
|
|
18
|
-
import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-
|
|
16
|
+
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-CDsVeZI7.mjs";
|
|
17
|
+
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-BZJ7NsVV.mjs";
|
|
18
|
+
import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-CVHpPAjK.mjs";
|
|
19
19
|
import { t as CircuitBreaker } from "./circuit-breaker-C5NqoLBJ.mjs";
|
|
20
20
|
import { t as buildCollectionSynchronizationHeader } from "./collection-CnnP1UAv.mjs";
|
|
21
|
-
import { a as verifyCompoundPortableObjectProofs, i as inspectCompoundPortableObjectApplicability, r as findUnsupportedCompoundProofShape, t as containsCompoundPortableObject } from "./compound-proof-
|
|
21
|
+
import { a as verifyCompoundPortableObjectProofs, i as inspectCompoundPortableObjectApplicability, r as findUnsupportedCompoundProofShape, t as containsCompoundPortableObject } from "./compound-proof-B5Skp-vE.mjs";
|
|
22
22
|
import { t as KvKeyCache } from "./keycache-BUDHB5rY.mjs";
|
|
23
23
|
import { t as acceptsJsonLd } from "./negotiation-CCocWT_N.mjs";
|
|
24
|
-
import { t as hasMalformedKnownTemporalLiteral } from "./temporal-
|
|
24
|
+
import { t as hasMalformedKnownTemporalLiteral } from "./temporal-CLzSfIOV.mjs";
|
|
25
25
|
import { t as createExponentialBackoffPolicy } from "./retry-zX5xw5e0.mjs";
|
|
26
26
|
import { t as TaskCodec } from "./codec-C6rTrpIp.mjs";
|
|
27
27
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
@@ -858,13 +858,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
|
|
|
858
858
|
* @param parameters The parameters for handling the collection.
|
|
859
859
|
* @returns A promise that resolves to an HTTP response.
|
|
860
860
|
*/
|
|
861
|
-
async function handleCollection(request, { name: name$
|
|
862
|
-
const spanName = name$
|
|
861
|
+
async function handleCollection(request, { name: name$2, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
|
|
862
|
+
const spanName = name$2.trim().replace(/\s+/g, "_");
|
|
863
863
|
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
864
864
|
const tracer = tracerProvider.getTracer(name, version);
|
|
865
865
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
866
866
|
const metricBase = {
|
|
867
|
-
kind: getCollectionMetricKind(name$
|
|
867
|
+
kind: getCollectionMetricKind(name$2),
|
|
868
868
|
page: cursor != null,
|
|
869
869
|
dispatcher: "built_in"
|
|
870
870
|
};
|
|
@@ -905,7 +905,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
905
905
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
906
906
|
return await onNotFound(request);
|
|
907
907
|
}
|
|
908
|
-
const items = filterCollectionItems(page.items, name$
|
|
908
|
+
const items = filterCollectionItems(page.items, name$2, filterPredicate);
|
|
909
909
|
itemCount = items.length;
|
|
910
910
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
911
911
|
return items;
|
|
@@ -945,7 +945,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
945
945
|
} else {
|
|
946
946
|
const uri = new URL(baseUri);
|
|
947
947
|
uri.searchParams.set("cursor", cursor);
|
|
948
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$
|
|
948
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$2}`, {
|
|
949
949
|
kind: SpanKind.SERVER,
|
|
950
950
|
attributes: {
|
|
951
951
|
"activitypub.collection.id": uri.href,
|
|
@@ -961,7 +961,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
961
961
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
962
962
|
return await onNotFound(request);
|
|
963
963
|
}
|
|
964
|
-
const items = filterCollectionItems(page.items, name$
|
|
964
|
+
const items = filterCollectionItems(page.items, name$2, filterPredicate);
|
|
965
965
|
itemCount = items.length;
|
|
966
966
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
967
967
|
return {
|
|
@@ -1467,7 +1467,7 @@ async function handleInbox(request, options) {
|
|
|
1467
1467
|
* @returns A promise that resolves to an HTTP response.
|
|
1468
1468
|
*/
|
|
1469
1469
|
async function handleInboxInternal(request, parameters, span) {
|
|
1470
|
-
const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, publicKeyTtl, queue, actorDispatcher, inboxListeners, inboxErrorHandler, unverifiedActivityHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, inboxChallengePolicy, meterProvider, tracerProvider } = parameters;
|
|
1470
|
+
const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, publicKeyTtl, queue, actorDispatcher, inboxListeners, inboxErrorHandler, unverifiedActivityHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, inboxChallengePolicy, meterProvider, tracerProvider, portableInbox } = parameters;
|
|
1471
1471
|
const logger = getLogger([
|
|
1472
1472
|
"fedify",
|
|
1473
1473
|
"federation",
|
|
@@ -1480,7 +1480,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1480
1480
|
message: "Actor dispatcher is not set."
|
|
1481
1481
|
});
|
|
1482
1482
|
return await onNotFound(request);
|
|
1483
|
-
} else if (recipient != null) {
|
|
1483
|
+
} else if (recipient != null && portableInbox == null) {
|
|
1484
1484
|
const actor = await actorDispatcher(ctx, recipient);
|
|
1485
1485
|
if (actor == null || actor instanceof Tombstone) {
|
|
1486
1486
|
logger.error("Actor {recipient} not found.", { recipient });
|
|
@@ -1942,6 +1942,19 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1942
1942
|
tracerProvider,
|
|
1943
1943
|
idempotencyStrategy: parameters.idempotencyStrategy
|
|
1944
1944
|
});
|
|
1945
|
+
if (portableInbox != null && activity.id != null && PORTABLE_INBOX_FORWARDABLE_RESULTS.has(routeResult)) if (skipSignatureVerification || !(ldSigVerified || proofVerified)) logger.debug("Not forwarding activity {activityId} to the other gateways of the portable inbox {inbox}, as it is not authenticated by its own proof.", {
|
|
1946
|
+
activityId: activity.id.href,
|
|
1947
|
+
inbox: portableInbox.recipient.canonicalInboxId
|
|
1948
|
+
});
|
|
1949
|
+
else try {
|
|
1950
|
+
await portableInbox.forward(json, activity.id, getTypeId(activity).href);
|
|
1951
|
+
} catch (error) {
|
|
1952
|
+
logger.error("Failed to forward activity {activityId} to the other gateways of the portable inbox {inbox}:\n{error}", {
|
|
1953
|
+
activityId: activity.id.href,
|
|
1954
|
+
inbox: portableInbox.recipient.canonicalInboxId,
|
|
1955
|
+
error
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1945
1958
|
if (routeResult === "alreadyProcessed") return new Response(`Activity <${activity.id}> has already been processed.`, {
|
|
1946
1959
|
status: 202,
|
|
1947
1960
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
@@ -1967,6 +1980,12 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1967
1980
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1968
1981
|
});
|
|
1969
1982
|
}
|
|
1983
|
+
const PORTABLE_INBOX_FORWARDABLE_RESULTS = /* @__PURE__ */ new Set([
|
|
1984
|
+
"success",
|
|
1985
|
+
"enqueued",
|
|
1986
|
+
"alreadyProcessed",
|
|
1987
|
+
"unsupportedActivity"
|
|
1988
|
+
]);
|
|
1970
1989
|
/**
|
|
1971
1990
|
* Handles a custom collection request.
|
|
1972
1991
|
* @template TItem The type of items in the collection.
|
|
@@ -2089,8 +2108,8 @@ var CustomCollectionHandler = class {
|
|
|
2089
2108
|
* @param CollectionPage The CollectionPage constructor.
|
|
2090
2109
|
* @param filterPredicate Optional filter predicate for items.
|
|
2091
2110
|
*/
|
|
2092
|
-
constructor(name$
|
|
2093
|
-
this.name = name$
|
|
2111
|
+
constructor(name$1, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate) {
|
|
2112
|
+
this.name = name$1;
|
|
2094
2113
|
this.values = values;
|
|
2095
2114
|
this.context = context;
|
|
2096
2115
|
this.callbacks = callbacks;
|
|
@@ -2584,6 +2603,251 @@ function isPortableGatewayKey(key) {
|
|
|
2584
2603
|
return key?.id != null && isCompatibleKeyId(key.id) && key.ownerId != null && isPortableUri(key.ownerId);
|
|
2585
2604
|
}
|
|
2586
2605
|
//#endregion
|
|
2606
|
+
//#region src/federation/portable-inbox.ts
|
|
2607
|
+
const MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
2608
|
+
/**
|
|
2609
|
+
* Fills in the defaults of {@link PortableInboxForwardingOptions} and
|
|
2610
|
+
* validates them.
|
|
2611
|
+
* @param options The options.
|
|
2612
|
+
* @returns The resolved options.
|
|
2613
|
+
* @throws {RangeError} If `maxTargets` is not a non-negative integer, if `ttl`
|
|
2614
|
+
* is not positive, if `deadline` is negative or longer
|
|
2615
|
+
* than 2,147,483,647 milliseconds (about 24.8 days), or
|
|
2616
|
+
* if either duration has calendar units, i.e., weeks,
|
|
2617
|
+
* months, or years, whose length depends on the date.
|
|
2618
|
+
*/
|
|
2619
|
+
function resolvePortableInboxForwardingOptions(options = {}) {
|
|
2620
|
+
const maxTargets = options.maxTargets ?? 10;
|
|
2621
|
+
if (!Number.isInteger(maxTargets) || maxTargets < 0) throw new RangeError("portableInboxForwarding.maxTargets must be a non-negative integer.");
|
|
2622
|
+
const ttl = Temporal.Duration.from(options.ttl ?? { days: 30 });
|
|
2623
|
+
if (ttl.total("millisecond") <= 0) throw new RangeError("portableInboxForwarding.ttl must be positive.");
|
|
2624
|
+
const deadline = Temporal.Duration.from(options.deadline ?? { seconds: 10 });
|
|
2625
|
+
const deadlineMs = deadline.total("millisecond");
|
|
2626
|
+
if (deadlineMs < 0 || deadlineMs > MAX_TIMEOUT_MS) throw new RangeError(`portableInboxForwarding.deadline must be between 0 and ${MAX_TIMEOUT_MS} milliseconds.`);
|
|
2627
|
+
return {
|
|
2628
|
+
maxTargets,
|
|
2629
|
+
ttl,
|
|
2630
|
+
deadline
|
|
2631
|
+
};
|
|
2632
|
+
}
|
|
2633
|
+
/**
|
|
2634
|
+
* Decides whether this server accepts a delivery to a portable inbox on behalf
|
|
2635
|
+
* of the given actor, which the actor dispatcher returned for the identifier
|
|
2636
|
+
* in the requested inbox path.
|
|
2637
|
+
*
|
|
2638
|
+
* The actor document comes from the application, so it is trusted as is and
|
|
2639
|
+
* its proof is not verified here.
|
|
2640
|
+
* @param actor The actor the actor dispatcher returned.
|
|
2641
|
+
* @param options The requested DID, the canonical form of the requested inbox
|
|
2642
|
+
* ID, and the origin of this server.
|
|
2643
|
+
* @returns The resolution.
|
|
2644
|
+
*/
|
|
2645
|
+
function resolvePortableInboxRecipient(actor, { authority, canonicalInboxId, localOrigin }) {
|
|
2646
|
+
if (actor == null) return {
|
|
2647
|
+
status: "rejected",
|
|
2648
|
+
reason: "notFound"
|
|
2649
|
+
};
|
|
2650
|
+
const id = actor.id;
|
|
2651
|
+
if (id == null || id.protocol !== "ap:" && id.protocol !== "ap+ef61:") return {
|
|
2652
|
+
status: "rejected",
|
|
2653
|
+
reason: "notPortable"
|
|
2654
|
+
};
|
|
2655
|
+
if (!isSameAuthority(id, authority)) return {
|
|
2656
|
+
status: "rejected",
|
|
2657
|
+
reason: "authorityMismatch"
|
|
2658
|
+
};
|
|
2659
|
+
const inboxId = actor.inboxId;
|
|
2660
|
+
if (inboxId == null || canonicalize(inboxId) !== canonicalInboxId) return {
|
|
2661
|
+
status: "rejected",
|
|
2662
|
+
reason: "inboxMismatch"
|
|
2663
|
+
};
|
|
2664
|
+
const gateways = actor.gateways;
|
|
2665
|
+
if (!gateways.some((g) => isGatewayUrl(g) && g.origin === localOrigin)) return {
|
|
2666
|
+
status: "rejected",
|
|
2667
|
+
reason: "notGateway"
|
|
2668
|
+
};
|
|
2669
|
+
return {
|
|
2670
|
+
status: "accepted",
|
|
2671
|
+
recipient: {
|
|
2672
|
+
inboxId,
|
|
2673
|
+
canonicalInboxId,
|
|
2674
|
+
gateways
|
|
2675
|
+
}
|
|
2676
|
+
};
|
|
2677
|
+
}
|
|
2678
|
+
function isSameAuthority(id, authority) {
|
|
2679
|
+
try {
|
|
2680
|
+
return getFe34Origin(id) === authority;
|
|
2681
|
+
} catch (error) {
|
|
2682
|
+
if (error instanceof TypeError) return false;
|
|
2683
|
+
throw error;
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
function canonicalize(iri) {
|
|
2687
|
+
try {
|
|
2688
|
+
return canonicalizePortableUri(typeof iri === "string" ? iri : formatIri(iri));
|
|
2689
|
+
} catch (error) {
|
|
2690
|
+
if (error instanceof TypeError) return null;
|
|
2691
|
+
throw error;
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
/**
|
|
2695
|
+
* Forwards an activity received in a portable inbox to the inboxes of the same
|
|
2696
|
+
* portable actor on its other gateways, as FEP-ef61 recommends.
|
|
2697
|
+
*
|
|
2698
|
+
* FEP-ef61 forbids forwarding an activity from an inbox more than once, so
|
|
2699
|
+
* each target gateway is claimed with an atomic compare-and-swap before the
|
|
2700
|
+
* activity is handed off, and a claim is never released, even if the hand-off
|
|
2701
|
+
* fails, since a failed hand-off does not prove that nothing was delivered.
|
|
2702
|
+
* Forwarding is therefore best effort. Without {@link KvStore.cas}, nothing is
|
|
2703
|
+
* forwarded.
|
|
2704
|
+
*
|
|
2705
|
+
* Forwarded requests are not signed with HTTP Signatures; the receiving
|
|
2706
|
+
* gateways authenticate the activity by its own proof.
|
|
2707
|
+
* @param parameters The parameters.
|
|
2708
|
+
* @returns The target inbox URLs that the activity was handed off to.
|
|
2709
|
+
*/
|
|
2710
|
+
async function forwardPortableInboxActivity(parameters) {
|
|
2711
|
+
const logger = getLogger([
|
|
2712
|
+
"fedify",
|
|
2713
|
+
"federation",
|
|
2714
|
+
"inbox"
|
|
2715
|
+
]);
|
|
2716
|
+
const { recipient, activityId, excludedOrigins, kv, kvPrefix, outboxQueue } = parameters;
|
|
2717
|
+
const { maxTargets, ttl } = parameters.options ?? resolvePortableInboxForwardingOptions();
|
|
2718
|
+
if (kv.cas == null || maxTargets < 1) return [];
|
|
2719
|
+
const canonicalActivityId = canonicalize(activityId) ?? activityId.href;
|
|
2720
|
+
const targets = getForwardingTargets(recipient, excludedOrigins);
|
|
2721
|
+
if (targets.length > maxTargets) {
|
|
2722
|
+
logger.warn("The portable actor that owns the inbox {inbox} has more than {max} other gateways; the activity {activityId} is forwarded only to the first {max} of them.", {
|
|
2723
|
+
inbox: recipient.canonicalInboxId,
|
|
2724
|
+
activityId: activityId.href,
|
|
2725
|
+
max: maxTargets
|
|
2726
|
+
});
|
|
2727
|
+
targets.length = maxTargets;
|
|
2728
|
+
}
|
|
2729
|
+
const claimed = [];
|
|
2730
|
+
for (const { gateway, inbox } of targets) {
|
|
2731
|
+
const key = [
|
|
2732
|
+
...kvPrefix,
|
|
2733
|
+
recipient.canonicalInboxId,
|
|
2734
|
+
canonicalActivityId,
|
|
2735
|
+
gateway
|
|
2736
|
+
];
|
|
2737
|
+
if (await kv.cas(key, void 0, true, { ttl })) claimed.push(inbox);
|
|
2738
|
+
}
|
|
2739
|
+
if (claimed.length < 1) return [];
|
|
2740
|
+
logger.debug("Forwarding activity {activityId} from the portable inbox {inbox} to other gateways:\n{targets}", {
|
|
2741
|
+
activityId: activityId.href,
|
|
2742
|
+
inbox: recipient.canonicalInboxId,
|
|
2743
|
+
targets: claimed.map((t) => t.href)
|
|
2744
|
+
});
|
|
2745
|
+
if (outboxQueue == null) await forwardImmediately(parameters, claimed);
|
|
2746
|
+
else await enqueueForwarding(parameters, outboxQueue, claimed);
|
|
2747
|
+
return claimed;
|
|
2748
|
+
}
|
|
2749
|
+
function getForwardingTargets(recipient, excludedOrigins) {
|
|
2750
|
+
const logger = getLogger([
|
|
2751
|
+
"fedify",
|
|
2752
|
+
"federation",
|
|
2753
|
+
"inbox"
|
|
2754
|
+
]);
|
|
2755
|
+
const seen = new Set(excludedOrigins);
|
|
2756
|
+
const targets = [];
|
|
2757
|
+
for (const gateway of recipient.gateways) {
|
|
2758
|
+
if (!isGatewayUrl(gateway) || seen.has(gateway.origin)) continue;
|
|
2759
|
+
seen.add(gateway.origin);
|
|
2760
|
+
let inbox;
|
|
2761
|
+
try {
|
|
2762
|
+
inbox = toCompatibleEf61Id(recipient.inboxId, gateway.origin);
|
|
2763
|
+
} catch (error) {
|
|
2764
|
+
if (!(error instanceof TypeError)) throw error;
|
|
2765
|
+
logger.warn("Cannot forward to the gateway {gateway}, as the portable inbox {inbox} cannot be represented as its compatible identifier.", {
|
|
2766
|
+
gateway: gateway.origin,
|
|
2767
|
+
inbox: recipient.canonicalInboxId
|
|
2768
|
+
});
|
|
2769
|
+
continue;
|
|
2770
|
+
}
|
|
2771
|
+
targets.push({
|
|
2772
|
+
gateway: gateway.origin,
|
|
2773
|
+
inbox
|
|
2774
|
+
});
|
|
2775
|
+
}
|
|
2776
|
+
return targets;
|
|
2777
|
+
}
|
|
2778
|
+
async function forwardImmediately({ activity, activityId, activityType, allowPrivateAddress, options, meterProvider, tracerProvider }, inboxes) {
|
|
2779
|
+
const logger = getLogger([
|
|
2780
|
+
"fedify",
|
|
2781
|
+
"federation",
|
|
2782
|
+
"inbox"
|
|
2783
|
+
]);
|
|
2784
|
+
const deadline = (options ?? resolvePortableInboxForwardingOptions()).deadline.total("millisecond");
|
|
2785
|
+
const sends = inboxes.map((inbox) => sendActivity({
|
|
2786
|
+
activity,
|
|
2787
|
+
activityId: activityId.href,
|
|
2788
|
+
activityType,
|
|
2789
|
+
keys: [],
|
|
2790
|
+
inbox,
|
|
2791
|
+
allowPrivateAddress,
|
|
2792
|
+
meterProvider,
|
|
2793
|
+
tracerProvider
|
|
2794
|
+
}).catch((error) => {
|
|
2795
|
+
logger.error("Failed to forward activity {activityId} to {inbox}; it will not be forwarded to the inbox again:\n{error}", {
|
|
2796
|
+
activityId: activityId.href,
|
|
2797
|
+
inbox: inbox.href,
|
|
2798
|
+
error
|
|
2799
|
+
});
|
|
2800
|
+
}));
|
|
2801
|
+
let timer;
|
|
2802
|
+
const timedOut = await Promise.race([Promise.all(sends).then(() => false), new Promise((resolve) => {
|
|
2803
|
+
timer = setTimeout(() => resolve(true), deadline);
|
|
2804
|
+
})]);
|
|
2805
|
+
clearTimeout(timer);
|
|
2806
|
+
if (timedOut) logger.warn("Forwarding activity {activityId} to other gateways did not finish in {deadline} ms; responding to the delivery without waiting for it.", {
|
|
2807
|
+
activityId: activityId.href,
|
|
2808
|
+
deadline
|
|
2809
|
+
});
|
|
2810
|
+
}
|
|
2811
|
+
async function enqueueForwarding({ activity, activityId, activityType, baseUrl, startQueue, meterProvider }, outboxQueue, inboxes) {
|
|
2812
|
+
const logger = getLogger([
|
|
2813
|
+
"fedify",
|
|
2814
|
+
"federation",
|
|
2815
|
+
"inbox"
|
|
2816
|
+
]);
|
|
2817
|
+
startQueue?.();
|
|
2818
|
+
const started = (/* @__PURE__ */ new Date()).toISOString();
|
|
2819
|
+
const traceContext = {};
|
|
2820
|
+
propagation.inject(context.active(), traceContext);
|
|
2821
|
+
await Promise.all(inboxes.map(async (inbox) => {
|
|
2822
|
+
const message = {
|
|
2823
|
+
type: "outbox",
|
|
2824
|
+
id: crypto.randomUUID(),
|
|
2825
|
+
baseUrl,
|
|
2826
|
+
keys: [],
|
|
2827
|
+
activity,
|
|
2828
|
+
activityId: activityId.href,
|
|
2829
|
+
activityType,
|
|
2830
|
+
inbox: inbox.href,
|
|
2831
|
+
sharedInbox: false,
|
|
2832
|
+
started,
|
|
2833
|
+
attempt: 0,
|
|
2834
|
+
headers: {},
|
|
2835
|
+
traceContext
|
|
2836
|
+
};
|
|
2837
|
+
try {
|
|
2838
|
+
await outboxQueue.enqueue(message);
|
|
2839
|
+
} catch (error) {
|
|
2840
|
+
logger.error("Failed to enqueue activity {activityId} to forward to {inbox}; it will not be forwarded to the inbox again:\n{error}", {
|
|
2841
|
+
activityId: activityId.href,
|
|
2842
|
+
inbox: inbox.href,
|
|
2843
|
+
error
|
|
2844
|
+
});
|
|
2845
|
+
return;
|
|
2846
|
+
}
|
|
2847
|
+
recordOutboxEnqueue(meterProvider, outboxQueue, message);
|
|
2848
|
+
}));
|
|
2849
|
+
}
|
|
2850
|
+
//#endregion
|
|
2587
2851
|
//#region src/federation/outgoing-proof.ts
|
|
2588
2852
|
function isPortableUrl(url) {
|
|
2589
2853
|
return url.protocol === "ap:" || url.protocol === "ap+ef61:";
|
|
@@ -3304,6 +3568,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3304
3568
|
kvPrefixes;
|
|
3305
3569
|
publicKeyTtl;
|
|
3306
3570
|
httpMessageSignaturesSpecTtl;
|
|
3571
|
+
portableInboxForwarding;
|
|
3307
3572
|
inboxQueue;
|
|
3308
3573
|
outboxQueue;
|
|
3309
3574
|
fanoutQueue;
|
|
@@ -3336,6 +3601,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3336
3601
|
benchmarkMetricReader;
|
|
3337
3602
|
benchmarkTriggerOptions;
|
|
3338
3603
|
#mediaUploaderNoAuthWarned = false;
|
|
3604
|
+
#portableInboxForwardingWarned = false;
|
|
3339
3605
|
#queueDepthGaugeSourceId = `fedify-${(++nextQueueDepthGaugeSourceId).toString(36)}`;
|
|
3340
3606
|
#queueDepthGaugeEntries = [];
|
|
3341
3607
|
#queueDepthGaugeMeterProvider;
|
|
@@ -3367,10 +3633,12 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3367
3633
|
acceptSignatureNonce: ["_fedify", "acceptSignatureNonce"],
|
|
3368
3634
|
circuitBreaker: ["_fedify", "circuit"],
|
|
3369
3635
|
taskDeduplication: ["_fedify", "taskDeduplication"],
|
|
3636
|
+
portableInboxForwarding: ["_fedify", "portableInboxForwarding"],
|
|
3370
3637
|
...options.kvPrefixes ?? {}
|
|
3371
3638
|
};
|
|
3372
3639
|
this.publicKeyTtl = Temporal.Duration.from(options.publicKeyTtl ?? { days: 30 });
|
|
3373
3640
|
this.httpMessageSignaturesSpecTtl = Temporal.Duration.from(options.httpMessageSignaturesSpecTtl ?? { days: 90 });
|
|
3641
|
+
this.portableInboxForwarding = resolvePortableInboxForwardingOptions(options.portableInboxForwarding);
|
|
3374
3642
|
if (options.queue == null) {
|
|
3375
3643
|
this.inboxQueue = void 0;
|
|
3376
3644
|
this.outboxQueue = void 0;
|
|
@@ -4040,8 +4308,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4040
4308
|
]);
|
|
4041
4309
|
const baseUrl = new URL(message.baseUrl);
|
|
4042
4310
|
let context = this.#createContext(baseUrl, ctxData);
|
|
4043
|
-
if (message.identifier != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: await context.getDocumentLoader({ identifier: message.identifier }) });
|
|
4044
|
-
else if (this.sharedInboxKeyDispatcher != null) {
|
|
4311
|
+
if (message.identifier != null && this.actorCallbacks?.keyPairsDispatcher != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: await context.getDocumentLoader({ identifier: message.identifier }) });
|
|
4312
|
+
else if (message.identifier == null && this.sharedInboxKeyDispatcher != null) {
|
|
4045
4313
|
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
4046
4314
|
if (identity != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
4047
4315
|
}
|
|
@@ -4634,6 +4902,15 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4634
4902
|
span,
|
|
4635
4903
|
metricState
|
|
4636
4904
|
});
|
|
4905
|
+
if (request.method === "POST") {
|
|
4906
|
+
const portable = parsePortableGatewayRequest(url);
|
|
4907
|
+
if (portable != null) return await this.#fetchPortableInbox(request, portable, {
|
|
4908
|
+
onNotFound,
|
|
4909
|
+
contextData,
|
|
4910
|
+
span,
|
|
4911
|
+
metricState
|
|
4912
|
+
});
|
|
4913
|
+
}
|
|
4637
4914
|
const portable = request.method === "GET" || request.method === "HEAD" ? parsePortableGatewayRequest(url) : null;
|
|
4638
4915
|
if (portable != null) return await discardBodyForHead(request, await this.#fetchPortableObject(request, portable, {
|
|
4639
4916
|
onNotFound,
|
|
@@ -4785,35 +5062,17 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4785
5062
|
onNotFound
|
|
4786
5063
|
});
|
|
4787
5064
|
context = this.#createContext(request, contextData, { documentLoader: await context.getDocumentLoader({ identifier: route.values.identifier }) });
|
|
4788
|
-
case "sharedInbox":
|
|
5065
|
+
case "sharedInbox":
|
|
4789
5066
|
if (routeName !== "inbox" && this.sharedInboxKeyDispatcher != null) {
|
|
4790
5067
|
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
4791
5068
|
if (identity != null) context = this.#createContext(request, contextData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
4792
5069
|
}
|
|
4793
|
-
|
|
4794
|
-
const inboxContextFactory = context.toInboxContext.bind(context);
|
|
4795
|
-
inboxContextFactory[rawInboxContextFactorySymbol] = context.toInboxContext.bind(context);
|
|
4796
|
-
return await handleInbox(request, {
|
|
5070
|
+
return await this.#handleInbox(request, {
|
|
4797
5071
|
recipient: route.values.identifier ?? null,
|
|
4798
5072
|
context,
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
kvPrefixes: this.kvPrefixes,
|
|
4802
|
-
publicKeyTtl: this.publicKeyTtl,
|
|
4803
|
-
queue: this.inboxQueue,
|
|
4804
|
-
actorDispatcher: this.actorCallbacks?.dispatcher,
|
|
4805
|
-
inboxListeners: this.inboxListeners,
|
|
4806
|
-
inboxErrorHandler: this.inboxErrorHandler,
|
|
4807
|
-
unverifiedActivityHandler: this.unverifiedActivityHandler,
|
|
4808
|
-
onNotFound,
|
|
4809
|
-
signatureTimeWindow: this.signatureTimeWindow,
|
|
4810
|
-
skipSignatureVerification: this.skipSignatureVerification,
|
|
4811
|
-
inboxChallengePolicy: this.inboxChallengePolicy,
|
|
4812
|
-
meterProvider: this.meterProvider,
|
|
4813
|
-
tracerProvider: this.tracerProvider,
|
|
4814
|
-
idempotencyStrategy: this.idempotencyStrategy
|
|
5073
|
+
contextData,
|
|
5074
|
+
onNotFound
|
|
4815
5075
|
});
|
|
4816
|
-
}
|
|
4817
5076
|
case "following": return await handleCollection(request, {
|
|
4818
5077
|
name: "following",
|
|
4819
5078
|
identifier: route.values.identifier,
|
|
@@ -4966,6 +5225,113 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4966
5225
|
onNotFound
|
|
4967
5226
|
});
|
|
4968
5227
|
}
|
|
5228
|
+
async #handleInbox(request, { recipient, context, contextData, onNotFound, portableInbox }) {
|
|
5229
|
+
if (!this.manuallyStartQueue) this._startQueueInternal(contextData);
|
|
5230
|
+
const inboxContextFactory = context.toInboxContext.bind(context);
|
|
5231
|
+
inboxContextFactory[rawInboxContextFactorySymbol] = context.toInboxContext.bind(context);
|
|
5232
|
+
return await handleInbox(request, {
|
|
5233
|
+
recipient,
|
|
5234
|
+
context,
|
|
5235
|
+
inboxContextFactory,
|
|
5236
|
+
kv: this.kv,
|
|
5237
|
+
kvPrefixes: this.kvPrefixes,
|
|
5238
|
+
publicKeyTtl: this.publicKeyTtl,
|
|
5239
|
+
queue: this.inboxQueue,
|
|
5240
|
+
actorDispatcher: this.actorCallbacks?.dispatcher,
|
|
5241
|
+
inboxListeners: this.inboxListeners,
|
|
5242
|
+
inboxErrorHandler: this.inboxErrorHandler,
|
|
5243
|
+
unverifiedActivityHandler: this.unverifiedActivityHandler,
|
|
5244
|
+
onNotFound,
|
|
5245
|
+
signatureTimeWindow: this.signatureTimeWindow,
|
|
5246
|
+
skipSignatureVerification: this.skipSignatureVerification,
|
|
5247
|
+
inboxChallengePolicy: this.inboxChallengePolicy,
|
|
5248
|
+
meterProvider: this.meterProvider,
|
|
5249
|
+
tracerProvider: this.tracerProvider,
|
|
5250
|
+
idempotencyStrategy: this.idempotencyStrategy,
|
|
5251
|
+
portableInbox
|
|
5252
|
+
});
|
|
5253
|
+
}
|
|
5254
|
+
async #fetchPortableInbox(request, portable, { onNotFound, contextData, span, metricState }) {
|
|
5255
|
+
const logger = getLogger([
|
|
5256
|
+
"fedify",
|
|
5257
|
+
"federation",
|
|
5258
|
+
"inbox"
|
|
5259
|
+
]);
|
|
5260
|
+
if (portable.type === "malformed") {
|
|
5261
|
+
metricState.endpoint = "not_found";
|
|
5262
|
+
logger.debug("Malformed FEP-ef61 gateway inbox request {url}: {error}", {
|
|
5263
|
+
url: request.url,
|
|
5264
|
+
error: portable.error
|
|
5265
|
+
});
|
|
5266
|
+
return new Response("Malformed portable inbox ID.", {
|
|
5267
|
+
status: 400,
|
|
5268
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
5269
|
+
});
|
|
5270
|
+
}
|
|
5271
|
+
const route = this.router.route(portable.path);
|
|
5272
|
+
if (route == null || route.name !== "inbox") {
|
|
5273
|
+
metricState.endpoint = "not_found";
|
|
5274
|
+
return await onNotFound(request);
|
|
5275
|
+
}
|
|
5276
|
+
metricState.routeTemplate = PORTABLE_GATEWAY_ROUTE_PREFIX + route.template;
|
|
5277
|
+
metricState.endpoint = "inbox";
|
|
5278
|
+
span.updateName(`${request.method} ${metricState.routeTemplate}`);
|
|
5279
|
+
const identifier = route.values.identifier;
|
|
5280
|
+
let context = this.#createContext(request, contextData);
|
|
5281
|
+
const actor = this.actorCallbacks?.dispatcher == null ? null : await this.actorCallbacks.dispatcher(context, identifier);
|
|
5282
|
+
const localOrigin = context.canonicalOrigin;
|
|
5283
|
+
const resolution = resolvePortableInboxRecipient(actor == null || actor instanceof Tombstone ? null : actor, {
|
|
5284
|
+
authority: portable.portableRequest.authority,
|
|
5285
|
+
canonicalInboxId: portable.canonicalId,
|
|
5286
|
+
localOrigin
|
|
5287
|
+
});
|
|
5288
|
+
if (resolution.status === "rejected") {
|
|
5289
|
+
logger.debug("Not accepting a delivery to the portable inbox {inbox} on behalf of the actor {identifier}: {reason}.", {
|
|
5290
|
+
inbox: portable.canonicalId,
|
|
5291
|
+
identifier,
|
|
5292
|
+
reason: resolution.reason
|
|
5293
|
+
});
|
|
5294
|
+
return await onNotFound(request);
|
|
5295
|
+
}
|
|
5296
|
+
const { recipient } = resolution;
|
|
5297
|
+
if (this.actorCallbacks?.keyPairsDispatcher != null) context = this.#createContext(request, contextData, { documentLoader: await context.getDocumentLoader({ identifier }) });
|
|
5298
|
+
const excludedOrigins = [localOrigin, new URL(request.url).origin];
|
|
5299
|
+
return await this.#handleInbox(request, {
|
|
5300
|
+
recipient: identifier,
|
|
5301
|
+
context,
|
|
5302
|
+
contextData,
|
|
5303
|
+
onNotFound,
|
|
5304
|
+
portableInbox: {
|
|
5305
|
+
recipient,
|
|
5306
|
+
forward: async (activity, activityId, activityType) => {
|
|
5307
|
+
if (this.portableInboxForwarding.maxTargets < 1) return;
|
|
5308
|
+
if (this.kv.cas == null) {
|
|
5309
|
+
if (!this.#portableInboxForwardingWarned) {
|
|
5310
|
+
this.#portableInboxForwardingWarned = true;
|
|
5311
|
+
logger.warn("Activities delivered to FEP-ef61 portable inboxes are not forwarded to the other gateways, as the key–value store does not support compare-and-swap (KvStore.cas()), which is needed to forward each activity at most once.");
|
|
5312
|
+
}
|
|
5313
|
+
return;
|
|
5314
|
+
}
|
|
5315
|
+
await forwardPortableInboxActivity({
|
|
5316
|
+
recipient,
|
|
5317
|
+
activity,
|
|
5318
|
+
activityId,
|
|
5319
|
+
activityType,
|
|
5320
|
+
excludedOrigins,
|
|
5321
|
+
baseUrl: context.origin,
|
|
5322
|
+
kv: this.kv,
|
|
5323
|
+
kvPrefix: this.kvPrefixes.portableInboxForwarding,
|
|
5324
|
+
outboxQueue: this.outboxQueue,
|
|
5325
|
+
startQueue: this.manuallyStartQueue ? void 0 : () => this._startQueueInternal(contextData),
|
|
5326
|
+
allowPrivateAddress: this.allowPrivateAddress,
|
|
5327
|
+
options: this.portableInboxForwarding,
|
|
5328
|
+
meterProvider: this.meterProvider,
|
|
5329
|
+
tracerProvider: this.tracerProvider
|
|
5330
|
+
});
|
|
5331
|
+
}
|
|
5332
|
+
}
|
|
5333
|
+
});
|
|
5334
|
+
}
|
|
4969
5335
|
async #fetchHashlinkMedia(request, media, { onNotFound, contextData, span, metricState }) {
|
|
4970
5336
|
metricState.endpoint = "hashlink_media";
|
|
4971
5337
|
metricState.routeTemplate = HASHLINK_MEDIA_ROUTE_TEMPLATE;
|
|
@@ -5196,6 +5562,12 @@ var ContextImpl = class ContextImpl {
|
|
|
5196
5562
|
if (path == null) throw new RouterError("No inbox path registered.");
|
|
5197
5563
|
return new URL(path, this.canonicalOrigin);
|
|
5198
5564
|
}
|
|
5565
|
+
getPortableInboxUri(identifier, authority) {
|
|
5566
|
+
const path = this.federation.router.build("inbox", { identifier });
|
|
5567
|
+
if (path == null) throw new RouterError("No inbox path registered.");
|
|
5568
|
+
if (authority == null) throw new TypeError("The authority of a portable ID is required outside an FEP-ef61 gateway request.");
|
|
5569
|
+
return buildPortableUri(authority, path);
|
|
5570
|
+
}
|
|
5199
5571
|
getFollowingUri(identifier) {
|
|
5200
5572
|
const path = this.federation.router.build("following", { identifier });
|
|
5201
5573
|
if (path == null) throw new RouterError("No following collection path registered.");
|
|
@@ -5798,6 +6170,9 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
|
|
|
5798
6170
|
getPortableObjectUri(cls, values, authority) {
|
|
5799
6171
|
return super.getPortableObjectUri(cls, values, authority ?? this.portableRequest?.authority);
|
|
5800
6172
|
}
|
|
6173
|
+
getPortableInboxUri(identifier, authority) {
|
|
6174
|
+
return super.getPortableInboxUri(identifier, authority ?? this.portableRequest?.authority);
|
|
6175
|
+
}
|
|
5801
6176
|
async getActor(identifier, options) {
|
|
5802
6177
|
if (this.federation.actorCallbacks == null || this.federation.actorCallbacks.dispatcher == null) throw new Error("No actor dispatcher registered.");
|
|
5803
6178
|
if (this.#invokedFromActorDispatcher != null) getLogger([
|
|
@@ -6188,4 +6563,4 @@ function getRequestId(request) {
|
|
|
6188
6563
|
return `req_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
|
6189
6564
|
}
|
|
6190
6565
|
//#endregion
|
|
6191
|
-
export {
|
|
6566
|
+
export { actorDehydrator as C, handleNodeInfoJrd as S, respondWithObjectIfAcceptable as _, OutboxContextImpl as a, handleBenchmarkTrigger as b, forwardPortableInboxActivity as c, handleCollection as d, handleCustomCollection as f, respondWithObject as g, handleOutbox as h, KvSpecDeterminer as i, resolvePortableInboxForwardingOptions as l, handleObject as m, FederationImpl as n, createFederation as o, handleInbox as p, InboxContextImpl as r, handleWebFinger as s, ContextImpl as t, handleActor as u, PORTABLE_OBJECT_CONTENT_TYPE as v, autoIdAssigner as w, handleNodeInfo as x, parseHashlinkGatewayRequest as y };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import {
|
|
2
|
+
import { Wt as WebFingerLinksDispatcher, _t as ActorAliasMapper, u as RequestContext, vt as ActorDispatcher, yt as ActorHandleMapper } from "./context-BSywYspi.js";
|
|
3
3
|
import { RouterError, RouterOptions, RouterRouteResult } from "@fedify/uri-template";
|
|
4
4
|
import { MeterProvider, Span, Tracer } from "@opentelemetry/api";
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import {
|
|
2
|
+
import { Wt as WebFingerLinksDispatcher, _t as ActorAliasMapper, u as RequestContext, vt as ActorDispatcher, yt as ActorHandleMapper } from "./context-CZjZYXFC.cjs";
|
|
3
3
|
import { MeterProvider, Span, Tracer } from "@opentelemetry/api";
|
|
4
4
|
import { RouterError, RouterOptions, RouterRouteResult } from "@fedify/uri-template";
|
|
5
5
|
|
package/dist/mod.cjs
CHANGED
|
@@ -3,14 +3,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
require("./rolldown-runtime-Dmm3t92W.cjs");
|
|
4
4
|
const require_transformers = require("./transformers-BalCrSsr.cjs");
|
|
5
5
|
require("./compat/mod.cjs");
|
|
6
|
-
const require_http = require("./http-
|
|
7
|
-
const require_federation = require("./federation-
|
|
6
|
+
const require_http = require("./http-DGk8XI38.cjs");
|
|
7
|
+
const require_federation = require("./federation-B1aeTKKN.cjs");
|
|
8
8
|
const require_types = require("./types-Be2zbyeG.cjs");
|
|
9
|
-
const require_owner = require("./owner-
|
|
10
|
-
const require_kv_cache = require("./kv-cache-
|
|
9
|
+
const require_owner = require("./owner-DCIH7Iq0.cjs");
|
|
10
|
+
const require_kv_cache = require("./kv-cache-DvqkKNIj.cjs");
|
|
11
11
|
require("./nodeinfo/mod.cjs");
|
|
12
12
|
require("./runtime/mod.cjs");
|
|
13
|
-
const require_sig = require("./sig-
|
|
13
|
+
const require_sig = require("./sig-C6TnADze.cjs");
|
|
14
14
|
require("./utils/mod.cjs");
|
|
15
15
|
//#endregion
|
|
16
16
|
exports.CircuitBreaker = require_federation.CircuitBreaker;
|