UNPKG

@fedify/fedify

Version:

An ActivityPub server framework

160 lines (156 loc) • 6.26 kB
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