@fedify/fedify
Version:
An ActivityPub server framework
160 lines (156 loc) • 6.26 kB
JavaScript
import { Temporal } from "@js-temporal/polyfill";
import { URLPattern } from "urlpattern-polyfill";
globalThis.addEventListener = () => {};
import { assertEquals } from "../assert_equals-CTYbeopb.js";
import "../assert-DmFG7ppO.js";
import "../assert_instance_of-CF09JHYM.js";
import { MemoryKvStore } from "../kv-BMY6Qf_A.js";
import "../docloader-C8mmLN-Y.js";
import "../url-kTAI6_KP.js";
import { parseSemVer } from "../semver-DWClQt_5.js";
import "../router-D_aVZZUc.js";
import "../multibase-DeCHcK8L.js";
import { Activity, Note, Person } from "../vocab-dDpPQ0fF.js";
import "../langstr-DbWheeIS.js";
import "../type-D2s5lmbZ.js";
import "../inbox-AwdJVoMZ.js";
import { createFederationBuilder } from "../builder-EdzpUb9N.js";
import { test } from "../testing-BZ0dJ4qn.js";
import { assertExists } from "../std__assert-vp0TKMS1.js";
import "../assert_rejects-C-sxEMM5.js";
import "../assert_is_error-nrwA1GeT.js";
import "../assert_not_equals-Dc7y-V5Q.js";
import "../assert_throws-Cn9C6Jur.js";
//#region federation/builder.test.ts
test("FederationBuilder", async (t) => {
await t.step("should build a Federation object with registered components", async () => {
const builder = createFederationBuilder();
const kv = new MemoryKvStore();
const actorDispatcher = (_ctx, _identifier) => {
return null;
};
builder.setActorDispatcher("/users/{identifier}", actorDispatcher);
const inboxListener = (_ctx, _activity) => {};
const listeners = builder.setInboxListeners("/users/{identifier}/inbox");
listeners.on(Activity, inboxListener);
const objectDispatcher = (_ctx, _values) => {
return null;
};
builder.setObjectDispatcher(Note, "/notes/{id}", objectDispatcher);
const nodeInfo = {
version: "2.1",
software: {
name: "test",
version: parseSemVer("1.0.0")
},
protocols: ["activitypub"],
services: {
inbound: [],
outbound: []
},
openRegistrations: false,
usage: {
users: {},
localPosts: 0,
localComments: 0
},
metadata: {}
};
const nodeInfoDispatcher = (_ctx) => nodeInfo;
builder.setNodeInfoDispatcher("/nodeinfo", nodeInfoDispatcher);
const federation = await builder.build({ kv });
assertExists(federation);
const impl = federation;
assertEquals(impl.router.route("/.well-known/webfinger")?.name, "webfinger");
assertEquals(impl.router.route("/users/test123")?.name, "actor");
assertEquals(impl.router.route("/users/test123/inbox")?.name, "inbox");
assertEquals(impl.router.route("/notes/456")?.name, `object:${Note.typeId.href}`);
assertEquals(impl.router.route("/nodeinfo")?.name, "nodeInfo");
const actorCallbacksDispatcher = impl.actorCallbacks?.dispatcher;
assertExists(actorCallbacksDispatcher);
const inboxListeners = impl.inboxListeners;
assertExists(inboxListeners);
assertExists(impl.objectCallbacks[Note.typeId.href]);
assertExists(impl.nodeInfoDispatcher);
const notePaths = impl.router.build(`object:${Note.typeId.href}`, { id: "123" });
assertEquals(notePaths, "/notes/123");
assertEquals(impl.router.build("actor", { identifier: "user1" }), "/users/user1");
assertEquals(impl.router.build("inbox", { identifier: "user1" }), "/users/user1/inbox");
await builder.build({ kv });
});
await t.step("should build with default options", async () => {
const builder = createFederationBuilder();
const kv = new MemoryKvStore();
const federation = await builder.build({ kv });
assertExists(federation);
const impl = federation;
assertEquals(impl.kv, kv);
});
await t.step("should pass build options correctly", async () => {
const builder = createFederationBuilder();
const kv = new MemoryKvStore();
const federation = await builder.build({
kv,
kvPrefixes: { activityIdempotence: ["custom", "idem"] },
allowPrivateAddress: true,
trailingSlashInsensitive: true,
origin: "https://example.com"
});
assertExists(federation);
const impl = federation;
assertEquals(impl.kv, kv);
assertEquals(impl.kvPrefixes.activityIdempotence, ["custom", "idem"]);
assertEquals(impl.allowPrivateAddress, true);
assertEquals(impl.router.trailingSlashInsensitive, true);
assertEquals(impl.origin?.webOrigin, "https://example.com");
});
await t.step("should handle firstKnock option", async () => {
const builder = createFederationBuilder();
const kv = new MemoryKvStore();
const federationDefault = await builder.build({ kv });
assertExists(federationDefault);
const implDefault = federationDefault;
assertEquals(implDefault.firstKnock, void 0);
const federationCustom = await builder.build({
kv,
firstKnock: "draft-cavage-http-signatures-12"
});
assertExists(federationCustom);
const implCustom = federationCustom;
assertEquals(implCustom.firstKnock, "draft-cavage-http-signatures-12");
const federationRfc = await builder.build({
kv,
firstKnock: "rfc9421"
});
assertExists(federationRfc);
const implRfc = federationRfc;
assertEquals(implRfc.firstKnock, "rfc9421");
});
await t.step("should register multiple object dispatchers and verify them", async () => {
const builder = createFederationBuilder();
const kv = new MemoryKvStore();
const noteDispatcher = (_ctx, _values) => {
return null;
};
const personDispatcher = (_ctx, _values) => {
return null;
};
builder.setObjectDispatcher(Note, "/notes/{id}", noteDispatcher);
builder.setObjectDispatcher(Person, "/people/{id}", personDispatcher);
const federation = await builder.build({ kv });
const impl = federation;
assertExists(impl.objectCallbacks[Note.typeId.href]);
assertExists(impl.objectCallbacks[Person.typeId.href]);
const notePath = impl.router.build(`object:${Note.typeId.href}`, { id: "123" });
assertEquals(notePath, "/notes/123");
const personPath = impl.router.build(`object:${Person.typeId.href}`, { id: "456" });
assertEquals(personPath, "/people/456");
const noteRoute = impl.router.route("/notes/789");
assertEquals(noteRoute?.name, `object:${Note.typeId.href}`);
assertEquals(noteRoute?.values.id, "789");
const personRoute = impl.router.route("/people/abc");
assertEquals(personRoute?.name, `object:${Person.typeId.href}`);
assertEquals(personRoute?.values.id, "abc");
});
});
//#endregion