Unverified Commit 58ee54ab authored by Hong Minhee (洪 民憙)'s avatar Hong Minhee (洪 民憙) Committed by GitHub
Browse files

Merge pull request #237 from dahlia/context-clone

parents 87f95fcc 04840f5a
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@ To be released. Note that 1.6.0 was skipped due to a mistake in the versioning.
 -  Added `Context.federation` property to access the `Federation`
    object from the context.  [[#235]]

 -  Added `Context.clone()` method.  [[#237]]

 -  Introduced `FederationBuilder` for creating a federation instance with
    a builder pattern.

@@ -43,6 +45,7 @@ To be released. Note that 1.6.0 was skipped due to a mistake in the versioning.
[#208]: https://github.com/fedify-dev/fedify/issues/208
[#227]: https://github.com/fedify-dev/fedify/issues/227
[#235]: https://github.com/fedify-dev/fedify/pull/235
[#237]: https://github.com/fedify-dev/fedify/pull/237


Version 1.5.3
+18 −0
Original line number Diff line number Diff line
@@ -482,3 +482,21 @@ if (isActor(actor)) {
  }
}
~~~~


Replacing the context data
--------------------------

*This API is available since Fedify 1.6.0.*

You can replace the context data by calling the `Context.clone()` method.
This is useful when you want to create a new context based on the existing one
but with different data.  The following shows an example of replacing the
context data:

~~~~ typescript twoslash
import { type Context } from "@fedify/fedify";
const ctx = null as unknown as Context<{ foo: string; bar: number }>;
// ---cut-before---
const newCtx = ctx.clone({ ...ctx.data, foo: "new value" });
~~~~
+30 −0
Original line number Diff line number Diff line
@@ -84,6 +84,16 @@ export interface Context<TContextData> {
   */
  readonly federation: Federation<TContextData>;

  /**
   * Creates a new context with the same properties as this one,
   * but with the given data.
   * @param data The new data to associate with the context.
   * @returns A new context with the same properties as this one,
   *          but with the given data.
   * @since 1.6.0
   */
  clone(data: TContextData): Context<TContextData>;

  /**
   * Builds the URI of the NodeInfo document.
   * @returns The NodeInfo URI.
@@ -429,6 +439,16 @@ export interface RequestContext<TContextData> extends Context<TContextData> {
   */
  readonly url: URL;

  /**
   * Creates a new context with the same properties as this one,
   * but with the given data.
   * @param data The new data to associate with the context.
   * @returns A new context with the same properties as this one,
   *          but with the given data.
   * @since 1.6.0
   */
  clone(data: TContextData): RequestContext<TContextData>;

  /**
   * Gets an {@link Actor} object for the given identifier.
   * @param identifier The actor's identifier.
@@ -539,6 +559,16 @@ export interface InboxContext<TContextData> extends Context<TContextData> {
   */
  recipient: string | null;

  /**
   * Creates a new context with the same properties as this one,
   * but with the given data.
   * @param data The new data to associate with the context.
   * @returns A new context with the same properties as this one,
   *          but with the given data.
   * @since 1.6.0
   */
  clone(data: TContextData): InboxContext<TContextData>;

  /**
   * Forwards a received activity to the recipients' inboxes.  The forwarded
   * activity will be signed in HTTP Signatures by the forwarder, but its
+25 −9
Original line number Diff line number Diff line
@@ -1180,7 +1180,7 @@ test("handleInbox()", async () => {
    recipient: null,
    context: unsignedContext,
    inboxContextFactory(_activity) {
      return createInboxContext(unsignedContext);
      return createInboxContext({ ...unsignedContext, clone: undefined });
    },
    ...inboxOptions,
    actorDispatcher: undefined,
@@ -1193,7 +1193,11 @@ test("handleInbox()", async () => {
    recipient: "nobody",
    context: unsignedContext,
    inboxContextFactory(_activity) {
      return createInboxContext({ ...unsignedContext, recipient: "nobody" });
      return createInboxContext({
        ...unsignedContext,
        clone: undefined,
        recipient: "nobody",
      });
    },
    ...inboxOptions,
  });
@@ -1205,7 +1209,7 @@ test("handleInbox()", async () => {
    recipient: null,
    context: unsignedContext,
    inboxContextFactory(_activity) {
      return createInboxContext(unsignedContext);
      return createInboxContext({ ...unsignedContext, clone: undefined });
    },
    ...inboxOptions,
  });
@@ -1216,7 +1220,11 @@ test("handleInbox()", async () => {
    recipient: "someone",
    context: unsignedContext,
    inboxContextFactory(_activity) {
      return createInboxContext({ ...unsignedContext, recipient: "someone" });
      return createInboxContext({
        ...unsignedContext,
        clone: undefined,
        recipient: "someone",
      });
    },
    ...inboxOptions,
  });
@@ -1240,7 +1248,7 @@ test("handleInbox()", async () => {
    recipient: null,
    context: signedContext,
    inboxContextFactory(_activity) {
      return createInboxContext(unsignedContext);
      return createInboxContext({ ...unsignedContext, clone: undefined });
    },
    ...inboxOptions,
  });
@@ -1251,7 +1259,11 @@ test("handleInbox()", async () => {
    recipient: "someone",
    context: signedContext,
    inboxContextFactory(_activity) {
      return createInboxContext({ ...unsignedContext, recipient: "someone" });
      return createInboxContext({
        ...unsignedContext,
        clone: undefined,
        recipient: "someone",
      });
    },
    ...inboxOptions,
  });
@@ -1262,7 +1274,7 @@ test("handleInbox()", async () => {
    recipient: null,
    context: unsignedContext,
    inboxContextFactory(_activity) {
      return createInboxContext(unsignedContext);
      return createInboxContext({ ...unsignedContext, clone: undefined });
    },
    ...inboxOptions,
    skipSignatureVerification: true,
@@ -1274,7 +1286,11 @@ test("handleInbox()", async () => {
    recipient: "someone",
    context: unsignedContext,
    inboxContextFactory(_activity) {
      return createInboxContext({ ...unsignedContext, recipient: "someone" });
      return createInboxContext({
        ...unsignedContext,
        clone: undefined,
        recipient: "someone",
      });
    },
    ...inboxOptions,
    skipSignatureVerification: true,
@@ -1311,7 +1327,7 @@ test("handleInbox()", async () => {
    recipient: null,
    context: signedContext,
    inboxContextFactory(_activity) {
      return createInboxContext(signedInvalidContext);
      return createInboxContext({ ...signedInvalidContext, clone: undefined });
    },
    ...inboxOptions,
  });
+34 −0
Original line number Diff line number Diff line
@@ -726,6 +726,22 @@ test("Federation.createContext()", async (t) => {
    );
  });

  await t.step("Context.clone()", () => {
    const federation = createFederation<number>({
      kv,
    });
    const ctx = federation.createContext(new URL("https://example.com/"), 123);
    const clone = ctx.clone(456);
    assertStrictEquals(clone.canonicalOrigin, ctx.canonicalOrigin);
    assertStrictEquals(clone.origin, ctx.origin);
    assertEquals(clone.data, 456);
    assertEquals(clone.host, ctx.host);
    assertEquals(clone.hostname, ctx.hostname);
    assertStrictEquals(clone.documentLoader, ctx.documentLoader);
    assertStrictEquals(clone.contextLoader, ctx.contextLoader);
    assertStrictEquals(clone.federation, ctx.federation);
  });

  mf.mock("GET@/.well-known/nodeinfo", (req) => {
    assertEquals(new URL(req.url).host, "example.com");
    assertEquals(req.headers.get("User-Agent"), "CustomUserAgent/1.2.3");
@@ -875,6 +891,24 @@ test("Federation.createContext()", async (t) => {
    );
  });

  await t.step("RequestContext.clone()", () => {
    const federation = createFederation<number>({
      kv,
    });
    const req = new Request("https://example.com/");
    const ctx = federation.createContext(req, 123);
    const clone = ctx.clone(456);
    assertStrictEquals(clone.request, ctx.request);
    assertEquals(clone.url, ctx.url);
    assertEquals(clone.data, 456);
    assertEquals(clone.origin, ctx.origin);
    assertEquals(clone.host, ctx.host);
    assertEquals(clone.hostname, ctx.hostname);
    assertStrictEquals(clone.documentLoader, ctx.documentLoader);
    assertStrictEquals(clone.contextLoader, ctx.contextLoader);
    assertStrictEquals(clone.federation, ctx.federation);
  });

  mf.uninstall();
});

Loading