Unverified Commit 7b586abe authored by Hong Minhee's avatar Hong Minhee
Browse files

Activity transformers to accept Context

parent 1856bfff
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ To be released.
        to `AuthenticatedDocumentLoaderFactory` type.
     -  `GetAuthenticatedDocumentLoaderOptions` interface became to extend
        `DocumentLoaderFactoryOptions` interface.
     -  Added a type parameter `TContextData` to `CreateFederationOptions`
        interface.

 -  Introduced `ActivityTransformer`s for adjusting outgoing activities
    before sending them so that some ActivityPub implementations with quirks
+9 −2
Original line number Diff line number Diff line
import { assertEquals } from "@std/assert/assert-equals";
import { assertNotEquals } from "@std/assert/assert-not-equals";
import { MemoryKvStore } from "../federation/kv.ts";
import { FederationImpl } from "../federation/middleware.ts";
import { test } from "../testing/mod.ts";
import { Follow, Person } from "../vocab/vocab.ts";
import { actorDehydrator, autoIdAssigner } from "./transformers.ts";

const federation = new FederationImpl<void>({
  kv: new MemoryKvStore(),
});
const context = federation.createContext(new URL("http://example.com/"));

test("autoIdAssigner", async () => {
  const activity = new Follow({
    actor: new URL("http://example.com/actors/1"),
@@ -13,7 +20,7 @@ test("autoIdAssigner", async () => {
      preferredUsername: "bob",
    }),
  });
  const result = autoIdAssigner(activity);
  const result = autoIdAssigner(activity, context);
  assertNotEquals(result.id, null);
  assertEquals(
    await result.toJsonLd(),
@@ -43,7 +50,7 @@ test("actorDehydrator()", async () => {
      preferredUsername: "bob",
    }),
  });
  const result = actorDehydrator(activity);
  const result = actorDehydrator(activity, context);
  assertEquals(
    await result.toJsonLd(),
    await new Follow({
+24 −7
Original line number Diff line number Diff line
import { getLogger } from "@logtape/logtape";
import type { Context } from "../federation/context.ts";
import type { Activity } from "../vocab/vocab.ts";
import type { ActivityTransformer } from "./types.ts";

@@ -14,11 +15,16 @@ const logger = getLogger(["fedify", "compat", "transformers"]);
 * ```
 * urn:uuid:12345678-1234-5678-1234-567812345678
 * ```
 * @typeParam TContextData The type of the context data.
 * @param activity The activity to assign an ID to.
 * @param context The context of the activity.
 * @return The activity with an ID assigned.
 * @since 1.4.0
 */
export function autoIdAssigner(activity: Activity): Activity {
export function autoIdAssigner<TContextData>(
  activity: Activity,
  _context: Context<TContextData>,
): Activity {
  if (activity.id != null) return activity;
  const id = new URL(`urn:uuid:${crypto.randomUUID()}`);
  logger.warn(
@@ -69,11 +75,16 @@ export function autoIdAssigner(activity: Activity): Activity {
 *
 * As some ActivityPub implementations like Threads fail to deal with inlined
 * actor objects, this transformer can be used to work around this issue.
 * @typeParam TContextData The type of the context data.
 * @param activity The activity to dehydrate the actor property of.
 * @param context The context of the activity.
 * @returns The dehydrated activity.
 * @since 1.4.0
 */
export function actorDehydrator(activity: Activity): Activity {
export function actorDehydrator<TContextData>(
  activity: Activity,
  _context: Context<TContextData>,
): Activity {
  if (activity.actorIds.length < 1) return activity;
  return activity.clone({
    actors: activity.actorIds,
@@ -81,11 +92,17 @@ export function actorDehydrator(activity: Activity): Activity {
}

/**
 * The default activity transformers that are applied to all outgoing
 * Gets the default activity transformers that are applied to all outgoing
 * activities.
 * @typeParam TContextData The type of the context data.
 * @returns The default activity transformers.
 * @since 1.4.0
 */
export const defaultActivityTransformers: readonly ActivityTransformer[] = [
export function getDefaultActivityTransformers<
  TContextData,
>(): readonly ActivityTransformer<TContextData>[] {
  return [
    autoIdAssigner,
    actorDehydrator,
  ];
}
+5 −1
Original line number Diff line number Diff line
import type { Context } from "../federation/context.ts";
import type { Activity } from "../vocab/vocab.ts";

/**
 * A function that transforms an activity object.
 * @since 1.4.0
 */
export type ActivityTransformer = (activity: Activity) => Activity;
export type ActivityTransformer<TContextData> = (
  activity: Activity,
  context: Context<TContextData>,
) => Activity;
+5 −4
Original line number Diff line number Diff line
@@ -980,6 +980,7 @@ test("FederationImpl.sendActivity()", async (t) => {
    kv,
    contextLoader: mockDocumentLoader,
  });
  const context = federation.createContext(new URL("https://example.com/"));

  await t.step("success", async () => {
    const activity = new Create({
@@ -993,7 +994,7 @@ test("FederationImpl.sendActivity()", async (t) => {
      [{ privateKey: rsaPrivateKey2, keyId: rsaPublicKey2.id! }],
      recipient,
      activity,
      { contextData: undefined, origin: "https://example.com" },
      { context },
    );
    assertEquals(verified, ["http"]);
    assertInstanceOf(request, Request);
@@ -1011,7 +1012,7 @@ test("FederationImpl.sendActivity()", async (t) => {
      activity.clone({
        actor: new URL("https://example.com/person2"),
      }),
      { contextData: undefined, origin: "https://example.com" },
      { context },
    );
    assertEquals(verified, ["ld", "http"]);
    assertInstanceOf(request, Request);
@@ -1031,7 +1032,7 @@ test("FederationImpl.sendActivity()", async (t) => {
      activity.clone({
        actor: new URL("https://example.com/person2"),
      }),
      { contextData: undefined, origin: "https://example.com" },
      { context },
    );
    assertEquals(verified, ["proof"]);
    assertInstanceOf(request, Request);
@@ -1052,7 +1053,7 @@ test("FederationImpl.sendActivity()", async (t) => {
      activity.clone({
        actor: new URL("https://example.com/person2"),
      }),
      { contextData: undefined, origin: "https://example.com" },
      { context },
    );
    assertEquals(verified, ["ld", "proof", "http"]);
    assertInstanceOf(request, Request);
Loading