@fedify/fedify 2.4.0-dev.2030 → 2.4.0-dev.2047
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-BYJ5otJa.mjs → builder-Cue1kVHU.mjs} +12 -11
- 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-BIvUoJxm.mjs → compound-proof-YT4tajyj.mjs} +1 -1
- package/dist/{context-uyRUWoZQ.d.ts → context-BJPHhBmD.d.ts} +100 -2
- package/dist/{context-BeDnDuF3.d.cts → context-Bh_mJfbD.d.cts} +100 -2
- package/dist/{context-CbS35fLr.mjs → context-DG5QeQ8W.mjs} +3 -1
- package/dist/{deno-Vj_9wePq.mjs → deno-Dcj6O4LJ.mjs} +1 -1
- package/dist/{docloader-qUudHZVH.mjs → docloader-BRlNjHlQ.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/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.test.d.mts +2 -0
- package/dist/federation/portable.test.mjs +430 -0
- 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 +115 -2
- package/dist/{federation-CTnaljmy.cjs → federation-Bdu06LEl.cjs} +324 -26
- package/dist/{http-By8tnmEr.js → http-BmdqHyms.js} +1 -1
- package/dist/{http-B5F1JMh0.cjs → http-CGjvl34X.cjs} +1 -1
- package/dist/{http-D4WPcJUe.mjs → http-CK6kjLnO.mjs} +3 -3
- package/dist/{key-B_Zc5Jbd.mjs → key-CzCAq6D9.mjs} +2 -2
- package/dist/{kv-cache-8K70pjtX.cjs → kv-cache-CvEicbrf.cjs} +1 -1
- package/dist/{kv-cache-BXdT7pJQ.mjs → kv-cache-YATuzCy-.mjs} +1 -1
- package/dist/{kv-cache-BswMKQjC.js → kv-cache-fi_-XZco.js} +1 -1
- package/dist/{ld-B16KUSIQ.mjs → ld-CNWm8mJc.mjs} +3 -3
- package/dist/{metrics-DpQqUAmh.mjs → metrics-CDoBPWjf.mjs} +1 -1
- package/dist/{middleware-BL5HFFVU.mjs → middleware-CF6uz8wa.mjs} +1 -1
- package/dist/{middleware-C7_hqDnl.mjs → middleware-CtFNjIUD.mjs} +326 -28
- package/dist/{middleware-Cxto6Bq2.js → middleware-Drzx-OID.js} +325 -27
- package/dist/{mod-D882_Xsg.d.ts → mod-BofpDIcU.d.ts} +1 -1
- package/dist/{mod-x9W0d0Pk.d.cts → mod-DU8aVzQJ.d.cts} +1 -1
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +4 -4
- package/dist/mod.d.ts +4 -4
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/handler.test.mjs +2 -2
- package/dist/{owner-BIOIhZoM.mjs → owner-B3PgGiJ1.mjs} +2 -2
- package/dist/{owner-D-E0bT2O.js → owner-CMnmv7S9.js} +16 -3
- package/dist/{owner-WUYke16i.cjs → owner-Hurn_ocn.cjs} +16 -3
- package/dist/{proof-BVxJu5vv.mjs → proof-fKycdssC.mjs} +18 -5
- package/dist/{send-Cr5FJ7iu.mjs → send-BqBILxYE.mjs} +3 -3
- 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 +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/proof.test.mjs +208 -1
- package/dist/{temporal-CCf0lZV3.mjs → temporal-SUiLJ0Co.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/testing/mod.d.mts +99 -1
- package/dist/testing/mod.mjs +2 -2
- package/dist/{testing-hbky2gMN.mjs → testing-By1YYsIK.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 +7 -7
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as MessageQueue, A as ObjectCallbackSetters, At as NodeInfoDispatcher, B as TaskDefinitionOptions, Bt as WebFingerLinksDispatcher, C as FederationOptions, Ct as CollectionDispatcher, D as InboxChallengePolicy, Dt as InboxErrorHandler, E as IdempotencyStrategy, Et as CustomCollectionDispatcher, F as FederationQueueOptions, Ft as OutboxListenerErrorHandler, G as RetryContext, Gt as digest, H as TaskHandler, Ht as SenderKeyPair, I as createFederation, It as OutboxPermanentFailureHandler, J as RespondWithObjectOptions, K as RetryPolicy, L as Message, Lt as SharedInboxKeyDispatcher, M as Rfc6570Expression, Mt as ObjectDispatcher, N as FederationKvPrefixes, Nt as OutboxErrorHandler, O as InboxListenerSetters, Ot as InboxListener, P as FederationOrigin, Pt as OutboxListener, Q as InProcessMessageQueueOptions, R as createFederationBuilder, Rt as UnverifiedActivityHandler, S as FederationFetchOptions, St as CollectionCursor, T as IdempotencyKeyCallback, Tt as CustomCollectionCursor, U as TaskRegistry, Ut as PageItems, V as TaskEnqueueOptions, Vt as SendActivityError, W as CreateExponentialBackoffPolicyOptions, Wt as buildCollectionSynchronizationHeader, X as respondWithObjectIfAcceptable, Y as respondWithObject, Z as InProcessMessageQueue, _ as CustomCollectionCallbackSetters, _t as ActorDispatcher, a as GetSignedKeyOptions, at as CircuitBreakerActivityDrop, b as FederationBenchmarkOptions, bt as AuthorizePredicate, c as ParseUriResult, ct as CircuitBreakerFailurePolicy, d as RouteActivityOptions, dt as CircuitBreakerState, et as MessageQueueDepth, f as SendActivityOptions, ft as CircuitBreakerStateChange, g as ConstructorWithTypeId, gt as ActorAliasMapper, h as CollectionCallbackSetters, ht as parseCircuitBreakerKvState, i as GetActorOptions, it as CircuitBreaker, j as OutboxListenerSetters, jt as ObjectAuthorizePredicate, k as MediaUploaderSetters, kt as MediaUploaderCallback, l as PortableRequest, lt as CircuitBreakerKvState, m as ActorCallbackSetters, mt as normalizeCircuitBreakerOptions, n as Context, nt as MessageQueueListenOptions, o as InboxContext, ot as CircuitBreakerBeforeSendDecision, p as SendActivityOptionsForCollection, pt as NormalizedCircuitBreakerOptions, q as createExponentialBackoffPolicy, r as ForwardActivityOptions, rt as ParallelMessageQueue, s as OutboxContext, st as CircuitBreakerCreateOptions, t as ActorKeyPair, tt as MessageQueueEnqueueOptions, u as RequestContext, ut as CircuitBreakerOptions, v as Federatable, vt as ActorHandleMapper, w as FederationStartQueueOptions, wt as CustomCollectionCounter, x as FederationBuilder, xt as CollectionCounter, y as Federation, yt as ActorKeyPairsDispatcher, z as TaskDefinition, zt as UnverifiedActivityReason } from "../context-Bh_mJfbD.cjs";
|
|
3
3
|
import { a as MemoryKvStore, i as KvStoreSetOptions, n as KvStore, r as KvStoreListEntry, t as KvKey } from "../kv-BhNbN8Ed.cjs";
|
|
4
|
-
import { a as RouterOptions, i as RouterError, n as handleWebFinger, o as RouterRouteResult, r as Router, t as WebFingerHandlerParameters } from "../mod-
|
|
5
|
-
export { ActorAliasMapper, ActorCallbackSetters, ActorDispatcher, ActorHandleMapper, ActorKeyPair, ActorKeyPairsDispatcher, AuthorizePredicate, CircuitBreaker, CircuitBreakerActivityDrop, CircuitBreakerBeforeSendDecision, CircuitBreakerCreateOptions, CircuitBreakerFailurePolicy, CircuitBreakerKvState, CircuitBreakerOptions, CircuitBreakerState, CircuitBreakerStateChange, CollectionCallbackSetters, CollectionCounter, CollectionCursor, CollectionDispatcher, ConstructorWithTypeId, Context, CreateExponentialBackoffPolicyOptions, CustomCollectionCallbackSetters, CustomCollectionCounter, CustomCollectionCursor, CustomCollectionDispatcher, Federatable, Federation, FederationBenchmarkOptions, FederationBuilder, FederationFetchOptions, FederationKvPrefixes, FederationOptions, FederationOrigin, FederationQueueOptions, FederationStartQueueOptions, ForwardActivityOptions, GetActorOptions, GetSignedKeyOptions, IdempotencyKeyCallback, IdempotencyStrategy, InProcessMessageQueue, InProcessMessageQueueOptions, InboxChallengePolicy, InboxContext, InboxErrorHandler, InboxListener, InboxListenerSetters, KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions, MediaUploaderCallback, MediaUploaderSetters, MemoryKvStore, Message, MessageQueue, MessageQueueDepth, MessageQueueEnqueueOptions, MessageQueueListenOptions, NodeInfoDispatcher, NormalizedCircuitBreakerOptions, ObjectAuthorizePredicate, ObjectCallbackSetters, ObjectDispatcher, OutboxContext, OutboxErrorHandler, OutboxListener, OutboxListenerErrorHandler, OutboxListenerSetters, OutboxPermanentFailureHandler, PageItems, ParallelMessageQueue, ParseUriResult, RequestContext, RespondWithObjectOptions, RetryContext, RetryPolicy, Rfc6570Expression, RouteActivityOptions, Router, RouterError, RouterOptions, RouterRouteResult, SendActivityError, SendActivityOptions, SendActivityOptionsForCollection, SenderKeyPair, SharedInboxKeyDispatcher, TaskDefinition, TaskDefinitionOptions, TaskEnqueueOptions, TaskHandler, TaskRegistry, UnverifiedActivityHandler, UnverifiedActivityReason, WebFingerHandlerParameters, WebFingerLinksDispatcher, buildCollectionSynchronizationHeader, createExponentialBackoffPolicy, createFederation, createFederationBuilder, digest, handleWebFinger, normalizeCircuitBreakerOptions, parseCircuitBreakerKvState, respondWithObject, respondWithObjectIfAcceptable };
|
|
4
|
+
import { a as RouterOptions, i as RouterError, n as handleWebFinger, o as RouterRouteResult, r as Router, t as WebFingerHandlerParameters } from "../mod-DU8aVzQJ.cjs";
|
|
5
|
+
export { ActorAliasMapper, ActorCallbackSetters, ActorDispatcher, ActorHandleMapper, ActorKeyPair, ActorKeyPairsDispatcher, AuthorizePredicate, CircuitBreaker, CircuitBreakerActivityDrop, CircuitBreakerBeforeSendDecision, CircuitBreakerCreateOptions, CircuitBreakerFailurePolicy, CircuitBreakerKvState, CircuitBreakerOptions, CircuitBreakerState, CircuitBreakerStateChange, CollectionCallbackSetters, CollectionCounter, CollectionCursor, CollectionDispatcher, ConstructorWithTypeId, Context, CreateExponentialBackoffPolicyOptions, CustomCollectionCallbackSetters, CustomCollectionCounter, CustomCollectionCursor, CustomCollectionDispatcher, Federatable, Federation, FederationBenchmarkOptions, FederationBuilder, FederationFetchOptions, FederationKvPrefixes, FederationOptions, FederationOrigin, FederationQueueOptions, FederationStartQueueOptions, ForwardActivityOptions, GetActorOptions, GetSignedKeyOptions, IdempotencyKeyCallback, IdempotencyStrategy, InProcessMessageQueue, InProcessMessageQueueOptions, InboxChallengePolicy, InboxContext, InboxErrorHandler, InboxListener, InboxListenerSetters, KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions, MediaUploaderCallback, MediaUploaderSetters, MemoryKvStore, Message, MessageQueue, MessageQueueDepth, MessageQueueEnqueueOptions, MessageQueueListenOptions, NodeInfoDispatcher, NormalizedCircuitBreakerOptions, ObjectAuthorizePredicate, ObjectCallbackSetters, ObjectDispatcher, OutboxContext, OutboxErrorHandler, OutboxListener, OutboxListenerErrorHandler, OutboxListenerSetters, OutboxPermanentFailureHandler, PageItems, ParallelMessageQueue, ParseUriResult, PortableRequest, RequestContext, RespondWithObjectOptions, RetryContext, RetryPolicy, Rfc6570Expression, RouteActivityOptions, Router, RouterError, RouterOptions, RouterRouteResult, SendActivityError, SendActivityOptions, SendActivityOptionsForCollection, SenderKeyPair, SharedInboxKeyDispatcher, TaskDefinition, TaskDefinitionOptions, TaskEnqueueOptions, TaskHandler, TaskRegistry, UnverifiedActivityHandler, UnverifiedActivityReason, WebFingerHandlerParameters, WebFingerLinksDispatcher, buildCollectionSynchronizationHeader, createExponentialBackoffPolicy, createFederation, createFederationBuilder, digest, handleWebFinger, normalizeCircuitBreakerOptions, parseCircuitBreakerKvState, respondWithObject, respondWithObjectIfAcceptable };
|
package/dist/federation/mod.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as MessageQueue, A as ObjectCallbackSetters, At as NodeInfoDispatcher, B as TaskDefinitionOptions, Bt as WebFingerLinksDispatcher, C as FederationOptions, Ct as CollectionDispatcher, D as InboxChallengePolicy, Dt as InboxErrorHandler, E as IdempotencyStrategy, Et as CustomCollectionDispatcher, F as FederationQueueOptions, Ft as OutboxListenerErrorHandler, G as RetryContext, Gt as digest, H as TaskHandler, Ht as SenderKeyPair, I as createFederation, It as OutboxPermanentFailureHandler, J as RespondWithObjectOptions, K as RetryPolicy, L as Message, Lt as SharedInboxKeyDispatcher, M as Rfc6570Expression, Mt as ObjectDispatcher, N as FederationKvPrefixes, Nt as OutboxErrorHandler, O as InboxListenerSetters, Ot as InboxListener, P as FederationOrigin, Pt as OutboxListener, Q as InProcessMessageQueueOptions, R as createFederationBuilder, Rt as UnverifiedActivityHandler, S as FederationFetchOptions, St as CollectionCursor, T as IdempotencyKeyCallback, Tt as CustomCollectionCursor, U as TaskRegistry, Ut as PageItems, V as TaskEnqueueOptions, Vt as SendActivityError, W as CreateExponentialBackoffPolicyOptions, Wt as buildCollectionSynchronizationHeader, X as respondWithObjectIfAcceptable, Y as respondWithObject, Z as InProcessMessageQueue, _ as CustomCollectionCallbackSetters, _t as ActorDispatcher, a as GetSignedKeyOptions, at as CircuitBreakerActivityDrop, b as FederationBenchmarkOptions, bt as AuthorizePredicate, c as ParseUriResult, ct as CircuitBreakerFailurePolicy, d as RouteActivityOptions, dt as CircuitBreakerState, et as MessageQueueDepth, f as SendActivityOptions, ft as CircuitBreakerStateChange, g as ConstructorWithTypeId, gt as ActorAliasMapper, h as CollectionCallbackSetters, ht as parseCircuitBreakerKvState, i as GetActorOptions, it as CircuitBreaker, j as OutboxListenerSetters, jt as ObjectAuthorizePredicate, k as MediaUploaderSetters, kt as MediaUploaderCallback, l as PortableRequest, lt as CircuitBreakerKvState, m as ActorCallbackSetters, mt as normalizeCircuitBreakerOptions, n as Context, nt as MessageQueueListenOptions, o as InboxContext, ot as CircuitBreakerBeforeSendDecision, p as SendActivityOptionsForCollection, pt as NormalizedCircuitBreakerOptions, q as createExponentialBackoffPolicy, r as ForwardActivityOptions, rt as ParallelMessageQueue, s as OutboxContext, st as CircuitBreakerCreateOptions, t as ActorKeyPair, tt as MessageQueueEnqueueOptions, u as RequestContext, ut as CircuitBreakerOptions, v as Federatable, vt as ActorHandleMapper, w as FederationStartQueueOptions, wt as CustomCollectionCounter, x as FederationBuilder, xt as CollectionCounter, y as Federation, yt as ActorKeyPairsDispatcher, z as TaskDefinition, zt as UnverifiedActivityReason } from "../context-BJPHhBmD.js";
|
|
3
3
|
import { a as MemoryKvStore, i as KvStoreSetOptions, n as KvStore, r as KvStoreListEntry, t as KvKey } from "../kv-BhNbN8Ed.js";
|
|
4
|
-
import { a as RouterOptions, i as RouterError, n as handleWebFinger, o as RouterRouteResult, r as Router, t as WebFingerHandlerParameters } from "../mod-
|
|
5
|
-
export { ActorAliasMapper, ActorCallbackSetters, ActorDispatcher, ActorHandleMapper, ActorKeyPair, ActorKeyPairsDispatcher, AuthorizePredicate, CircuitBreaker, CircuitBreakerActivityDrop, CircuitBreakerBeforeSendDecision, CircuitBreakerCreateOptions, CircuitBreakerFailurePolicy, CircuitBreakerKvState, CircuitBreakerOptions, CircuitBreakerState, CircuitBreakerStateChange, CollectionCallbackSetters, CollectionCounter, CollectionCursor, CollectionDispatcher, ConstructorWithTypeId, Context, CreateExponentialBackoffPolicyOptions, CustomCollectionCallbackSetters, CustomCollectionCounter, CustomCollectionCursor, CustomCollectionDispatcher, Federatable, Federation, FederationBenchmarkOptions, FederationBuilder, FederationFetchOptions, FederationKvPrefixes, FederationOptions, FederationOrigin, FederationQueueOptions, FederationStartQueueOptions, ForwardActivityOptions, GetActorOptions, GetSignedKeyOptions, IdempotencyKeyCallback, IdempotencyStrategy, InProcessMessageQueue, InProcessMessageQueueOptions, InboxChallengePolicy, InboxContext, InboxErrorHandler, InboxListener, InboxListenerSetters, KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions, MediaUploaderCallback, MediaUploaderSetters, MemoryKvStore, Message, MessageQueue, MessageQueueDepth, MessageQueueEnqueueOptions, MessageQueueListenOptions, NodeInfoDispatcher, NormalizedCircuitBreakerOptions, ObjectAuthorizePredicate, ObjectCallbackSetters, ObjectDispatcher, OutboxContext, OutboxErrorHandler, OutboxListener, OutboxListenerErrorHandler, OutboxListenerSetters, OutboxPermanentFailureHandler, PageItems, ParallelMessageQueue, ParseUriResult, RequestContext, RespondWithObjectOptions, RetryContext, RetryPolicy, Rfc6570Expression, RouteActivityOptions, Router, RouterError, RouterOptions, RouterRouteResult, SendActivityError, SendActivityOptions, SendActivityOptionsForCollection, SenderKeyPair, SharedInboxKeyDispatcher, TaskDefinition, TaskDefinitionOptions, TaskEnqueueOptions, TaskHandler, TaskRegistry, UnverifiedActivityHandler, UnverifiedActivityReason, WebFingerHandlerParameters, WebFingerLinksDispatcher, buildCollectionSynchronizationHeader, createExponentialBackoffPolicy, createFederation, createFederationBuilder, digest, handleWebFinger, normalizeCircuitBreakerOptions, parseCircuitBreakerKvState, respondWithObject, respondWithObjectIfAcceptable };
|
|
4
|
+
import { a as RouterOptions, i as RouterError, n as handleWebFinger, o as RouterRouteResult, r as Router, t as WebFingerHandlerParameters } from "../mod-BofpDIcU.js";
|
|
5
|
+
export { ActorAliasMapper, ActorCallbackSetters, ActorDispatcher, ActorHandleMapper, ActorKeyPair, ActorKeyPairsDispatcher, AuthorizePredicate, CircuitBreaker, CircuitBreakerActivityDrop, CircuitBreakerBeforeSendDecision, CircuitBreakerCreateOptions, CircuitBreakerFailurePolicy, CircuitBreakerKvState, CircuitBreakerOptions, CircuitBreakerState, CircuitBreakerStateChange, CollectionCallbackSetters, CollectionCounter, CollectionCursor, CollectionDispatcher, ConstructorWithTypeId, Context, CreateExponentialBackoffPolicyOptions, CustomCollectionCallbackSetters, CustomCollectionCounter, CustomCollectionCursor, CustomCollectionDispatcher, Federatable, Federation, FederationBenchmarkOptions, FederationBuilder, FederationFetchOptions, FederationKvPrefixes, FederationOptions, FederationOrigin, FederationQueueOptions, FederationStartQueueOptions, ForwardActivityOptions, GetActorOptions, GetSignedKeyOptions, IdempotencyKeyCallback, IdempotencyStrategy, InProcessMessageQueue, InProcessMessageQueueOptions, InboxChallengePolicy, InboxContext, InboxErrorHandler, InboxListener, InboxListenerSetters, KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions, MediaUploaderCallback, MediaUploaderSetters, MemoryKvStore, Message, MessageQueue, MessageQueueDepth, MessageQueueEnqueueOptions, MessageQueueListenOptions, NodeInfoDispatcher, NormalizedCircuitBreakerOptions, ObjectAuthorizePredicate, ObjectCallbackSetters, ObjectDispatcher, OutboxContext, OutboxErrorHandler, OutboxListener, OutboxListenerErrorHandler, OutboxListenerSetters, OutboxPermanentFailureHandler, PageItems, ParallelMessageQueue, ParseUriResult, PortableRequest, RequestContext, RespondWithObjectOptions, RetryContext, RetryPolicy, Rfc6570Expression, RouteActivityOptions, Router, RouterError, RouterOptions, RouterRouteResult, SendActivityError, SendActivityOptions, SendActivityOptionsForCollection, SenderKeyPair, SharedInboxKeyDispatcher, TaskDefinition, TaskDefinitionOptions, TaskEnqueueOptions, TaskHandler, TaskRegistry, UnverifiedActivityHandler, UnverifiedActivityReason, WebFingerHandlerParameters, WebFingerLinksDispatcher, buildCollectionSynchronizationHeader, createExponentialBackoffPolicy, createFederation, createFederationBuilder, digest, handleWebFinger, normalizeCircuitBreakerOptions, parseCircuitBreakerKvState, respondWithObject, respondWithObjectIfAcceptable };
|
package/dist/federation/mod.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { a as respondWithObject, c as digest, d as parseCircuitBreakerKvState, f as createFederationBuilder, i as SendActivityError, l as CircuitBreaker, n as handleWebFinger, o as respondWithObjectIfAcceptable, r as createExponentialBackoffPolicy, s as buildCollectionSynchronizationHeader, t as createFederation, u as normalizeCircuitBreakerOptions } from "../middleware-
|
|
3
|
+
import { a as respondWithObject, c as digest, d as parseCircuitBreakerKvState, f as createFederationBuilder, i as SendActivityError, l as CircuitBreaker, n as handleWebFinger, o as respondWithObjectIfAcceptable, r as createExponentialBackoffPolicy, s as buildCollectionSynchronizationHeader, t as createFederation, u as normalizeCircuitBreakerOptions } from "../middleware-Drzx-OID.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
import { Router as Router$1, RouterError as RouterError$1, assertPath, isPath } from "@fedify/uri-template";
|
|
6
6
|
import { isEqual } from "es-toolkit";
|
|
@@ -7,12 +7,12 @@ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
|
7
7
|
import "../std__assert-DvMDRPes.mjs";
|
|
8
8
|
import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
|
|
9
9
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
10
|
-
import { t as exportJwk } from "../key-
|
|
10
|
+
import { t as exportJwk } from "../key-CzCAq6D9.mjs";
|
|
11
11
|
import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
|
|
12
|
-
import { n as FederationImpl, o as createFederation } from "../middleware-
|
|
13
|
-
import { s as detachSignature } from "../ld-
|
|
14
|
-
import { r as signObject } from "../proof-
|
|
15
|
-
import { a as verifyCompoundPortableObjectProofs } from "../compound-proof-
|
|
12
|
+
import { n as FederationImpl, o as createFederation } from "../middleware-CtFNjIUD.mjs";
|
|
13
|
+
import { s as detachSignature } from "../ld-CNWm8mJc.mjs";
|
|
14
|
+
import { r as signObject } from "../proof-fKycdssC.mjs";
|
|
15
|
+
import { a as verifyCompoundPortableObjectProofs } from "../compound-proof-YT4tajyj.mjs";
|
|
16
16
|
import { Create, Note, Person } from "@fedify/vocab";
|
|
17
17
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
18
18
|
import { exportDidKey, parseIri } from "@fedify/vocab-runtime";
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
5
|
+
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
6
|
+
import { t as assertInstanceOf } from "../assert_instance_of-mrXWWNY-.mjs";
|
|
7
|
+
import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
|
|
8
|
+
import "../std__assert-DvMDRPes.mjs";
|
|
9
|
+
import { t as assertStrictEquals } from "../assert_strict_equals-CYvBmkpC.mjs";
|
|
10
|
+
import { s as signRequest } from "../http-CK6kjLnO.mjs";
|
|
11
|
+
import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
|
|
12
|
+
import { g as PORTABLE_OBJECT_CONTENT_TYPE, o as createFederation } from "../middleware-CtFNjIUD.mjs";
|
|
13
|
+
import { o as verifyPortableObjectProof, r as signObject } from "../proof-fKycdssC.mjs";
|
|
14
|
+
import { Collection, Create, Note, Object as Object$1, Person, Tombstone, lookupObject } from "@fedify/vocab";
|
|
15
|
+
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
16
|
+
import { exportDidKey, formatIri, parseIri } from "@fedify/vocab-runtime";
|
|
17
|
+
//#region src/federation/portable.test.ts
|
|
18
|
+
const did = await exportDidKey(ed25519PublicKey.publicKey);
|
|
19
|
+
const keyId = new URL(`${did}#${did.substring(8)}`);
|
|
20
|
+
const otherKeyPair = await crypto.subtle.generateKey("Ed25519", true, ["sign", "verify"]);
|
|
21
|
+
const otherDid = await exportDidKey(otherKeyPair.publicKey);
|
|
22
|
+
const otherKeyId = new URL(`${otherDid}#${otherDid.substring(8)}`);
|
|
23
|
+
const ACCEPT = "application/activity+json";
|
|
24
|
+
function gatewayUrl(path, authority = did) {
|
|
25
|
+
return `https://example.com/.well-known/apgateway/${authority}${path}`;
|
|
26
|
+
}
|
|
27
|
+
function gatewayRequest(path, init = {}) {
|
|
28
|
+
const { authority, ...rest } = init;
|
|
29
|
+
return new Request(gatewayUrl(path, authority), {
|
|
30
|
+
...rest,
|
|
31
|
+
headers: {
|
|
32
|
+
Accept: ACCEPT,
|
|
33
|
+
...rest.headers
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function createTestFederation() {
|
|
38
|
+
return createFederation({
|
|
39
|
+
kv: new MemoryKvStore(),
|
|
40
|
+
documentLoaderFactory: () => mockDocumentLoader,
|
|
41
|
+
contextLoaderFactory: () => mockDocumentLoader
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async function sign(object, privateKey = ed25519PrivateKey, key = keyId) {
|
|
45
|
+
return await signObject(object, privateKey, key, { contextLoader: mockDocumentLoader });
|
|
46
|
+
}
|
|
47
|
+
async function signedNote(path, authority = did, content = "Hello") {
|
|
48
|
+
return await sign(new Note({
|
|
49
|
+
id: parseIri(`ap+ef61://${authority}${path}`),
|
|
50
|
+
attribution: parseIri(`ap+ef61://${authority}/actor`),
|
|
51
|
+
content
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
test("Federation.fetch() serves portable objects through object dispatchers", async (t) => {
|
|
55
|
+
const federation = createTestFederation();
|
|
56
|
+
const calls = [];
|
|
57
|
+
federation.setObjectDispatcher(Note, "/users/{userId}/notes/{noteId}", async (ctx, values) => {
|
|
58
|
+
calls.push({
|
|
59
|
+
values,
|
|
60
|
+
portableRequest: ctx.portableRequest
|
|
61
|
+
});
|
|
62
|
+
if (values.noteId === "missing") return null;
|
|
63
|
+
if (values.noteId === "https") return new Note({
|
|
64
|
+
id: ctx.getObjectUri(Note, values),
|
|
65
|
+
content: "Not portable"
|
|
66
|
+
});
|
|
67
|
+
if (values.noteId === "ap") return await sign(new Note({
|
|
68
|
+
id: parseIri(`ap://${did}/users/${values.userId}/notes/ap`),
|
|
69
|
+
content: "Hello"
|
|
70
|
+
}));
|
|
71
|
+
if (values.noteId === "ignores-authority") return await signedNote(`/users/${values.userId}/notes/${values.noteId}`);
|
|
72
|
+
if (ctx.portableRequest?.authority !== did) return null;
|
|
73
|
+
return await sign(new Note({
|
|
74
|
+
id: ctx.getPortableObjectUri(Note, values),
|
|
75
|
+
attribution: parseIri(`ap+ef61://${did}/actor`),
|
|
76
|
+
content: `Note ${values.noteId} by ${values.userId}`
|
|
77
|
+
}));
|
|
78
|
+
});
|
|
79
|
+
federation.setActorDispatcher("/actors/{identifier}", (ctx, identifier) => new Person({ id: ctx.getActorUri(identifier) }));
|
|
80
|
+
await t.step("serves a portable object", async () => {
|
|
81
|
+
calls.length = 0;
|
|
82
|
+
const response = await federation.fetch(gatewayRequest("/users/alice/notes/123"), { contextData: void 0 });
|
|
83
|
+
assertEquals(response.status, 200);
|
|
84
|
+
assertEquals(response.headers.get("Content-Type"), PORTABLE_OBJECT_CONTENT_TYPE);
|
|
85
|
+
assertEquals(response.headers.get("Vary"), "Accept");
|
|
86
|
+
const json = await response.json();
|
|
87
|
+
assertEquals(json.id, `ap+ef61://${did}/users/alice/notes/123`);
|
|
88
|
+
assertEquals(json.content, "Note 123 by alice");
|
|
89
|
+
assertEquals((await verifyPortableObjectProof(json, { contextLoader: mockDocumentLoader })).verified, true);
|
|
90
|
+
assertEquals(calls.length, 1);
|
|
91
|
+
assertEquals(calls[0].values, {
|
|
92
|
+
userId: "alice",
|
|
93
|
+
noteId: "123"
|
|
94
|
+
});
|
|
95
|
+
assertEquals(calls[0].portableRequest?.authority, did);
|
|
96
|
+
assertEquals(formatIri(calls[0].portableRequest.id), `ap+ef61://${did}/users/alice/notes/123`);
|
|
97
|
+
});
|
|
98
|
+
await t.step("accepts a percent-encoded DID authority", async () => {
|
|
99
|
+
calls.length = 0;
|
|
100
|
+
assertEquals((await federation.fetch(gatewayRequest("/users/alice/notes/123", { authority: did.replaceAll(":", "%3A") }), { contextData: void 0 })).status, 200);
|
|
101
|
+
assertEquals(calls[0].portableRequest?.authority, did);
|
|
102
|
+
});
|
|
103
|
+
await t.step("ignores the query, including location hints", async () => {
|
|
104
|
+
assertEquals((await federation.fetch(gatewayRequest("/users/alice/notes/123?@gateway=https%3A%2F%2Fexample.com&x=%ZZ"), { contextData: void 0 })).status, 200);
|
|
105
|
+
});
|
|
106
|
+
await t.step("accepts an ap: ID returned by the dispatcher", async () => {
|
|
107
|
+
assertEquals((await federation.fetch(gatewayRequest("/users/alice/notes/ap"), { contextData: void 0 })).status, 200);
|
|
108
|
+
});
|
|
109
|
+
await t.step("responds to HEAD without a body", async () => {
|
|
110
|
+
const response = await federation.fetch(gatewayRequest("/users/alice/notes/123", { method: "HEAD" }), { contextData: void 0 });
|
|
111
|
+
assertEquals(response.status, 200);
|
|
112
|
+
assertEquals(response.headers.get("Content-Type"), PORTABLE_OBJECT_CONTENT_TYPE);
|
|
113
|
+
assertEquals(response.body, null);
|
|
114
|
+
});
|
|
115
|
+
await t.step("responds with 404 for objects it does not serve", async () => {
|
|
116
|
+
for (const request of [
|
|
117
|
+
gatewayRequest("/users/alice/notes/missing"),
|
|
118
|
+
gatewayRequest("/users/alice/notes/https"),
|
|
119
|
+
gatewayRequest("/users/alice/notes/123", { authority: otherDid }),
|
|
120
|
+
gatewayRequest("/users/alice/notes/ignores-authority", { authority: otherDid }),
|
|
121
|
+
gatewayRequest("/users/alice/posts/123"),
|
|
122
|
+
gatewayRequest("/actors/alice")
|
|
123
|
+
]) assertEquals((await federation.fetch(request, { contextData: void 0 })).status, 404, request.url);
|
|
124
|
+
});
|
|
125
|
+
await t.step("responds with 400 for malformed portable IDs", async () => {
|
|
126
|
+
for (const path of [
|
|
127
|
+
`/.well-known/apgateway/${did}`,
|
|
128
|
+
"/.well-known/apgateway/did:key:/users/alice/notes/123",
|
|
129
|
+
`/.well-known/apgateway/${did}/users/alice/notes/%ZZ`
|
|
130
|
+
]) assertEquals((await federation.fetch(new Request(`https://example.com${path}`, { headers: { Accept: ACCEPT } }), { contextData: void 0 })).status, 400, path);
|
|
131
|
+
});
|
|
132
|
+
await t.step("leaves other gateway requests to onNotFound()", async () => {
|
|
133
|
+
for (const request of [
|
|
134
|
+
new Request("https://example.com/.well-known/apgateway", { headers: { Accept: ACCEPT } }),
|
|
135
|
+
new Request("https://example.com/.well-known/apgateway/hl:zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n"),
|
|
136
|
+
gatewayRequest("/users/alice/notes/123", {
|
|
137
|
+
method: "POST",
|
|
138
|
+
body: "{}"
|
|
139
|
+
})
|
|
140
|
+
]) {
|
|
141
|
+
let notFound = false;
|
|
142
|
+
assertEquals((await federation.fetch(request, {
|
|
143
|
+
contextData: void 0,
|
|
144
|
+
onNotFound() {
|
|
145
|
+
notFound = true;
|
|
146
|
+
return new Response("Not found", { status: 404 });
|
|
147
|
+
}
|
|
148
|
+
})).status, 404);
|
|
149
|
+
assertEquals(notFound, true, request.url);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
await t.step("responds to HEAD without a body on errors", async () => {
|
|
153
|
+
for (const [request, status] of [[gatewayRequest("/users/alice/notes/missing", { method: "HEAD" }), 404], [gatewayRequest("/users/alice/notes/123", {
|
|
154
|
+
method: "HEAD",
|
|
155
|
+
headers: { Accept: "text/html" }
|
|
156
|
+
}), 406]]) {
|
|
157
|
+
const response = await federation.fetch(request, { contextData: void 0 });
|
|
158
|
+
assertEquals(response.status, status);
|
|
159
|
+
assertEquals(response.body, null);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
await t.step("responds with 406 without a JSON-LD Accept header", async () => {
|
|
163
|
+
assertEquals((await federation.fetch(gatewayRequest("/users/alice/notes/123", { headers: { Accept: "text/html" } }), { contextData: void 0 })).status, 406);
|
|
164
|
+
});
|
|
165
|
+
await t.step("keeps ordinary object requests unchanged", async () => {
|
|
166
|
+
const response = await federation.fetch(new Request("https://example.com/users/alice/notes/https", { headers: { Accept: ACCEPT } }), { contextData: void 0 });
|
|
167
|
+
assertEquals(response.status, 200);
|
|
168
|
+
assertEquals(response.headers.get("Content-Type"), "application/activity+json");
|
|
169
|
+
assertEquals((await response.json()).id, "https://example.com/users/alice/notes/https");
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
test("Federation.fetch() applies the FEP-ef61 proof policy to portable objects", async (t) => {
|
|
173
|
+
const federation = createTestFederation();
|
|
174
|
+
const objects = {
|
|
175
|
+
"valid": () => signedNote("/objects/valid"),
|
|
176
|
+
"unsigned": () => Promise.resolve(new Note({ id: parseIri(`ap+ef61://${did}/objects/unsigned`) })),
|
|
177
|
+
"wrong-did": () => sign(new Note({ id: parseIri(`ap+ef61://${did}/objects/wrong-did`) }), otherKeyPair.privateKey, otherKeyId),
|
|
178
|
+
"tampered": async () => (await signedNote("/objects/tampered")).clone({ content: "Tampered" }),
|
|
179
|
+
"unsigned-collection": () => Promise.resolve(new Collection({
|
|
180
|
+
id: parseIri(`ap+ef61://${did}/objects/unsigned-collection`),
|
|
181
|
+
totalItems: 0
|
|
182
|
+
})),
|
|
183
|
+
"aliased-collection": () => Collection.fromJsonLd({
|
|
184
|
+
"@context": ["https://www.w3.org/ns/activitystreams", { "identifier": "@id" }],
|
|
185
|
+
type: "Collection",
|
|
186
|
+
identifier: `ap+ef61://${did}/objects/aliased-collection`,
|
|
187
|
+
totalItems: 0
|
|
188
|
+
}, {
|
|
189
|
+
contextLoader: mockDocumentLoader,
|
|
190
|
+
documentLoader: mockDocumentLoader
|
|
191
|
+
}),
|
|
192
|
+
"tampered-collection": async () => (await sign(new Collection({
|
|
193
|
+
id: parseIri(`ap+ef61://${did}/objects/tampered-collection`),
|
|
194
|
+
totalItems: 0
|
|
195
|
+
}))).clone({ totalItems: 1 }),
|
|
196
|
+
"activity": () => sign(new Create({
|
|
197
|
+
id: parseIri(`ap+ef61://${did}/objects/activity`),
|
|
198
|
+
actor: parseIri(`ap+ef61://${did}/actor`),
|
|
199
|
+
object: parseIri(`ap+ef61://${did}/objects/valid`)
|
|
200
|
+
})),
|
|
201
|
+
"actor": () => sign(new Person({
|
|
202
|
+
id: parseIri(`ap+ef61://${did}/objects/actor`),
|
|
203
|
+
inbox: parseIri(`ap+ef61://${did}/objects/actor/inbox`),
|
|
204
|
+
outbox: parseIri(`ap+ef61://${did}/objects/actor/outbox`),
|
|
205
|
+
gateways: [new URL("https://example.com/")]
|
|
206
|
+
})),
|
|
207
|
+
"mutated-id": async () => {
|
|
208
|
+
const signed = await signedNote("/objects/original");
|
|
209
|
+
const object = await Note.fromJsonLd(await signed.toJsonLd({ contextLoader: mockDocumentLoader }), {
|
|
210
|
+
contextLoader: mockDocumentLoader,
|
|
211
|
+
documentLoader: mockDocumentLoader
|
|
212
|
+
});
|
|
213
|
+
object.id.pathname = "/objects/mutated-id";
|
|
214
|
+
return object;
|
|
215
|
+
},
|
|
216
|
+
"unsigned-actor": () => Promise.resolve(new Person({
|
|
217
|
+
id: parseIri(`ap+ef61://${did}/objects/unsigned-actor`),
|
|
218
|
+
inbox: parseIri(`ap+ef61://${did}/objects/unsigned-actor/inbox`),
|
|
219
|
+
outbox: parseIri(`ap+ef61://${did}/objects/unsigned-actor/outbox`),
|
|
220
|
+
gateways: [new URL("https://example.com/")]
|
|
221
|
+
}))
|
|
222
|
+
};
|
|
223
|
+
federation.setObjectDispatcher(Object$1, "/objects/{id}", (_ctx, { id }) => objects[id]?.() ?? null);
|
|
224
|
+
for (const [id, status] of globalThis.Object.entries({
|
|
225
|
+
"valid": 200,
|
|
226
|
+
"unsigned": 500,
|
|
227
|
+
"wrong-did": 500,
|
|
228
|
+
"tampered": 500,
|
|
229
|
+
"unsigned-collection": 200,
|
|
230
|
+
"aliased-collection": 200,
|
|
231
|
+
"tampered-collection": 500,
|
|
232
|
+
"activity": 200,
|
|
233
|
+
"actor": 200,
|
|
234
|
+
"mutated-id": 404,
|
|
235
|
+
"unsigned-actor": 500
|
|
236
|
+
})) await t.step(`${id} → ${status}`, async () => {
|
|
237
|
+
const response = await federation.fetch(gatewayRequest(`/objects/${id}`), { contextData: void 0 });
|
|
238
|
+
assertEquals(response.status, status);
|
|
239
|
+
if (status === 500) assertEquals(await response.text(), "Internal server error.");
|
|
240
|
+
});
|
|
241
|
+
await t.step("responds to HEAD without a body on failure", async () => {
|
|
242
|
+
const response = await federation.fetch(gatewayRequest("/objects/unsigned", { method: "HEAD" }), { contextData: void 0 });
|
|
243
|
+
assertEquals(response.status, 500);
|
|
244
|
+
assertEquals(response.body, null);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
test("Federation.fetch() authorizes portable object requests", async (t) => {
|
|
248
|
+
const federation = createTestFederation();
|
|
249
|
+
let dispatched = 0;
|
|
250
|
+
federation.setObjectDispatcher(Note, "/notes/{id}", (ctx, values) => {
|
|
251
|
+
dispatched++;
|
|
252
|
+
if (values.id === "unsigned") return new Note({ id: ctx.getPortableObjectUri(Note, values) });
|
|
253
|
+
return signedNote(`/notes/${values.id}`);
|
|
254
|
+
}).authorize(async (ctx) => {
|
|
255
|
+
assertEquals(ctx.portableRequest?.authority, did);
|
|
256
|
+
return (await ctx.getSignedKeyOwner())?.id?.href === "https://example.com/person2";
|
|
257
|
+
});
|
|
258
|
+
await t.step("allows a signed request by the audience", async () => {
|
|
259
|
+
const request = await signRequest(gatewayRequest("/notes/1"), rsaPrivateKey3, rsaPublicKey3.id);
|
|
260
|
+
assertEquals((await federation.fetch(request, { contextData: void 0 })).status, 200);
|
|
261
|
+
});
|
|
262
|
+
await t.step("denies an unsigned request", async () => {
|
|
263
|
+
assertEquals((await federation.fetch(gatewayRequest("/notes/1"), { contextData: void 0 })).status, 401);
|
|
264
|
+
});
|
|
265
|
+
await t.step("denies a request signed by someone else", async () => {
|
|
266
|
+
const request = await signRequest(gatewayRequest("/notes/1"), rsaPrivateKey2, rsaPublicKey2.id);
|
|
267
|
+
assertEquals((await federation.fetch(request, { contextData: void 0 })).status, 401);
|
|
268
|
+
});
|
|
269
|
+
await t.step("denies a request whose target was tampered with", async () => {
|
|
270
|
+
const signed = await signRequest(gatewayRequest("/notes/1"), rsaPrivateKey3, rsaPublicKey3.id);
|
|
271
|
+
assertEquals((await federation.fetch(new Request(gatewayUrl("/notes/2"), { headers: signed.headers }), { contextData: void 0 })).status, 401);
|
|
272
|
+
});
|
|
273
|
+
await t.step("authorizes before checking proofs", async () => {
|
|
274
|
+
dispatched = 0;
|
|
275
|
+
assertEquals((await federation.fetch(gatewayRequest("/notes/unsigned"), { contextData: void 0 })).status, 401);
|
|
276
|
+
assertEquals(dispatched, 1);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
test("Federation.fetch() lets application routes shadow the gateway", async () => {
|
|
280
|
+
const federation = createTestFederation();
|
|
281
|
+
const paths = [];
|
|
282
|
+
federation.setObjectDispatcher(Note, "/{+path}", (_ctx, { path }) => {
|
|
283
|
+
paths.push(path);
|
|
284
|
+
return null;
|
|
285
|
+
});
|
|
286
|
+
assertEquals((await federation.fetch(gatewayRequest("/notes/1"), { contextData: void 0 })).status, 404);
|
|
287
|
+
assertEquals(paths, [`.well-known/apgateway/${did}/notes/1`]);
|
|
288
|
+
});
|
|
289
|
+
test("Federation.fetch() compares portable IDs with the requested path", async () => {
|
|
290
|
+
const federation = createTestFederation();
|
|
291
|
+
federation.setObjectDispatcher(Note, "/notes/{id}", async (ctx, values) => {
|
|
292
|
+
if (values.id === "a/b") return await sign(new Note({ id: ctx.getPortableObjectUri(Note, values) }));
|
|
293
|
+
return await signedNote(`/notes/${values.id}`);
|
|
294
|
+
});
|
|
295
|
+
let response = await federation.fetch(gatewayRequest("/notes/a%2Fb"), { contextData: void 0 });
|
|
296
|
+
assertEquals(response.status, 200);
|
|
297
|
+
assertEquals((await response.json()).id, `ap+ef61://${did}/notes/a%2Fb`);
|
|
298
|
+
const tolerant = createFederation({
|
|
299
|
+
kv: new MemoryKvStore(),
|
|
300
|
+
documentLoaderFactory: () => mockDocumentLoader,
|
|
301
|
+
contextLoaderFactory: () => mockDocumentLoader,
|
|
302
|
+
trailingSlashInsensitive: true
|
|
303
|
+
});
|
|
304
|
+
tolerant.setObjectDispatcher(Note, "/notes/{id}", (_ctx, values) => signedNote(`/notes/${values.id}`));
|
|
305
|
+
response = await tolerant.fetch(gatewayRequest("/notes/1/"), { contextData: void 0 });
|
|
306
|
+
assertEquals(response.status, 404);
|
|
307
|
+
});
|
|
308
|
+
test("RequestContext.portableRequest", async (t) => {
|
|
309
|
+
const federation = createTestFederation();
|
|
310
|
+
const contexts = [];
|
|
311
|
+
federation.setObjectDispatcher(Tombstone, "/tombstones/{id}", (ctx) => {
|
|
312
|
+
contexts.push(ctx);
|
|
313
|
+
return null;
|
|
314
|
+
});
|
|
315
|
+
federation.setObjectDispatcher(Note, "/notes/{id}", async (ctx, values) => {
|
|
316
|
+
contexts.push(ctx);
|
|
317
|
+
ctx.portableRequest.id.pathname = "/notes/other";
|
|
318
|
+
await ctx.getObject(Tombstone, { id: values.id });
|
|
319
|
+
contexts.push(ctx.clone(void 0));
|
|
320
|
+
return await sign(new Note({ id: ctx.getPortableObjectUri(Note, values) }));
|
|
321
|
+
});
|
|
322
|
+
assertEquals((await federation.fetch(gatewayRequest("/notes/1"), { contextData: void 0 })).status, 200);
|
|
323
|
+
await t.step("is frozen and returns a new URL each time", () => {
|
|
324
|
+
const [ctx] = contexts;
|
|
325
|
+
const portableRequest = ctx.portableRequest;
|
|
326
|
+
assertEquals(globalThis.Object.isFrozen(portableRequest), true);
|
|
327
|
+
assertEquals(formatIri(portableRequest.id), `ap+ef61://${did}/notes/1`);
|
|
328
|
+
assertInstanceOf(portableRequest.id, URL);
|
|
329
|
+
const first = portableRequest.id;
|
|
330
|
+
const second = portableRequest.id;
|
|
331
|
+
assertEquals(first === second, false);
|
|
332
|
+
});
|
|
333
|
+
await t.step("is kept by derived contexts", () => {
|
|
334
|
+
assertEquals(contexts.length, 3);
|
|
335
|
+
assertStrictEquals(contexts[1].portableRequest, contexts[0].portableRequest);
|
|
336
|
+
assertStrictEquals(contexts[2].portableRequest, contexts[0].portableRequest);
|
|
337
|
+
});
|
|
338
|
+
await t.step("is undefined for ordinary requests", () => {
|
|
339
|
+
assertEquals(federation.createContext(new Request("https://example.com/notes/1"), void 0).portableRequest, void 0);
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
test("Context.getPortableObjectUri()", async (t) => {
|
|
343
|
+
const federation = createTestFederation();
|
|
344
|
+
federation.setObjectDispatcher(Note, "/users/{userId}/notes/{noteId}", () => null);
|
|
345
|
+
const ctx = federation.createContext(new URL("https://example.com/"), void 0);
|
|
346
|
+
const values = {
|
|
347
|
+
userId: "alice",
|
|
348
|
+
noteId: "123"
|
|
349
|
+
};
|
|
350
|
+
await t.step("builds a portable ID from the object path", () => {
|
|
351
|
+
const uri = ctx.getPortableObjectUri(Note, values, did);
|
|
352
|
+
assertInstanceOf(uri, URL);
|
|
353
|
+
assertEquals(uri.protocol, "ap+ef61:");
|
|
354
|
+
assertEquals(formatIri(uri), `ap+ef61://${did}/users/alice/notes/123`);
|
|
355
|
+
assertEquals(ctx.getObjectUri(Note, values), new URL("https://example.com/users/alice/notes/123"));
|
|
356
|
+
});
|
|
357
|
+
await t.step("requires a bare DID authority", () => {
|
|
358
|
+
for (const authority of [
|
|
359
|
+
`${did}/extra`,
|
|
360
|
+
`${did}?query`,
|
|
361
|
+
`${did}#fragment`,
|
|
362
|
+
"did:key:",
|
|
363
|
+
"https://example.com",
|
|
364
|
+
""
|
|
365
|
+
]) assertThrows(() => ctx.getPortableObjectUri(Note, values, authority), TypeError, void 0, authority);
|
|
366
|
+
});
|
|
367
|
+
await t.step("requires an authority outside gateway requests", () => {
|
|
368
|
+
const requestCtx = federation.createContext(new Request("https://example.com/"), void 0);
|
|
369
|
+
assertThrows(() => requestCtx.getPortableObjectUri(Note, values), TypeError);
|
|
370
|
+
assertEquals(formatIri(requestCtx.getPortableObjectUri(Note, values, did)), `ap+ef61://${did}/users/alice/notes/123`);
|
|
371
|
+
});
|
|
372
|
+
await t.step("validates values like getObjectUri()", () => {
|
|
373
|
+
assertThrows(() => ctx.getPortableObjectUri(Note, { userId: "alice" }, did), TypeError);
|
|
374
|
+
assertThrows(() => ctx.getPortableObjectUri(Person, values, did));
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
test("Federation.fetch() serves portable actors through WebFinger", async () => {
|
|
378
|
+
const federation = createTestFederation();
|
|
379
|
+
const getActor = async (ctx, name) => {
|
|
380
|
+
if (name !== "alice") return null;
|
|
381
|
+
return await sign(new Person({
|
|
382
|
+
id: ctx.getPortableObjectUri(Person, { name }, did),
|
|
383
|
+
preferredUsername: name,
|
|
384
|
+
gateways: [new URL("https://example.com")]
|
|
385
|
+
}));
|
|
386
|
+
};
|
|
387
|
+
federation.setActorDispatcher("/users/{identifier}", (ctx, identifier) => getActor(ctx, identifier)).mapHandle((_ctx, username) => username);
|
|
388
|
+
federation.setObjectDispatcher(Person, "/actors/{name}", (ctx, values) => ctx.portableRequest?.authority === did ? getActor(ctx, values.name) : null);
|
|
389
|
+
const webFinger = await federation.fetch(new Request("https://example.com/.well-known/webfinger?resource=acct:alice@example.com"), { contextData: void 0 });
|
|
390
|
+
assertEquals(webFinger.status, 200);
|
|
391
|
+
const jrd = await webFinger.json();
|
|
392
|
+
const compatibleId = gatewayUrl("/actors/alice");
|
|
393
|
+
assertEquals(jrd.subject, "acct:alice@example.com");
|
|
394
|
+
assertEquals(jrd.links?.[0], {
|
|
395
|
+
rel: "self",
|
|
396
|
+
href: compatibleId,
|
|
397
|
+
type: "application/activity+json"
|
|
398
|
+
});
|
|
399
|
+
const documentLoader = async (url) => {
|
|
400
|
+
const response = await federation.fetch(new Request(url, { headers: { Accept: ACCEPT } }), { contextData: void 0 });
|
|
401
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}: ${url}`);
|
|
402
|
+
return {
|
|
403
|
+
contextUrl: null,
|
|
404
|
+
documentUrl: url,
|
|
405
|
+
document: await response.json()
|
|
406
|
+
};
|
|
407
|
+
};
|
|
408
|
+
const actor = await lookupObject(compatibleId, {
|
|
409
|
+
documentLoader,
|
|
410
|
+
contextLoader: mockDocumentLoader,
|
|
411
|
+
verifyPortableObject: verifyPortableObjectProof
|
|
412
|
+
});
|
|
413
|
+
assertInstanceOf(actor, Person);
|
|
414
|
+
assertEquals(formatIri(actor.id), `ap+ef61://${did}/actors/alice`);
|
|
415
|
+
assertEquals(actor.preferredUsername, "alice");
|
|
416
|
+
const ctx = federation.createContext(new URL("https://example.com/"), void 0);
|
|
417
|
+
assertInstanceOf(await ctx.lookupObject(compatibleId, { documentLoader }), Person);
|
|
418
|
+
const unsigned = {
|
|
419
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
420
|
+
id: `ap://${did}/actors/alice`,
|
|
421
|
+
type: "Person"
|
|
422
|
+
};
|
|
423
|
+
assertEquals(await ctx.lookupObject(compatibleId, { documentLoader: (url) => Promise.resolve({
|
|
424
|
+
contextUrl: null,
|
|
425
|
+
documentUrl: url,
|
|
426
|
+
document: unsigned
|
|
427
|
+
}) }), null);
|
|
428
|
+
});
|
|
429
|
+
//#endregion
|
|
430
|
+
export {};
|
|
@@ -10,10 +10,10 @@ import { t as assertNotEquals } from "../assert_not_equals-CpPK2t89.mjs";
|
|
|
10
10
|
import "../std__assert-DvMDRPes.mjs";
|
|
11
11
|
import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
|
|
12
12
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
13
|
-
import { l as verifyRequest } from "../http-
|
|
13
|
+
import { l as verifyRequest } from "../http-CK6kjLnO.mjs";
|
|
14
14
|
import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
|
|
15
|
-
import { t as doesActorOwnKey } from "../owner-
|
|
16
|
-
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-
|
|
15
|
+
import { t as doesActorOwnKey } from "../owner-B3PgGiJ1.mjs";
|
|
16
|
+
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-BqBILxYE.mjs";
|
|
17
17
|
import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
|
|
18
18
|
import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
19
19
|
import { FetchError, UrlError } from "@fedify/vocab-runtime";
|
|
@@ -3,8 +3,8 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as MemoryKvStore } from "../../kv-DCHkaJ9-.mjs";
|
|
5
5
|
import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, t as MockQueue } from "../../tasks-dbCShlCb.mjs";
|
|
6
|
-
import "../../testing-
|
|
7
|
-
import { o as createFederation } from "../../middleware-
|
|
6
|
+
import "../../testing-By1YYsIK.mjs";
|
|
7
|
+
import { o as createFederation } from "../../middleware-CtFNjIUD.mjs";
|
|
8
8
|
import { n as ParallelMessageQueue } from "../../mq-Dm1Wmtm-.mjs";
|
|
9
9
|
import { configure, reset } from "@logtape/logtape";
|
|
10
10
|
import { delay } from "es-toolkit";
|
|
@@ -3,9 +3,9 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as MemoryKvStore } from "../../kv-DCHkaJ9-.mjs";
|
|
5
5
|
import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, t as MockQueue } from "../../tasks-dbCShlCb.mjs";
|
|
6
|
-
import "../../testing-
|
|
7
|
-
import { o as createFederation } from "../../middleware-
|
|
8
|
-
import { r as createFederationBuilder } from "../../builder-
|
|
6
|
+
import "../../testing-By1YYsIK.mjs";
|
|
7
|
+
import { o as createFederation } from "../../middleware-CtFNjIUD.mjs";
|
|
8
|
+
import { r as createFederationBuilder } from "../../builder-Cue1kVHU.mjs";
|
|
9
9
|
import { t as TaskCodec } from "../../codec-C6rTrpIp.mjs";
|
|
10
10
|
import { t as InProcessMessageQueue } from "../../mq-Dm1Wmtm-.mjs";
|
|
11
11
|
import { W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
|
|
|
4
4
|
import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
|
|
5
5
|
import "../std__assert-DvMDRPes.mjs";
|
|
6
6
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
7
|
-
import { t as hasMalformedKnownTemporalLiteral } from "../temporal-
|
|
7
|
+
import { t as hasMalformedKnownTemporalLiteral } from "../temporal-SUiLJ0Co.mjs";
|
|
8
8
|
import { test } from "@fedify/fixture";
|
|
9
9
|
//#region src/federation/temporal.test.ts
|
|
10
10
|
test("hasMalformedKnownTemporalLiteral() detects expanded proof timestamps", async () => {
|