@fedify/fedify 0.7.0-dev.132 → 0.7.0-dev.134
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.
Potentially problematic release.
This version of @fedify/fedify might be problematic. Click here for more details.
- package/CHANGES.md +16 -1
- package/esm/federation/handler.js +23 -0
- package/esm/federation/middleware.js +85 -3
- package/esm/vocab/vocab.js +258 -0
- package/package.json +1 -1
- package/types/federation/callback.d.ts +27 -0
- package/types/federation/callback.d.ts.map +1 -1
- package/types/federation/context.d.ts +26 -1
- package/types/federation/context.d.ts.map +1 -1
- package/types/federation/handler.d.ts +11 -1
- package/types/federation/handler.d.ts.map +1 -1
- package/types/federation/middleware.d.ts +121 -7
- package/types/federation/middleware.d.ts.map +1 -1
- package/types/testing/context.d.ts.map +1 -1
- package/types/vocab/vocab.d.ts +172 -0
- package/types/vocab/vocab.d.ts.map +1 -1
package/CHANGES.md
CHANGED
@@ -26,7 +26,7 @@ To be released.
|
|
26
26
|
option now responds with `Vary: Accept, Signature` header.
|
27
27
|
|
28
28
|
- Added log messages using the [LogTape] library. Currently the below
|
29
|
-
categories are used:
|
29
|
+
logger categories are used:
|
30
30
|
|
31
31
|
- `["fedify"]`
|
32
32
|
- `["fedify", "federation"]`
|
@@ -35,9 +35,24 @@ To be released.
|
|
35
35
|
|
36
36
|
- Added `RequestContext.getActor()` method.
|
37
37
|
|
38
|
+
- Activity Vocabulary classes now have `typeId` static property.
|
39
|
+
|
40
|
+
- Dispatcher setters and inbox listener setters in `Federation` now take
|
41
|
+
a path as <code>`${string}{handle}${string}`</code> instead of `string`
|
42
|
+
so that it is more type-safe.
|
43
|
+
|
44
|
+
- Added generalized object dispatchers. [[#33]]
|
45
|
+
|
46
|
+
- Added `Federation.setObjectDispatcher()` method.
|
47
|
+
- Added `ObjectDispatcher` type.
|
48
|
+
- Added `ObjectAuthorizePredicate` type.
|
49
|
+
- Added `Context.getObjectUri()` method.
|
50
|
+
- Added `RequestContext.getObject()` method.
|
51
|
+
|
38
52
|
[public addressing]: https://www.w3.org/TR/activitypub/#public-addressing
|
39
53
|
[authorized fetch]: https://swicg.github.io/activitypub-http-signature/#authorized-fetch
|
40
54
|
[LogTape]: https://github.com/dahlia/logtape
|
55
|
+
[#33]: https://github.com/dahlia/fedify/issues/33
|
41
56
|
|
42
57
|
|
43
58
|
Version 0.6.1
|
@@ -38,6 +38,29 @@ export async function handleActor(request, { handle, context, actorDispatcher, a
|
|
38
38
|
},
|
39
39
|
});
|
40
40
|
}
|
41
|
+
export async function handleObject(request, { values, context, objectDispatcher, authorizePredicate, onNotFound, onNotAcceptable, onUnauthorized, }) {
|
42
|
+
if (objectDispatcher == null)
|
43
|
+
return await onNotFound(request);
|
44
|
+
const object = await objectDispatcher(context, values);
|
45
|
+
if (object == null)
|
46
|
+
return await onNotFound(request);
|
47
|
+
if (!acceptsJsonLd(request))
|
48
|
+
return await onNotAcceptable(request);
|
49
|
+
if (authorizePredicate != null) {
|
50
|
+
const key = await context.getSignedKey();
|
51
|
+
const keyOwner = await context.getSignedKeyOwner();
|
52
|
+
if (!await authorizePredicate(context, values, key, keyOwner)) {
|
53
|
+
return await onUnauthorized(request);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
const jsonLd = await object.toJsonLd(context);
|
57
|
+
return new Response(JSON.stringify(jsonLd), {
|
58
|
+
headers: {
|
59
|
+
"Content-Type": "application/activity+json",
|
60
|
+
Vary: "Accept",
|
61
|
+
},
|
62
|
+
});
|
63
|
+
}
|
41
64
|
export async function handleCollection(request, { handle, context, collectionCallbacks, onUnauthorized, onNotFound, onNotAcceptable, }) {
|
42
65
|
if (collectionCallbacks == null)
|
43
66
|
return await onNotFound(request);
|
@@ -7,7 +7,7 @@ import { handleNodeInfo, handleNodeInfoJrd } from "../nodeinfo/handler.js";
|
|
7
7
|
import { fetchDocumentLoader, getAuthenticatedDocumentLoader, kvCache, } from "../runtime/docloader.js";
|
8
8
|
import { Activity, CryptographicKey } from "../vocab/mod.js";
|
9
9
|
import { handleWebFinger } from "../webfinger/handler.js";
|
10
|
-
import { handleActor, handleCollection, handleInbox, } from "./handler.js";
|
10
|
+
import { handleActor, handleCollection, handleInbox, handleObject, } from "./handler.js";
|
11
11
|
import { Router, RouterError } from "./router.js";
|
12
12
|
import { extractInboxes, sendActivity } from "./send.js";
|
13
13
|
/**
|
@@ -25,6 +25,7 @@ export class Federation {
|
|
25
25
|
#router;
|
26
26
|
#nodeInfoDispatcher;
|
27
27
|
#actorCallbacks;
|
28
|
+
#objectCallbacks;
|
28
29
|
#outboxCallbacks;
|
29
30
|
#followingCallbacks;
|
30
31
|
#followersCallbacks;
|
@@ -54,6 +55,7 @@ export class Federation {
|
|
54
55
|
this.#router.add("/.well-known/webfinger", "webfinger");
|
55
56
|
this.#router.add("/.well-known/nodeinfo", "nodeInfoJrd");
|
56
57
|
this.#inboxListeners = new Map();
|
58
|
+
this.#objectCallbacks = {};
|
57
59
|
this.#documentLoader = documentLoader ?? kvCache({
|
58
60
|
loader: fetchDocumentLoader,
|
59
61
|
kv: kv,
|
@@ -179,6 +181,22 @@ export class Federation {
|
|
179
181
|
}
|
180
182
|
return new URL(path, url);
|
181
183
|
},
|
184
|
+
getObjectUri: (cls, values) => {
|
185
|
+
const callbacks = this.#objectCallbacks[cls.typeId.href];
|
186
|
+
if (callbacks == null) {
|
187
|
+
throw new RouterError("No object dispatcher registered.");
|
188
|
+
}
|
189
|
+
for (const param of callbacks.parameters) {
|
190
|
+
if (!(param in values)) {
|
191
|
+
throw new TypeError(`Missing parameter: ${param}`);
|
192
|
+
}
|
193
|
+
}
|
194
|
+
const path = this.#router.build(`object:${cls.typeId.href}`, values);
|
195
|
+
if (path == null) {
|
196
|
+
throw new RouterError("No object dispatcher registered.");
|
197
|
+
}
|
198
|
+
return new URL(path, url);
|
199
|
+
},
|
182
200
|
getOutboxUri: (handle) => {
|
183
201
|
const path = this.#router.build("outbox", { handle });
|
184
202
|
if (path == null) {
|
@@ -255,7 +273,7 @@ export class Federation {
|
|
255
273
|
this.#actorCallbacks.dispatcher == null) {
|
256
274
|
throw new Error("No actor dispatcher registered.");
|
257
275
|
}
|
258
|
-
return this.#actorCallbacks.dispatcher({
|
276
|
+
return await this.#actorCallbacks.dispatcher({
|
259
277
|
...reqCtx,
|
260
278
|
getActor(handle2) {
|
261
279
|
getLogger(["fedify", "federation"]).warn("RequestContext.getActor({getActorHandle}) is invoked from " +
|
@@ -265,6 +283,32 @@ export class Federation {
|
|
265
283
|
},
|
266
284
|
}, handle, await context.getActorKey(handle));
|
267
285
|
},
|
286
|
+
getObject: async (cls, values) => {
|
287
|
+
const callbacks = this.#objectCallbacks[cls.typeId.href];
|
288
|
+
if (callbacks == null) {
|
289
|
+
throw new Error("No object dispatcher registered.");
|
290
|
+
}
|
291
|
+
for (const param of callbacks.parameters) {
|
292
|
+
if (!(param in values)) {
|
293
|
+
throw new TypeError(`Missing parameter: ${param}`);
|
294
|
+
}
|
295
|
+
}
|
296
|
+
return await callbacks.dispatcher({
|
297
|
+
...reqCtx,
|
298
|
+
getObject(cls2, values2) {
|
299
|
+
getLogger(["fedify", "federation"]).warn("RequestContext.getObject({getObjectClass}, " +
|
300
|
+
"{getObjectValues}) is invoked from the object dispatcher " +
|
301
|
+
"({actorDispatcherClass}, {actorDispatcherValues}); " +
|
302
|
+
"this may cause an infinite loop.", {
|
303
|
+
getObjectClass: cls2.name,
|
304
|
+
getObjectValues: values2,
|
305
|
+
actorDispatcherClass: cls.name,
|
306
|
+
actorDispatcherValues: values,
|
307
|
+
});
|
308
|
+
return reqCtx.getObject(cls2, values2);
|
309
|
+
},
|
310
|
+
}, values);
|
311
|
+
},
|
268
312
|
async getSignedKey() {
|
269
313
|
if (signedKey !== undefined)
|
270
314
|
return signedKey;
|
@@ -348,6 +392,30 @@ export class Federation {
|
|
348
392
|
};
|
349
393
|
return setters;
|
350
394
|
}
|
395
|
+
setObjectDispatcher(
|
396
|
+
// deno-lint-ignore no-explicit-any
|
397
|
+
cls, path, dispatcher) {
|
398
|
+
const routeName = `object:${cls.typeId.href}`;
|
399
|
+
if (this.#router.has(routeName)) {
|
400
|
+
throw new RouterError(`Object dispatcher for ${cls.name} already set.`);
|
401
|
+
}
|
402
|
+
const variables = this.#router.add(path, routeName);
|
403
|
+
if (variables.size < 1) {
|
404
|
+
throw new RouterError("Path for object dispatcher must have at least one variable.");
|
405
|
+
}
|
406
|
+
const callbacks = {
|
407
|
+
dispatcher,
|
408
|
+
parameters: variables,
|
409
|
+
};
|
410
|
+
this.#objectCallbacks[cls.typeId.href] = callbacks;
|
411
|
+
const setters = {
|
412
|
+
authorize(predicate) {
|
413
|
+
callbacks.authorizePredicate = predicate;
|
414
|
+
return setters;
|
415
|
+
},
|
416
|
+
};
|
417
|
+
return setters;
|
418
|
+
}
|
351
419
|
/**
|
352
420
|
* Registers an outbox dispatcher.
|
353
421
|
*
|
@@ -632,6 +700,7 @@ export class Federation {
|
|
632
700
|
* @deprecated Use {@link Federation.fetch} instead.
|
633
701
|
*/
|
634
702
|
handle(request, options) {
|
703
|
+
getLogger(["fedify", "federation"]).warn("Federation.handle() is deprecated. Use Federation.fetch() instead.");
|
635
704
|
return this.fetch(request, options);
|
636
705
|
}
|
637
706
|
/**
|
@@ -657,7 +726,7 @@ export class Federation {
|
|
657
726
|
return response instanceof Promise ? await response : response;
|
658
727
|
}
|
659
728
|
let context = this.createContext(request, contextData);
|
660
|
-
switch (route.name) {
|
729
|
+
switch (route.name.replace(/:.*$/, "")) {
|
661
730
|
case "webfinger":
|
662
731
|
return await handleWebFinger(request, {
|
663
732
|
context,
|
@@ -681,6 +750,19 @@ export class Federation {
|
|
681
750
|
onNotFound,
|
682
751
|
onNotAcceptable,
|
683
752
|
});
|
753
|
+
case "object": {
|
754
|
+
const typeId = route.name.replace(/^object:/, "");
|
755
|
+
const callbacks = this.#objectCallbacks[typeId];
|
756
|
+
return await handleObject(request, {
|
757
|
+
values: route.values,
|
758
|
+
context,
|
759
|
+
objectDispatcher: callbacks?.dispatcher,
|
760
|
+
authorizePredicate: callbacks?.authorizePredicate,
|
761
|
+
onUnauthorized,
|
762
|
+
onNotFound,
|
763
|
+
onNotAcceptable,
|
764
|
+
});
|
765
|
+
}
|
684
766
|
case "outbox":
|
685
767
|
return await handleCollection(request, {
|
686
768
|
handle: route.values.handle,
|