@fedify/fedify 2.4.0-dev.1599 → 2.4.0-dev.1618
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-BvCI7Xch.mjs → builder-C4a7TAvq.mjs} +24 -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/{context-C7Sbmci2.mjs → context-BJXxPElm.mjs} +2 -1
- package/dist/{context-GfQA-CqB.d.ts → context-Zii1f5xS.d.ts} +97 -1
- package/dist/{context-BLe0NPtZ.d.cts → context-lxX6I7as.d.cts} +97 -1
- package/dist/{deno-BCt09TJn.mjs → deno-DepnPEgI.mjs} +1 -1
- package/dist/{docloader-BrRjFwOp.mjs → docloader-C_IefWRb.mjs} +2 -2
- package/dist/federation/builder.test.mjs +11 -1
- package/dist/federation/handler.test.mjs +4 -4
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +456 -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/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/{http-yainOC9t.mjs → http-CT7tcVBN.mjs} +3 -3
- package/dist/{http-zJsVCnKu.cjs → http-D5ylizT7.cjs} +1 -1
- package/dist/{http--wLYmH1x.js → http-DD07Erm7.js} +1 -1
- package/dist/{key-DcLwG7x4.mjs → key-C3t-PS3M.mjs} +2 -2
- package/dist/{kv-cache-0TGAGm8S.js → kv-cache-Bvv7Wp8h.js} +1 -1
- package/dist/{kv-cache-SZL9uu3V.mjs → kv-cache-CK273Baz.mjs} +1 -1
- package/dist/{kv-cache-BPu_M3-N.cjs → kv-cache-DbFdquuM.cjs} +1 -1
- package/dist/{ld-B-jskR-q.mjs → ld-D8wAPjxC.mjs} +3 -3
- package/dist/{metrics-C-pKLuAU.mjs → metrics-D1NrDWq-.mjs} +1 -1
- package/dist/{middleware-DGEQ07xT.mjs → middleware-BRunoF2v.mjs} +232 -12
- package/dist/{middleware-HFQkD-r8.mjs → middleware-CaP0k3AD.mjs} +1 -1
- package/dist/{middleware-D1POKL1d.js → middleware-kQ-qwTDh.js} +245 -3
- package/dist/{middleware-DLzOFLD5.cjs → middleware-nmfhGFtV.cjs} +245 -3
- package/dist/{mod-Cmr39iWq.d.ts → mod-DLc2Ot6f.d.ts} +1 -1
- package/dist/{mod-B8Efb9qp.d.cts → mod-gOlPDuT8.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-CeJuB8wq.mjs → owner-BjdNNmKF.mjs} +2 -2
- package/dist/{proof-Bri1zUVM.js → proof--HiDnLAE.js} +14 -3
- package/dist/{proof-917XYw_e.mjs → proof-1Xy5Ur-T.mjs} +16 -4
- package/dist/{proof-BkQosXrd.cjs → proof-DcOiiLDF.cjs} +13 -2
- package/dist/{send-CDi3XQ0V.mjs → send-ClJ4UcZL.mjs} +3 -3
- 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 +138 -1
- package/dist/{temporal-jusSJxbN.mjs → temporal-wA-b1IAz.mjs} +1 -1
- package/dist/testing/mod.d.mts +96 -0
- package/dist/testing/mod.mjs +2 -2
- package/dist/{testing-C3vgUK0b.mjs → testing-CO7ftO8A.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,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
4
|
+
import { n as version, t as name } from "./deno-DepnPEgI.mjs";
|
|
5
5
|
import { t as ActivityListenerSet } from "./activity-listener-BtTSxZWA.mjs";
|
|
6
6
|
import { getLogger } from "@logtape/logtape";
|
|
7
7
|
import { Router, RouterError, assertPath } from "@fedify/uri-template";
|
|
@@ -55,6 +55,9 @@ var FederationBuilderImpl = class {
|
|
|
55
55
|
inboxErrorHandler;
|
|
56
56
|
outboxListenerErrorHandler;
|
|
57
57
|
outboxAuthorizePredicate;
|
|
58
|
+
mediaUploaderPath;
|
|
59
|
+
mediaUploaderCallback;
|
|
60
|
+
mediaUploaderAuthorizePredicate;
|
|
58
61
|
sharedInboxKeyDispatcher;
|
|
59
62
|
unverifiedActivityHandler;
|
|
60
63
|
outboxPermanentFailureHandler;
|
|
@@ -82,7 +85,7 @@ var FederationBuilderImpl = class {
|
|
|
82
85
|
* specified.
|
|
83
86
|
*/
|
|
84
87
|
async build(options) {
|
|
85
|
-
const { FederationImpl } = await import("./middleware-
|
|
88
|
+
const { FederationImpl } = await import("./middleware-CaP0k3AD.mjs");
|
|
86
89
|
const f = new FederationImpl(options);
|
|
87
90
|
const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
|
|
88
91
|
f.router = this.router.clone();
|
|
@@ -107,6 +110,9 @@ var FederationBuilderImpl = class {
|
|
|
107
110
|
f.inboxErrorHandler = this.inboxErrorHandler;
|
|
108
111
|
f.outboxListenerErrorHandler = this.outboxListenerErrorHandler;
|
|
109
112
|
f.outboxAuthorizePredicate = this.outboxAuthorizePredicate;
|
|
113
|
+
f.mediaUploaderPath = this.mediaUploaderPath;
|
|
114
|
+
f.mediaUploaderCallback = this.mediaUploaderCallback;
|
|
115
|
+
f.mediaUploaderAuthorizePredicate = this.mediaUploaderAuthorizePredicate;
|
|
110
116
|
f.sharedInboxKeyDispatcher = this.sharedInboxKeyDispatcher;
|
|
111
117
|
f.unverifiedActivityHandler = this.unverifiedActivityHandler;
|
|
112
118
|
f.outboxPermanentFailureHandler = this.outboxPermanentFailureHandler;
|
|
@@ -185,6 +191,10 @@ var FederationBuilderImpl = class {
|
|
|
185
191
|
if (actor.publicKeyId == null) logger.warn("You configured a key pairs dispatcher, but the actor does not have a publicKey property. Set the property with Context.getActorKeyPairs(identifier).");
|
|
186
192
|
if (actor.assertionMethodId == null) logger.warn("You configured a key pairs dispatcher, but the actor does not have an assertionMethod property. Set the property with Context.getActorKeyPairs(identifier).");
|
|
187
193
|
}
|
|
194
|
+
if (this.mediaUploaderCallback != null) {
|
|
195
|
+
if (actor.endpoints == null || actor.endpoints.uploadMedia == null) logger.warn("You configured a media uploader, but the actor does not have a endpoints.uploadMedia property. Set the property with Context.getMediaUploaderUri(identifier).");
|
|
196
|
+
else if (actor.endpoints.uploadMedia.href != context.getMediaUploaderUri(identifier).href) logger.warn("You configured a media uploader, but the actor's endpoints.uploadMedia property does not match the media upload endpoint URI. Set the property with Context.getMediaUploaderUri(identifier).");
|
|
197
|
+
}
|
|
188
198
|
return actor;
|
|
189
199
|
} };
|
|
190
200
|
this.actorCallbacks = callbacks;
|
|
@@ -397,6 +407,18 @@ var FederationBuilderImpl = class {
|
|
|
397
407
|
};
|
|
398
408
|
return setters;
|
|
399
409
|
}
|
|
410
|
+
setMediaUploader(path, callback) {
|
|
411
|
+
if (this.mediaUploaderCallback != null) throw new RouterError("Media uploader already set.");
|
|
412
|
+
assertPath(path);
|
|
413
|
+
this.router.add(path, "mediaUploader", identifierSingular);
|
|
414
|
+
this.mediaUploaderPath = path;
|
|
415
|
+
this.mediaUploaderCallback = callback;
|
|
416
|
+
const setters = { authorize: (predicate) => {
|
|
417
|
+
this.mediaUploaderAuthorizePredicate = predicate;
|
|
418
|
+
return setters;
|
|
419
|
+
} };
|
|
420
|
+
return setters;
|
|
421
|
+
}
|
|
400
422
|
setFollowingDispatcher(path, dispatcher) {
|
|
401
423
|
if (this.router.has("following")) throw new RouterError("Following collection dispatcher already set.");
|
|
402
424
|
assertPath(path);
|
package/dist/compat/mod.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import {
|
|
2
|
+
import { Rt as ActivityTransformer, n as Context } from "../context-lxX6I7as.cjs";
|
|
3
3
|
import { Activity } from "@fedify/vocab";
|
|
4
4
|
|
|
5
5
|
//#region src/compat/transformers.d.ts
|
package/dist/compat/mod.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import {
|
|
2
|
+
import { Rt as ActivityTransformer, n as Context } from "../context-Zii1f5xS.js";
|
|
3
3
|
import { Activity } from "@fedify/vocab";
|
|
4
4
|
|
|
5
5
|
//#region src/compat/transformers.d.ts
|
|
@@ -5,7 +5,7 @@ import { t as MemoryKvStore } from "../kv-CXBAok3k.mjs";
|
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-BV7oLMxm.mjs";
|
|
6
6
|
import { t as assertInstanceOf } from "../assert_instance_of-Q9KTBnrf.mjs";
|
|
7
7
|
import { t as assert } from "../assert-CJ1KXcvv.mjs";
|
|
8
|
-
import { b as autoIdAssigner, n as FederationImpl, y as actorDehydrator } from "../middleware-
|
|
8
|
+
import { b as autoIdAssigner, n as FederationImpl, y as actorDehydrator } from "../middleware-BRunoF2v.mjs";
|
|
9
9
|
import { Follow, Person } from "@fedify/vocab";
|
|
10
10
|
import { test } from "@fedify/fixture";
|
|
11
11
|
//#region src/compat/transformers.test.ts
|
|
@@ -66,7 +66,7 @@ const testDefinitions = [];
|
|
|
66
66
|
//#endregion
|
|
67
67
|
//#region src/testing/context.ts
|
|
68
68
|
function createContext(values) {
|
|
69
|
-
const { federation, url = new URL("http://example.com/"), canonicalOrigin, data, documentLoader, contextLoader, meterProvider, tracerProvider, clone, getNodeInfoUri, getActorUri, getObjectUri, getCollectionUri, getOutboxUri, getInboxUri, getFollowingUri, getFollowersUri, getLikedUri, getFeaturedUri, getFeaturedTagsUri, parseUri, getActorKeyPairs, getDocumentLoader, lookupObject: lookupObject$1, traverseCollection: traverseCollection$1, lookupNodeInfo, lookupWebFinger: lookupWebFinger$1, sendActivity, routeActivity, enqueueTask, enqueueTaskMany } = values;
|
|
69
|
+
const { federation, url = new URL("http://example.com/"), canonicalOrigin, data, documentLoader, contextLoader, meterProvider, tracerProvider, clone, getNodeInfoUri, getActorUri, getObjectUri, getCollectionUri, getOutboxUri, getMediaUploaderUri, getInboxUri, getFollowingUri, getFollowersUri, getLikedUri, getFeaturedUri, getFeaturedTagsUri, parseUri, getActorKeyPairs, getDocumentLoader, lookupObject: lookupObject$1, traverseCollection: traverseCollection$1, lookupNodeInfo, lookupWebFinger: lookupWebFinger$1, sendActivity, routeActivity, enqueueTask, enqueueTaskMany } = values;
|
|
70
70
|
function throwRouterError() {
|
|
71
71
|
throw new RouterError("Not implemented");
|
|
72
72
|
}
|
|
@@ -90,6 +90,7 @@ function createContext(values) {
|
|
|
90
90
|
getObjectUri: getObjectUri ?? throwRouterError,
|
|
91
91
|
getCollectionUri: getCollectionUri ?? throwRouterError,
|
|
92
92
|
getOutboxUri: getOutboxUri ?? throwRouterError,
|
|
93
|
+
getMediaUploaderUri: getMediaUploaderUri ?? throwRouterError,
|
|
93
94
|
getInboxUri: getInboxUri ?? throwRouterError,
|
|
94
95
|
getFollowingUri: getFollowingUri ?? throwRouterError,
|
|
95
96
|
getFollowersUri: getFollowersUri ?? throwRouterError,
|
|
@@ -231,6 +231,35 @@ type InboxListener<TContextData, TActivity extends Activity> = (context: InboxCo
|
|
|
231
231
|
*/
|
|
232
232
|
type OutboxListener<TContextData, TActivity extends Activity> = (context: OutboxContext<TContextData>, activity: TActivity) => void | Promise<void>;
|
|
233
233
|
/**
|
|
234
|
+
* A callback that finalizes a media upload posted to the media upload endpoint
|
|
235
|
+
* (the [ActivityPub Media Upload
|
|
236
|
+
* extension](https://www.w3.org/wiki/SocialCG/ActivityPub/MediaUpload)).
|
|
237
|
+
*
|
|
238
|
+
* The return value determines the HTTP response:
|
|
239
|
+
*
|
|
240
|
+
* - Returning a {@link Object} (the resource is fetchable right away) makes the
|
|
241
|
+
* endpoint respond with `201 Created` and a `Location` header pointing at the
|
|
242
|
+
* object's `id`.
|
|
243
|
+
* - Returning a {@link URL} (the resource is still being processed, e.g.
|
|
244
|
+
* transcoding) makes the endpoint respond with `202 Accepted` and a
|
|
245
|
+
* `Location` header pointing at the returned URL.
|
|
246
|
+
*
|
|
247
|
+
* @template TContextData The context data to pass to the {@link Context}.
|
|
248
|
+
* @param context The request context.
|
|
249
|
+
* @param identifier The identifier of the actor whose media upload endpoint
|
|
250
|
+
* received the request.
|
|
251
|
+
* @param file The uploaded file.
|
|
252
|
+
* @param object The parsed ActivityStreams object shell sent alongside the file.
|
|
253
|
+
* Since the client may send any subtype of {@link Object} and the
|
|
254
|
+
* shell lacks an `id`, the callback receives the base
|
|
255
|
+
* {@link Object} and narrows with `instanceof` as needed.
|
|
256
|
+
* @returns The finalized object (`201 Created`) or the URL at which it will
|
|
257
|
+
* become available (`202 Accepted`). It may be returned synchronously
|
|
258
|
+
* or wrapped in a `Promise`.
|
|
259
|
+
* @since 2.4.0
|
|
260
|
+
*/
|
|
261
|
+
type MediaUploaderCallback<TContextData> = (context: RequestContext<TContextData>, identifier: string, file: File, object: Object$1) => Object$1 | URL | Promise<Object$1 | URL>;
|
|
262
|
+
/**
|
|
234
263
|
* The reason why an incoming activity could not be verified.
|
|
235
264
|
*
|
|
236
265
|
* Unlike inbox listeners registered through {@link InboxListenerSetters.on},
|
|
@@ -1289,6 +1318,48 @@ interface Federatable<TContextData> extends TaskRegistry<TContextData> {
|
|
|
1289
1318
|
*/
|
|
1290
1319
|
setOutboxListeners(outboxPath: `${string}${Rfc6570Expression<"identifier">}${string}`): OutboxListenerSetters<TContextData>;
|
|
1291
1320
|
/**
|
|
1321
|
+
* Registers a media upload endpoint for the [ActivityPub Media Upload
|
|
1322
|
+
* extension](https://www.w3.org/wiki/SocialCG/ActivityPub/MediaUpload).
|
|
1323
|
+
* Clients `POST` a `multipart/form-data` request with a `file` part (the
|
|
1324
|
+
* binary payload) and an `object` part (an ActivityStreams object shell) to
|
|
1325
|
+
* this endpoint. The actor should advertise this endpoint under
|
|
1326
|
+
* `endpoints.uploadMedia` using {@link Context.getMediaUploaderUri}.
|
|
1327
|
+
*
|
|
1328
|
+
* @example
|
|
1329
|
+
* ``` typescript
|
|
1330
|
+
* federation
|
|
1331
|
+
* .setMediaUploader(
|
|
1332
|
+
* "/users/{identifier}/media",
|
|
1333
|
+
* async (ctx, identifier, file, object) => {
|
|
1334
|
+
* const stored = await uploadToStorage(file);
|
|
1335
|
+
* return new Image({
|
|
1336
|
+
* id: ctx.getObjectUri(Image, { uuid: stored.uuid }),
|
|
1337
|
+
* url: new URL(stored.publicUrl),
|
|
1338
|
+
* mediaType: file.type,
|
|
1339
|
+
* name: object.name,
|
|
1340
|
+
* });
|
|
1341
|
+
* },
|
|
1342
|
+
* )
|
|
1343
|
+
* .authorize(async (ctx, identifier) => {
|
|
1344
|
+
* return ctx.request.headers.get("authorization") === `Bearer ${identifier}`;
|
|
1345
|
+
* });
|
|
1346
|
+
* ```
|
|
1347
|
+
*
|
|
1348
|
+
* @param path The URI path pattern for the media upload endpoint. The syntax
|
|
1349
|
+
* is based on URI Template
|
|
1350
|
+
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
|
|
1351
|
+
* must have one variable: `{identifier}`.
|
|
1352
|
+
* @param callback A callback that finalizes the uploaded media and returns
|
|
1353
|
+
* either the created {@link Object} (`201 Created`) or the
|
|
1354
|
+
* {@link URL} at which it will become available
|
|
1355
|
+
* (`202 Accepted`).
|
|
1356
|
+
* @returns An object to configure the media upload endpoint.
|
|
1357
|
+
* @throws {RouterError} Thrown if the path pattern is invalid or a media
|
|
1358
|
+
* uploader is already registered.
|
|
1359
|
+
* @since 2.4.0
|
|
1360
|
+
*/
|
|
1361
|
+
setMediaUploader(path: `${string}${Rfc6570Expression<"identifier">}${string}`, callback: MediaUploaderCallback<TContextData>): MediaUploaderSetters<TContextData>;
|
|
1362
|
+
/**
|
|
1292
1363
|
* Registers a following collection dispatcher.
|
|
1293
1364
|
* @param path The URI path pattern for the following collection. The syntax
|
|
1294
1365
|
* is based on URI Template
|
|
@@ -2053,6 +2124,21 @@ interface OutboxListenerSetters<TContextData> {
|
|
|
2053
2124
|
authorize(predicate: AuthorizePredicate<TContextData>): OutboxListenerSetters<TContextData>;
|
|
2054
2125
|
}
|
|
2055
2126
|
/**
|
|
2127
|
+
* An object to configure the media upload endpoint registered through
|
|
2128
|
+
* {@link Federatable.setMediaUploader}.
|
|
2129
|
+
* @since 2.4.0
|
|
2130
|
+
*/
|
|
2131
|
+
interface MediaUploaderSetters<TContextData> {
|
|
2132
|
+
/**
|
|
2133
|
+
* Registers a callback to authorize requests to the media upload endpoint.
|
|
2134
|
+
*
|
|
2135
|
+
* @param predicate A callback to authorize the request.
|
|
2136
|
+
* @returns The setters object so that settings can be chained.
|
|
2137
|
+
* @since 2.4.0
|
|
2138
|
+
*/
|
|
2139
|
+
authorize(predicate: AuthorizePredicate<TContextData>): MediaUploaderSetters<TContextData>;
|
|
2140
|
+
}
|
|
2141
|
+
/**
|
|
2056
2142
|
* Registry for inbox listeners for different activity types.
|
|
2057
2143
|
*/
|
|
2058
2144
|
interface InboxListenerSetters<TContextData> {
|
|
@@ -2352,6 +2438,16 @@ interface Context<TContextData> {
|
|
|
2352
2438
|
*/
|
|
2353
2439
|
getOutboxUri(identifier: string): URL;
|
|
2354
2440
|
/**
|
|
2441
|
+
* Builds the URI of an actor's media upload endpoint with the given
|
|
2442
|
+
* identifier. This is the endpoint advertised under `endpoints.uploadMedia`
|
|
2443
|
+
* in the actor document.
|
|
2444
|
+
* @param identifier The actor's identifier.
|
|
2445
|
+
* @returns The actor's media upload endpoint URI.
|
|
2446
|
+
* @throws {RouterError} If no media uploader is registered.
|
|
2447
|
+
* @since 2.4.0
|
|
2448
|
+
*/
|
|
2449
|
+
getMediaUploaderUri(identifier: string): URL;
|
|
2450
|
+
/**
|
|
2355
2451
|
* Builds the URI of the shared inbox.
|
|
2356
2452
|
* @returns The shared inbox URI.
|
|
2357
2453
|
* @throws {RouterError} If no inbox listener is available.
|
|
@@ -3154,4 +3250,4 @@ interface ActorKeyPair extends CryptoKeyPair {
|
|
|
3154
3250
|
readonly multikey: Multikey;
|
|
3155
3251
|
}
|
|
3156
3252
|
//#endregion
|
|
3157
|
-
export {
|
|
3253
|
+
export { CircuitBreakerCreateOptions as $, OutboxListenerSetters as A, UnverifiedActivityHandler as At, TaskEnqueueOptions as B, FederationStartQueueOptions as C, ObjectAuthorizePredicate as Ct, InboxListenerSetters as D, OutboxListenerErrorHandler as Dt, InboxChallengePolicy as E, OutboxListener as Et, createFederation as F, PageItems as Ft, RetryPolicy as G, TaskRegistry as H, Message as I, buildCollectionSynchronizationHeader as It, respondWithObject as J, createExponentialBackoffPolicy as K, createFederationBuilder as L, digest as Lt, FederationKvPrefixes as M, WebFingerLinksDispatcher as Mt, FederationOrigin as N, SendActivityError as Nt, MediaUploaderSetters as O, OutboxPermanentFailureHandler as Ot, FederationQueueOptions as P, SenderKeyPair as Pt, CircuitBreakerBeforeSendDecision as Q, TaskDefinition as R, ActivityTransformer as Rt, FederationOptions as S, NodeInfoDispatcher as St, IdempotencyStrategy as T, OutboxErrorHandler as Tt, CreateExponentialBackoffPolicyOptions as U, TaskHandler as V, RetryContext as W, CircuitBreaker as X, respondWithObjectIfAcceptable as Y, CircuitBreakerActivityDrop as Z, Federatable as _, CustomCollectionCursor as _t, GetSignedKeyOptions as a, NormalizedCircuitBreakerOptions as at, FederationBuilder as b, InboxListener as bt, ParseUriResult as c, ActorAliasMapper as ct, SendActivityOptions as d, ActorKeyPairsDispatcher as dt, CircuitBreakerFailurePolicy as et, SendActivityOptionsForCollection as f, AuthorizePredicate as ft, CustomCollectionCallbackSetters as g, CustomCollectionCounter as gt, ConstructorWithTypeId as h, CollectionDispatcher as ht, GetActorOptions as i, CircuitBreakerStateChange as it, Rfc6570Expression as j, UnverifiedActivityReason as jt, ObjectCallbackSetters as k, SharedInboxKeyDispatcher as kt, RequestContext as l, ActorDispatcher as lt, CollectionCallbackSetters as m, CollectionCursor as mt, Context as n, CircuitBreakerOptions as nt, InboxContext as o, normalizeCircuitBreakerOptions as ot, ActorCallbackSetters as p, CollectionCounter as pt, RespondWithObjectOptions as q, ForwardActivityOptions as r, CircuitBreakerState as rt, OutboxContext as s, parseCircuitBreakerKvState as st, ActorKeyPair as t, CircuitBreakerKvState as tt, RouteActivityOptions as u, ActorHandleMapper as ut, Federation as v, CustomCollectionDispatcher as vt, IdempotencyKeyCallback as w, ObjectDispatcher as wt, FederationFetchOptions as x, MediaUploaderCallback as xt, FederationBenchmarkOptions as y, InboxErrorHandler as yt, TaskDefinitionOptions as z };
|
|
@@ -229,6 +229,35 @@ type InboxListener<TContextData, TActivity extends Activity> = (context: InboxCo
|
|
|
229
229
|
*/
|
|
230
230
|
type OutboxListener<TContextData, TActivity extends Activity> = (context: OutboxContext<TContextData>, activity: TActivity) => void | Promise<void>;
|
|
231
231
|
/**
|
|
232
|
+
* A callback that finalizes a media upload posted to the media upload endpoint
|
|
233
|
+
* (the [ActivityPub Media Upload
|
|
234
|
+
* extension](https://www.w3.org/wiki/SocialCG/ActivityPub/MediaUpload)).
|
|
235
|
+
*
|
|
236
|
+
* The return value determines the HTTP response:
|
|
237
|
+
*
|
|
238
|
+
* - Returning a {@link Object} (the resource is fetchable right away) makes the
|
|
239
|
+
* endpoint respond with `201 Created` and a `Location` header pointing at the
|
|
240
|
+
* object's `id`.
|
|
241
|
+
* - Returning a {@link URL} (the resource is still being processed, e.g.
|
|
242
|
+
* transcoding) makes the endpoint respond with `202 Accepted` and a
|
|
243
|
+
* `Location` header pointing at the returned URL.
|
|
244
|
+
*
|
|
245
|
+
* @template TContextData The context data to pass to the {@link Context}.
|
|
246
|
+
* @param context The request context.
|
|
247
|
+
* @param identifier The identifier of the actor whose media upload endpoint
|
|
248
|
+
* received the request.
|
|
249
|
+
* @param file The uploaded file.
|
|
250
|
+
* @param object The parsed ActivityStreams object shell sent alongside the file.
|
|
251
|
+
* Since the client may send any subtype of {@link Object} and the
|
|
252
|
+
* shell lacks an `id`, the callback receives the base
|
|
253
|
+
* {@link Object} and narrows with `instanceof` as needed.
|
|
254
|
+
* @returns The finalized object (`201 Created`) or the URL at which it will
|
|
255
|
+
* become available (`202 Accepted`). It may be returned synchronously
|
|
256
|
+
* or wrapped in a `Promise`.
|
|
257
|
+
* @since 2.4.0
|
|
258
|
+
*/
|
|
259
|
+
type MediaUploaderCallback<TContextData> = (context: RequestContext<TContextData>, identifier: string, file: File, object: Object$1) => Object$1 | URL | Promise<Object$1 | URL>;
|
|
260
|
+
/**
|
|
232
261
|
* The reason why an incoming activity could not be verified.
|
|
233
262
|
*
|
|
234
263
|
* Unlike inbox listeners registered through {@link InboxListenerSetters.on},
|
|
@@ -1287,6 +1316,48 @@ interface Federatable<TContextData> extends TaskRegistry<TContextData> {
|
|
|
1287
1316
|
*/
|
|
1288
1317
|
setOutboxListeners(outboxPath: `${string}${Rfc6570Expression<"identifier">}${string}`): OutboxListenerSetters<TContextData>;
|
|
1289
1318
|
/**
|
|
1319
|
+
* Registers a media upload endpoint for the [ActivityPub Media Upload
|
|
1320
|
+
* extension](https://www.w3.org/wiki/SocialCG/ActivityPub/MediaUpload).
|
|
1321
|
+
* Clients `POST` a `multipart/form-data` request with a `file` part (the
|
|
1322
|
+
* binary payload) and an `object` part (an ActivityStreams object shell) to
|
|
1323
|
+
* this endpoint. The actor should advertise this endpoint under
|
|
1324
|
+
* `endpoints.uploadMedia` using {@link Context.getMediaUploaderUri}.
|
|
1325
|
+
*
|
|
1326
|
+
* @example
|
|
1327
|
+
* ``` typescript
|
|
1328
|
+
* federation
|
|
1329
|
+
* .setMediaUploader(
|
|
1330
|
+
* "/users/{identifier}/media",
|
|
1331
|
+
* async (ctx, identifier, file, object) => {
|
|
1332
|
+
* const stored = await uploadToStorage(file);
|
|
1333
|
+
* return new Image({
|
|
1334
|
+
* id: ctx.getObjectUri(Image, { uuid: stored.uuid }),
|
|
1335
|
+
* url: new URL(stored.publicUrl),
|
|
1336
|
+
* mediaType: file.type,
|
|
1337
|
+
* name: object.name,
|
|
1338
|
+
* });
|
|
1339
|
+
* },
|
|
1340
|
+
* )
|
|
1341
|
+
* .authorize(async (ctx, identifier) => {
|
|
1342
|
+
* return ctx.request.headers.get("authorization") === `Bearer ${identifier}`;
|
|
1343
|
+
* });
|
|
1344
|
+
* ```
|
|
1345
|
+
*
|
|
1346
|
+
* @param path The URI path pattern for the media upload endpoint. The syntax
|
|
1347
|
+
* is based on URI Template
|
|
1348
|
+
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
|
|
1349
|
+
* must have one variable: `{identifier}`.
|
|
1350
|
+
* @param callback A callback that finalizes the uploaded media and returns
|
|
1351
|
+
* either the created {@link Object} (`201 Created`) or the
|
|
1352
|
+
* {@link URL} at which it will become available
|
|
1353
|
+
* (`202 Accepted`).
|
|
1354
|
+
* @returns An object to configure the media upload endpoint.
|
|
1355
|
+
* @throws {RouterError} Thrown if the path pattern is invalid or a media
|
|
1356
|
+
* uploader is already registered.
|
|
1357
|
+
* @since 2.4.0
|
|
1358
|
+
*/
|
|
1359
|
+
setMediaUploader(path: `${string}${Rfc6570Expression<"identifier">}${string}`, callback: MediaUploaderCallback<TContextData>): MediaUploaderSetters<TContextData>;
|
|
1360
|
+
/**
|
|
1290
1361
|
* Registers a following collection dispatcher.
|
|
1291
1362
|
* @param path The URI path pattern for the following collection. The syntax
|
|
1292
1363
|
* is based on URI Template
|
|
@@ -2051,6 +2122,21 @@ interface OutboxListenerSetters<TContextData> {
|
|
|
2051
2122
|
authorize(predicate: AuthorizePredicate<TContextData>): OutboxListenerSetters<TContextData>;
|
|
2052
2123
|
}
|
|
2053
2124
|
/**
|
|
2125
|
+
* An object to configure the media upload endpoint registered through
|
|
2126
|
+
* {@link Federatable.setMediaUploader}.
|
|
2127
|
+
* @since 2.4.0
|
|
2128
|
+
*/
|
|
2129
|
+
interface MediaUploaderSetters<TContextData> {
|
|
2130
|
+
/**
|
|
2131
|
+
* Registers a callback to authorize requests to the media upload endpoint.
|
|
2132
|
+
*
|
|
2133
|
+
* @param predicate A callback to authorize the request.
|
|
2134
|
+
* @returns The setters object so that settings can be chained.
|
|
2135
|
+
* @since 2.4.0
|
|
2136
|
+
*/
|
|
2137
|
+
authorize(predicate: AuthorizePredicate<TContextData>): MediaUploaderSetters<TContextData>;
|
|
2138
|
+
}
|
|
2139
|
+
/**
|
|
2054
2140
|
* Registry for inbox listeners for different activity types.
|
|
2055
2141
|
*/
|
|
2056
2142
|
interface InboxListenerSetters<TContextData> {
|
|
@@ -2350,6 +2436,16 @@ interface Context<TContextData> {
|
|
|
2350
2436
|
*/
|
|
2351
2437
|
getOutboxUri(identifier: string): URL;
|
|
2352
2438
|
/**
|
|
2439
|
+
* Builds the URI of an actor's media upload endpoint with the given
|
|
2440
|
+
* identifier. This is the endpoint advertised under `endpoints.uploadMedia`
|
|
2441
|
+
* in the actor document.
|
|
2442
|
+
* @param identifier The actor's identifier.
|
|
2443
|
+
* @returns The actor's media upload endpoint URI.
|
|
2444
|
+
* @throws {RouterError} If no media uploader is registered.
|
|
2445
|
+
* @since 2.4.0
|
|
2446
|
+
*/
|
|
2447
|
+
getMediaUploaderUri(identifier: string): URL;
|
|
2448
|
+
/**
|
|
2353
2449
|
* Builds the URI of the shared inbox.
|
|
2354
2450
|
* @returns The shared inbox URI.
|
|
2355
2451
|
* @throws {RouterError} If no inbox listener is available.
|
|
@@ -3152,4 +3248,4 @@ interface ActorKeyPair extends CryptoKeyPair {
|
|
|
3152
3248
|
readonly multikey: Multikey;
|
|
3153
3249
|
}
|
|
3154
3250
|
//#endregion
|
|
3155
|
-
export {
|
|
3251
|
+
export { CircuitBreakerCreateOptions as $, OutboxListenerSetters as A, UnverifiedActivityHandler as At, TaskEnqueueOptions as B, FederationStartQueueOptions as C, ObjectAuthorizePredicate as Ct, InboxListenerSetters as D, OutboxListenerErrorHandler as Dt, InboxChallengePolicy as E, OutboxListener as Et, createFederation as F, PageItems as Ft, RetryPolicy as G, TaskRegistry as H, Message as I, buildCollectionSynchronizationHeader as It, respondWithObject as J, createExponentialBackoffPolicy as K, createFederationBuilder as L, digest as Lt, FederationKvPrefixes as M, WebFingerLinksDispatcher as Mt, FederationOrigin as N, SendActivityError as Nt, MediaUploaderSetters as O, OutboxPermanentFailureHandler as Ot, FederationQueueOptions as P, SenderKeyPair as Pt, CircuitBreakerBeforeSendDecision as Q, TaskDefinition as R, ActivityTransformer as Rt, FederationOptions as S, NodeInfoDispatcher as St, IdempotencyStrategy as T, OutboxErrorHandler as Tt, CreateExponentialBackoffPolicyOptions as U, TaskHandler as V, RetryContext as W, CircuitBreaker as X, respondWithObjectIfAcceptable as Y, CircuitBreakerActivityDrop as Z, Federatable as _, CustomCollectionCursor as _t, GetSignedKeyOptions as a, NormalizedCircuitBreakerOptions as at, FederationBuilder as b, InboxListener as bt, ParseUriResult as c, ActorAliasMapper as ct, SendActivityOptions as d, ActorKeyPairsDispatcher as dt, CircuitBreakerFailurePolicy as et, SendActivityOptionsForCollection as f, AuthorizePredicate as ft, CustomCollectionCallbackSetters as g, CustomCollectionCounter as gt, ConstructorWithTypeId as h, CollectionDispatcher as ht, GetActorOptions as i, CircuitBreakerStateChange as it, Rfc6570Expression as j, UnverifiedActivityReason as jt, ObjectCallbackSetters as k, SharedInboxKeyDispatcher as kt, RequestContext as l, ActorDispatcher as lt, CollectionCallbackSetters as m, CollectionCursor as mt, Context as n, CircuitBreakerOptions as nt, InboxContext as o, normalizeCircuitBreakerOptions as ot, ActorCallbackSetters as p, CollectionCounter as pt, RespondWithObjectOptions as q, ForwardActivityOptions as r, CircuitBreakerState as rt, OutboxContext as s, parseCircuitBreakerKvState as st, ActorKeyPair as t, CircuitBreakerKvState as tt, RouteActivityOptions as u, ActorHandleMapper as ut, Federation as v, CustomCollectionDispatcher as vt, IdempotencyKeyCallback as w, ObjectDispatcher as wt, FederationFetchOptions as x, MediaUploaderCallback as xt, FederationBenchmarkOptions as y, InboxErrorHandler as yt, TaskDefinitionOptions as z };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { o as validateCryptoKey } from "./key-
|
|
5
|
-
import { n as doubleKnock } from "./http-
|
|
4
|
+
import { o as validateCryptoKey } from "./key-C3t-PS3M.mjs";
|
|
5
|
+
import { n as doubleKnock } from "./http-CT7tcVBN.mjs";
|
|
6
6
|
import { getLogger } from "@logtape/logtape";
|
|
7
7
|
import { curry } from "es-toolkit";
|
|
8
8
|
import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
@@ -5,7 +5,7 @@ import { t as MemoryKvStore } from "../kv-CXBAok3k.mjs";
|
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-BV7oLMxm.mjs";
|
|
6
6
|
import { r as assertExists } from "../std__assert-B2NnY9bq.mjs";
|
|
7
7
|
import { t as assertThrows } from "../assert_throws-NiFfqbnH.mjs";
|
|
8
|
-
import { r as createFederationBuilder } from "../builder-
|
|
8
|
+
import { r as createFederationBuilder } from "../builder-C4a7TAvq.mjs";
|
|
9
9
|
import { DisallowedOperatorError, DisallowedVarSpecModifierError, DuplicateRouteVariableError, RouteTemplateOptionsNotMatchedError, RouterError } from "@fedify/uri-template";
|
|
10
10
|
import { Activity, Note, Person } from "@fedify/vocab";
|
|
11
11
|
import { test } from "@fedify/fixture";
|
|
@@ -142,6 +142,16 @@ test("FederationBuilder", async (t) => {
|
|
|
142
142
|
const builder5 = createFederationBuilder();
|
|
143
143
|
assertThrows(() => builder5.setOutboxDispatcher("/users/{identifier:3}/outbox", () => ({ items: [] })), DisallowedVarSpecModifierError);
|
|
144
144
|
});
|
|
145
|
+
await t.step("should validate media uploader paths", () => {
|
|
146
|
+
const noop = () => Promise.resolve(new URL("https://example.com/"));
|
|
147
|
+
const builder = createFederationBuilder();
|
|
148
|
+
builder.setMediaUploader("/users/{identifier}/media", noop);
|
|
149
|
+
assertThrows(() => builder.setMediaUploader("/users/{identifier}/media2", noop), RouterError);
|
|
150
|
+
assertThrows(() => createFederationBuilder().setMediaUploader("/users/media", noop), RouteTemplateOptionsNotMatchedError);
|
|
151
|
+
assertThrows(() => createFederationBuilder().setMediaUploader("/users/{identifier}/media/{extra}", noop), RouterError);
|
|
152
|
+
assertThrows(() => createFederationBuilder().setMediaUploader("/users/{identifier*}/media", noop), DisallowedVarSpecModifierError);
|
|
153
|
+
assertThrows(() => createFederationBuilder().setMediaUploader("/users{?identifier}/media", noop), DisallowedOperatorError);
|
|
154
|
+
});
|
|
145
155
|
await t.step("rejects non-segment-boundary identifier operators at registration for required-identifier routes", () => {
|
|
146
156
|
assertThrows(() => createFederationBuilder().setActorDispatcher("/users{/identifier}", () => null), DisallowedOperatorError);
|
|
147
157
|
assertThrows(() => createFederationBuilder().setActorDispatcher("{/identifier}", () => null), DisallowedOperatorError);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-
|
|
4
|
+
import { n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-BJXxPElm.mjs";
|
|
5
5
|
import { t as MemoryKvStore } from "../kv-CXBAok3k.mjs";
|
|
6
6
|
import { t as assertEquals } from "../assert_equals-BV7oLMxm.mjs";
|
|
7
7
|
import "../std__assert-B2NnY9bq.mjs";
|
|
@@ -9,10 +9,10 @@ import { n as assertGreaterOrEqual, t as assertRejects } from "../assert_rejects
|
|
|
9
9
|
import { t as assertInstanceOf } from "../assert_instance_of-Q9KTBnrf.mjs";
|
|
10
10
|
import { t as assert } from "../assert-CJ1KXcvv.mjs";
|
|
11
11
|
import { r as parseAcceptSignature } from "../accept-8PiolDP7.mjs";
|
|
12
|
-
import { s as signRequest } from "../http-
|
|
12
|
+
import { s as signRequest } from "../http-CT7tcVBN.mjs";
|
|
13
13
|
import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-Dbyd7bhl.mjs";
|
|
14
|
-
import { a as compactJsonLd, p as signJsonLd } from "../ld-
|
|
15
|
-
import { c as handleActor, d as handleInbox, f as handleObject, h as respondWithObjectIfAcceptable, l as handleCollection, m as respondWithObject, o as createFederation, p as handleOutbox, u as handleCustomCollection } from "../middleware-
|
|
14
|
+
import { a as compactJsonLd, p as signJsonLd } from "../ld-D8wAPjxC.mjs";
|
|
15
|
+
import { c as handleActor, d as handleInbox, f as handleObject, h as respondWithObjectIfAcceptable, l as handleCollection, m as respondWithObject, o as createFederation, p as handleOutbox, u as handleCustomCollection } from "../middleware-BRunoF2v.mjs";
|
|
16
16
|
import { t as ActivityListenerSet } from "../activity-listener-BtTSxZWA.mjs";
|
|
17
17
|
import { Activity, Create, Note, Person, Tombstone } from "@fedify/vocab";
|
|
18
18
|
import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
@@ -5,8 +5,8 @@ import { t as MemoryKvStore } from "../kv-CXBAok3k.mjs";
|
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-BV7oLMxm.mjs";
|
|
6
6
|
import "../std__assert-B2NnY9bq.mjs";
|
|
7
7
|
import { n as ed25519PrivateKey, r as ed25519PublicKey, t as ed25519Multikey } from "../keys-Dbyd7bhl.mjs";
|
|
8
|
-
import { r as signObject } from "../proof-
|
|
9
|
-
import { o as createFederation } from "../middleware-
|
|
8
|
+
import { r as signObject } from "../proof-1Xy5Ur-T.mjs";
|
|
9
|
+
import { o as createFederation } from "../middleware-BRunoF2v.mjs";
|
|
10
10
|
import { Create, Follow, Person } from "@fedify/vocab";
|
|
11
11
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
12
12
|
//#region src/federation/idempotency.test.ts
|
|
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
|
|
|
4
4
|
import { t as assertEquals } from "../assert_equals-BV7oLMxm.mjs";
|
|
5
5
|
import "../std__assert-B2NnY9bq.mjs";
|
|
6
6
|
import { t as assertRejects } from "../assert_rejects-EgstcQy5.mjs";
|
|
7
|
-
import { _ as recordKeyLookup, 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, m as recordDocumentFetch, p as recordDocumentCache, r as getFederationMetrics, t as classifyFetchError, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "../metrics-
|
|
7
|
+
import { _ as recordKeyLookup, 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, m as recordDocumentFetch, p as recordDocumentCache, r as getFederationMetrics, t as classifyFetchError, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "../metrics-D1NrDWq-.mjs";
|
|
8
8
|
import { createTestMeterProvider, test } from "@fedify/fixture";
|
|
9
9
|
import { FetchError } from "@fedify/vocab-runtime";
|
|
10
10
|
import { DataPointType, MeterProvider, MetricReader } from "@opentelemetry/sdk-metrics";
|