From 5a016ea51d4c49f59d49ef581577176d1f90c8b4 Mon Sep 17 00:00:00 2001 From: ChanHaeng Lee <2chanhaeng@gmail.com> Date: Sat, 14 Feb 2026 08:21:27 +0000 Subject: [PATCH 1/4] Delete `CreateFederationOptions` and `fetchDocumentLoader` --- packages/fedify/src/federation/federation.ts | 6 +-- .../fedify/src/federation/middleware.test.ts | 48 +++++++++---------- packages/fedify/src/federation/middleware.ts | 14 +----- packages/fedify/src/federation/mod.ts | 1 - packages/fedify/src/utils/docloader.ts | 47 ------------------ 5 files changed, 29 insertions(+), 87 deletions(-) diff --git a/packages/fedify/src/federation/federation.ts b/packages/fedify/src/federation/federation.ts index 34a1b4468..adae8fe08 100644 --- a/packages/fedify/src/federation/federation.ts +++ b/packages/fedify/src/federation/federation.ts @@ -868,9 +868,9 @@ export interface FederationOptions { /** * Whether to allow fetching private network addresses in the document loader. * - * If turned on, {@link CreateFederationOptions.documentLoader}, - * {@link CreateFederationOptions.contextLoader}, and - * {@link CreateFederationOptions.authenticatedDocumentLoaderFactory} + * If turned on, {@link FederationOptions.documentLoader}, + * {@link FederationOptions.contextLoader}, and + * {@link FederationOptions.authenticatedDocumentLoaderFactory} * cannot be configured. * * Mostly useful for testing purposes. *Do not use in production.* diff --git a/packages/fedify/src/federation/middleware.test.ts b/packages/fedify/src/federation/middleware.test.ts index aa673f58b..5a1e2be51 100644 --- a/packages/fedify/src/federation/middleware.test.ts +++ b/packages/fedify/src/federation/middleware.test.ts @@ -35,10 +35,10 @@ import { rsaPublicKey2, rsaPublicKey3, } from "../testing/keys.ts"; -import { - fetchDocumentLoader, - getAuthenticatedDocumentLoader, -} from "../utils/docloader.ts"; +import { getDocumentLoader } from "@fedify/vocab-runtime"; +import { getAuthenticatedDocumentLoader } from "../utils/docloader.ts"; + +const documentLoader = getDocumentLoader(); import type { Context } from "./context.ts"; import { MemoryKvStore } from "./kv.ts"; import { @@ -390,7 +390,7 @@ test({ const federation2 = createFederation({ kv, - documentLoaderFactory: () => fetchDocumentLoader, + documentLoaderFactory: () => documentLoader, contextLoaderFactory: () => mockDocumentLoader, }); const ctx2 = federation2.createContext( @@ -2333,8 +2333,8 @@ test("ContextImpl.sendActivity()", async (t) => { data: undefined, federation, url: new URL("https://example.com/"), - documentLoader: fetchDocumentLoader, - contextLoader: fetchDocumentLoader, + documentLoader: documentLoader, + contextLoader: documentLoader, }); await ctx.sendActivity( [{ privateKey: rsaPrivateKey2, keyId: rsaPublicKey2.id! }], @@ -2474,8 +2474,8 @@ test("ContextImpl.sendActivity()", async (t) => { data: undefined, federation: federation2, url: new URL("https://example.com/"), - documentLoader: fetchDocumentLoader, - contextLoader: fetchDocumentLoader, + documentLoader: documentLoader, + contextLoader: documentLoader, }); await t.step('fanout: "force"', async () => { @@ -2498,7 +2498,7 @@ test("ContextImpl.sendActivity()", async (t) => { type: "fanout", activity: await activity.toJsonLd({ format: "compact", - contextLoader: fetchDocumentLoader, + contextLoader: documentLoader, }), activityId: "https://example.com/activity/1", activityType: "https://www.w3.org/ns/activitystreams#Create", @@ -2609,8 +2609,8 @@ test("ContextImpl.sendActivity()", async (t) => { data: undefined, federation, url: new URL("https://example.com/"), - documentLoader: fetchDocumentLoader, - contextLoader: fetchDocumentLoader, + documentLoader: documentLoader, + contextLoader: documentLoader, }); const activity = new vocab.Create({ @@ -2631,8 +2631,8 @@ test("ContextImpl.sendActivity()", async (t) => { data: undefined, federation, url: new URL("https://example.com/"), - documentLoader: fetchDocumentLoader, - contextLoader: fetchDocumentLoader, + documentLoader: documentLoader, + contextLoader: documentLoader, }); const activity = new vocab.Create({ @@ -2753,7 +2753,7 @@ test({ federation, data: undefined, documentLoader: mockDocumentLoader, - contextLoader: fetchDocumentLoader, + contextLoader: documentLoader, }); // Unsigned & non-dereferenceable activity @@ -2900,7 +2900,7 @@ test("ContextImpl.getCollectionUri()", () => { federation, data: undefined, documentLoader: mockDocumentLoader, - contextLoader: fetchDocumentLoader, + contextLoader: documentLoader, }); const values = { id: "123" }; @@ -3000,8 +3000,8 @@ test("InboxContextImpl.forwardActivity()", async (t) => { data: undefined, federation, url: new URL("https://example.com/"), - documentLoader: fetchDocumentLoader, - contextLoader: fetchDocumentLoader, + documentLoader: documentLoader, + contextLoader: documentLoader, }, ); await ctx.forwardActivity( @@ -3031,8 +3031,8 @@ test("InboxContextImpl.forwardActivity()", async (t) => { data: undefined, federation, url: new URL("https://example.com/"), - documentLoader: fetchDocumentLoader, - contextLoader: fetchDocumentLoader, + documentLoader: documentLoader, + contextLoader: documentLoader, }, ); await assertRejects(() => @@ -3066,8 +3066,8 @@ test("InboxContextImpl.forwardActivity()", async (t) => { data: undefined, federation, url: new URL("https://example.com/"), - documentLoader: fetchDocumentLoader, - contextLoader: fetchDocumentLoader, + documentLoader: documentLoader, + contextLoader: documentLoader, }, ); await ctx.forwardActivity( @@ -3102,8 +3102,8 @@ test("InboxContextImpl.forwardActivity()", async (t) => { data: undefined, federation, url: new URL("https://example.com/"), - documentLoader: fetchDocumentLoader, - contextLoader: fetchDocumentLoader, + documentLoader: documentLoader, + contextLoader: documentLoader, }, ); await ctx.forwardActivity( diff --git a/packages/fedify/src/federation/middleware.ts b/packages/fedify/src/federation/middleware.ts index a154e4e5a..ccd6387a3 100644 --- a/packages/fedify/src/federation/middleware.ts +++ b/packages/fedify/src/federation/middleware.ts @@ -114,16 +114,6 @@ import { } from "./send.ts"; import { handleWebFinger } from "./webfinger.ts"; -/** - * Options for {@link createFederation} function. - * @template TContextData The type of the context data. - * @since 0.10.0 - * @deprecated Use {@link FederationOptions} instead. - */ -export interface CreateFederationOptions - extends FederationOptions { -} - /** * Configures the task queues for sending and receiving activities. * @since 1.3.0 @@ -185,7 +175,7 @@ export interface FederationKvPrefixes { } /** - * Options for {@link CreateFederationOptions.origin} when it is not a string. + * Options for {@link FederationOptions.origin} when it is not a string. * @since 1.5.0 */ export interface FederationOrigin { @@ -211,7 +201,7 @@ export interface FederationOrigin { * @since 0.10.0 */ export function createFederation( - options: CreateFederationOptions, + options: FederationOptions, ): Federation { return new FederationImpl(options); } diff --git a/packages/fedify/src/federation/mod.ts b/packages/fedify/src/federation/mod.ts index 62f21a2cc..b490e2a44 100644 --- a/packages/fedify/src/federation/mod.ts +++ b/packages/fedify/src/federation/mod.ts @@ -16,7 +16,6 @@ export { export * from "./kv.ts"; export { createFederation, - type CreateFederationOptions, type FederationKvPrefixes, type FederationOrigin, type FederationQueueOptions, diff --git a/packages/fedify/src/utils/docloader.ts b/packages/fedify/src/utils/docloader.ts index 03c4a193f..69d1ca991 100644 --- a/packages/fedify/src/utils/docloader.ts +++ b/packages/fedify/src/utils/docloader.ts @@ -3,7 +3,6 @@ import { type DocumentLoader, type DocumentLoaderFactoryOptions, type DocumentLoaderOptions, - getDocumentLoader, getRemoteDocument, logRequest, type RemoteDocument, @@ -91,49 +90,3 @@ export function getAuthenticatedDocumentLoader( } return load; } - -const _fetchDocumentLoader = getDocumentLoader(); -const _fetchDocumentLoader_allowPrivateAddress = getDocumentLoader({ - allowPrivateAddress: true, -}); - -/** - * A JSON-LD document loader that utilizes the browser's `fetch` API. - * - * This loader preloads the below frequently used contexts: - * - * - - * - - * - - * - - * - - * - - * - - * @param url The URL of the document to load. - * @param allowPrivateAddress Whether to allow fetching private network - * addresses. Turned off by default. - * @returns The remote document. - * @deprecated Use {@link getDocumentLoader} instead. - */ -export function fetchDocumentLoader( - url: string, - allowPrivateAddress?: boolean, -): Promise; -export function fetchDocumentLoader( - url: string, - options?: DocumentLoaderOptions, -): Promise; -export function fetchDocumentLoader( - url: string, - arg: boolean | DocumentLoaderOptions = false, -): Promise { - const allowPrivateAddress = typeof arg === "boolean" ? arg : false; - logger.warn( - "fetchDocumentLoader() function is deprecated. " + - "Use getDocumentLoader() function instead.", - ); - const loader = allowPrivateAddress - ? _fetchDocumentLoader_allowPrivateAddress - : _fetchDocumentLoader; - return loader(url); -} From d64755de83e2d3edd197292ce7a32a83762c2286 Mon Sep 17 00:00:00 2001 From: ChanHaeng Lee <2chanhaeng@gmail.com> Date: Sat, 14 Feb 2026 18:40:14 +0000 Subject: [PATCH 2/4] Remove `{ handle: string }` --- packages/fedify/src/federation/callback.ts | 2 - packages/fedify/src/federation/context.ts | 23 +-- .../fedify/src/federation/middleware.test.ts | 54 +++---- packages/fedify/src/federation/middleware.ts | 144 +++--------------- .../fedify/src/federation/webfinger.test.ts | 3 - packages/testing/src/mock.ts | 1 - 6 files changed, 51 insertions(+), 176 deletions(-) diff --git a/packages/fedify/src/federation/callback.ts b/packages/fedify/src/federation/callback.ts index 600a01ed7..6ac9a1a10 100644 --- a/packages/fedify/src/federation/callback.ts +++ b/packages/fedify/src/federation/callback.ts @@ -209,13 +209,11 @@ export type SharedInboxKeyDispatcher = ( | SenderKeyPair | { identifier: string } | { username: string } - | { handle: string } | null | Promise< | SenderKeyPair | { identifier: string } | { username: string } - | { handle: string } | null >; diff --git a/packages/fedify/src/federation/context.ts b/packages/fedify/src/federation/context.ts index 6b4b255d9..0f6b14a64 100644 --- a/packages/fedify/src/federation/context.ts +++ b/packages/fedify/src/federation/context.ts @@ -225,8 +225,7 @@ export interface Context { getDocumentLoader( identity: | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, ): Promise; /** @@ -375,8 +374,7 @@ export interface Context { | SenderKeyPair | SenderKeyPair[] | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, recipients: Recipient | Recipient[], activity: Activity, options?: SendActivityOptions, @@ -392,7 +390,7 @@ export interface Context { * @since 0.14.0 */ sendActivity( - sender: { identifier: string } | { username: string } | { handle: string }, + sender: { identifier: string } | { username: string }, recipients: "followers", activity: Activity, options?: SendActivityOptionsForCollection, @@ -600,8 +598,7 @@ export interface InboxContext extends Context { | SenderKeyPair | SenderKeyPair[] | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, recipients: Recipient | Recipient[], options?: ForwardActivityOptions, ): Promise; @@ -621,8 +618,7 @@ export interface InboxContext extends Context { forwardActivity( forwarder: | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, recipients: "followers", options?: ForwardActivityOptions, ): Promise; @@ -638,7 +634,6 @@ export type ParseUriResult = | { readonly type: "actor"; readonly identifier: string; - readonly handle: string; } /** * The case of an object URI. @@ -655,7 +650,6 @@ export type ParseUriResult = | { readonly type: "inbox"; readonly identifier: undefined; - readonly handle: undefined; } /** * The case of an personal inbox URI. @@ -663,7 +657,6 @@ export type ParseUriResult = | { readonly type: "inbox"; readonly identifier: string; - readonly handle: string; } /** * The case of an outbox collection URI. @@ -671,7 +664,6 @@ export type ParseUriResult = | { readonly type: "outbox"; readonly identifier: string; - readonly handle: string; } /** * The case of a following collection URI. @@ -679,7 +671,6 @@ export type ParseUriResult = | { readonly type: "following"; readonly identifier: string; - readonly handle: string; } /** * The case of a followers collection URI. @@ -687,7 +678,6 @@ export type ParseUriResult = | { readonly type: "followers"; readonly identifier: string; - readonly handle: string; } /** * The case of a liked collection URI. @@ -696,7 +686,6 @@ export type ParseUriResult = | { readonly type: "liked"; readonly identifier: string; - readonly handle: string; } /** * The case of a featured collection URI. @@ -705,7 +694,6 @@ export type ParseUriResult = | { readonly type: "featured"; readonly identifier: string; - readonly handle: string; } /** * The case of a featured tags collection URI. @@ -714,7 +702,6 @@ export type ParseUriResult = | { readonly type: "featuredTags"; readonly identifier: string; - readonly handle: string; } /** * The case of a custom collection URI. diff --git a/packages/fedify/src/federation/middleware.test.ts b/packages/fedify/src/federation/middleware.test.ts index 5a1e2be51..2265db3a8 100644 --- a/packages/fedify/src/federation/middleware.test.ts +++ b/packages/fedify/src/federation/middleware.test.ts @@ -302,7 +302,7 @@ test({ assertEquals(ctx.parseUri(new URL("https://example.com/")), null); assertEquals( ctx.parseUri(new URL("https://example.com/users/handle")), - { type: "actor", identifier: "handle", handle: "handle" }, + { type: "actor", identifier: "handle" }, ); assertEquals(ctx.parseUri(null), null); assertEquals( @@ -439,11 +439,11 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://example.com/inbox")), - { type: "inbox", identifier: undefined, handle: undefined }, + { type: "inbox", identifier: undefined }, ); assertEquals( ctx.parseUri(new URL("https://example.com/users/handle/inbox")), - { type: "inbox", identifier: "handle", handle: "handle" }, + { type: "inbox", identifier: "handle" }, ); assertEquals(ctx.parseUri(null), null); @@ -458,7 +458,7 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://example.com/users/handle/outbox")), - { type: "outbox", identifier: "handle", handle: "handle" }, + { type: "outbox", identifier: "handle" }, ); assertEquals(ctx.parseUri(null), null); @@ -473,7 +473,7 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://example.com/users/handle/following")), - { type: "following", identifier: "handle", handle: "handle" }, + { type: "following", identifier: "handle" }, ); assertEquals(ctx.parseUri(null), null); @@ -488,7 +488,7 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://example.com/users/handle/followers")), - { type: "followers", identifier: "handle", handle: "handle" }, + { type: "followers", identifier: "handle" }, ); assertEquals(ctx.parseUri(null), null); @@ -503,7 +503,7 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://example.com/users/handle/liked")), - { type: "liked", identifier: "handle", handle: "handle" }, + { type: "liked", identifier: "handle" }, ); assertEquals(ctx.parseUri(null), null); @@ -518,7 +518,7 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://example.com/users/handle/featured")), - { type: "featured", identifier: "handle", handle: "handle" }, + { type: "featured", identifier: "handle" }, ); assertEquals(ctx.parseUri(null), null); @@ -533,7 +533,7 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://example.com/users/handle/tags")), - { type: "featuredTags", identifier: "handle", handle: "handle" }, + { type: "featuredTags", identifier: "handle" }, ); assertEquals(ctx.parseUri(null), null); }); @@ -580,11 +580,11 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://ap.example.com/users/handle")), - { type: "actor", handle: "handle", identifier: "handle" }, + { type: "actor", identifier: "handle" }, ); assertEquals( ctx.parseUri(new URL("https://example.com:1234/users/handle")), - { type: "actor", handle: "handle", identifier: "handle" }, + { type: "actor", identifier: "handle" }, ); federation.setObjectDispatcher( @@ -627,19 +627,19 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://ap.example.com/inbox")), - { type: "inbox", handle: undefined, identifier: undefined }, + { type: "inbox", identifier: undefined }, ); assertEquals( ctx.parseUri(new URL("https://example.com:1234/inbox")), - { type: "inbox", handle: undefined, identifier: undefined }, + { type: "inbox", identifier: undefined }, ); assertEquals( ctx.parseUri(new URL("https://ap.example.com/users/handle/inbox")), - { type: "inbox", handle: "handle", identifier: "handle" }, + { type: "inbox", identifier: "handle" }, ); assertEquals( ctx.parseUri(new URL("https://example.com:1234/users/handle/inbox")), - { type: "inbox", handle: "handle", identifier: "handle" }, + { type: "inbox", identifier: "handle" }, ); federation.setOutboxDispatcher( @@ -652,11 +652,11 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://ap.example.com/users/handle/outbox")), - { type: "outbox", handle: "handle", identifier: "handle" }, + { type: "outbox", identifier: "handle" }, ); assertEquals( ctx.parseUri(new URL("https://example.com:1234/users/handle/outbox")), - { type: "outbox", handle: "handle", identifier: "handle" }, + { type: "outbox", identifier: "handle" }, ); federation.setFollowingDispatcher( @@ -669,13 +669,13 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://ap.example.com/users/handle/following")), - { type: "following", handle: "handle", identifier: "handle" }, + { type: "following", identifier: "handle" }, ); assertEquals( ctx.parseUri( new URL("https://example.com:1234/users/handle/following"), ), - { type: "following", handle: "handle", identifier: "handle" }, + { type: "following", identifier: "handle" }, ); federation.setFollowersDispatcher( @@ -688,13 +688,13 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://ap.example.com/users/handle/followers")), - { type: "followers", handle: "handle", identifier: "handle" }, + { type: "followers", identifier: "handle" }, ); assertEquals( ctx.parseUri( new URL("https://example.com:1234/users/handle/followers"), ), - { type: "followers", handle: "handle", identifier: "handle" }, + { type: "followers", identifier: "handle" }, ); federation.setLikedDispatcher( @@ -707,11 +707,11 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://ap.example.com/users/handle/liked")), - { type: "liked", handle: "handle", identifier: "handle" }, + { type: "liked", identifier: "handle" }, ); assertEquals( ctx.parseUri(new URL("https://example.com:1234/users/handle/liked")), - { type: "liked", handle: "handle", identifier: "handle" }, + { type: "liked", identifier: "handle" }, ); federation.setFeaturedDispatcher( @@ -724,11 +724,11 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://ap.example.com/users/handle/featured")), - { type: "featured", handle: "handle", identifier: "handle" }, + { type: "featured", identifier: "handle" }, ); assertEquals( ctx.parseUri(new URL("https://example.com:1234/users/handle/featured")), - { type: "featured", handle: "handle", identifier: "handle" }, + { type: "featured", identifier: "handle" }, ); federation.setFeaturedTagsDispatcher( @@ -741,11 +741,11 @@ test({ ); assertEquals( ctx.parseUri(new URL("https://ap.example.com/users/handle/tags")), - { type: "featuredTags", handle: "handle", identifier: "handle" }, + { type: "featuredTags", identifier: "handle" }, ); assertEquals( ctx.parseUri(new URL("https://example.com:1234/users/handle/tags")), - { type: "featuredTags", handle: "handle", identifier: "handle" }, + { type: "featuredTags", identifier: "handle" }, ); }); diff --git a/packages/fedify/src/federation/middleware.ts b/packages/fedify/src/federation/middleware.ts index ccd6387a3..0994b23cf 100644 --- a/packages/fedify/src/federation/middleware.ts +++ b/packages/fedify/src/federation/middleware.ts @@ -789,8 +789,7 @@ export class FederationImpl const identity = await this.sharedInboxKeyDispatcher(context); if (identity != null) { context = this.#createContext(baseUrl, ctxData, { - documentLoader: "identifier" in identity || "username" in identity || - "handle" in identity + documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity), }); @@ -1465,11 +1464,9 @@ export class FederationImpl const identity = await this.sharedInboxKeyDispatcher(context); if (identity != null) { context = this.#createContext(request, contextData, { - documentLoader: - "identifier" in identity || "username" in identity || - "handle" in identity - ? await context.getDocumentLoader(identity) - : context.getDocumentLoader(identity), + documentLoader: "identifier" in identity || "username" in identity + ? await context.getDocumentLoader(identity) + : context.getDocumentLoader(identity), }); } } @@ -1850,19 +1847,11 @@ export class ContextImpl implements Context { return null; } const route = this.federation.router.route(uri.pathname); - const logger = getLogger(["fedify", "federation"]); if (route == null) return null; else if (route.name === "sharedInbox") { return { type: "inbox", identifier: undefined, - get handle() { - logger.warn( - "The ParseUriResult.handle property is deprecated; " + - "use ParseUriResult.identifier instead.", - ); - return undefined; - }, }; } const identifier = "identifier" in route.values @@ -1872,13 +1861,6 @@ export class ContextImpl implements Context { return { type: "actor", identifier, - get handle() { - logger.warn( - "The ParseUriResult.handle property is deprecated; " + - "use ParseUriResult.identifier instead.", - ); - return identifier; - }, }; } else if (route.name.startsWith("object:")) { const typeId = route.name.replace(/^object:/, ""); @@ -1892,85 +1874,36 @@ export class ContextImpl implements Context { return { type: "inbox", identifier, - get handle() { - logger.warn( - "The ParseUriResult.handle property is deprecated; " + - "use ParseUriResult.identifier instead.", - ); - return identifier; - }, }; } else if (route.name === "outbox") { return { type: "outbox", identifier, - get handle() { - logger.warn( - "The ParseUriResult.handle property is deprecated; " + - "use ParseUriResult.identifier instead.", - ); - return identifier; - }, }; } else if (route.name === "following") { return { type: "following", identifier, - get handle() { - logger.warn( - "The ParseUriResult.handle property is deprecated; " + - "use ParseUriResult.identifier instead.", - ); - return identifier; - }, }; } else if (route.name === "followers") { return { type: "followers", identifier, - get handle() { - logger.warn( - "The ParseUriResult.handle property is deprecated; " + - "use ParseUriResult.identifier instead.", - ); - return identifier; - }, }; } else if (route.name === "liked") { return { type: "liked", identifier, - get handle() { - logger.warn( - "The ParseUriResult.handle property is deprecated; " + - "use ParseUriResult.identifier instead.", - ); - return identifier; - }, }; } else if (route.name === "featured") { return { type: "featured", identifier, - get handle() { - logger.warn( - "The ParseUriResult.handle property is deprecated; " + - "use ParseUriResult.identifier instead.", - ); - return identifier; - }, }; } else if (route.name === "featuredTags") { return { type: "featuredTags", identifier, - get handle() { - logger.warn( - "The ParseUriResult.handle property is deprecated; " + - "use ParseUriResult.identifier instead.", - ); - return identifier; - }, }; } @@ -2106,33 +2039,21 @@ export class ContextImpl implements Context { getDocumentLoader( identity: | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, ): Promise; getDocumentLoader(identity: SenderKeyPair): DocumentLoader; getDocumentLoader( identity: | SenderKeyPair | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, ): DocumentLoader | Promise { if ( - "identifier" in identity || "username" in identity || "handle" in identity + "identifier" in identity || "username" in identity ) { let identifierPromise: Promise; - if ("username" in identity || "handle" in identity) { - let username: string; - if ("username" in identity) { - username = identity.username; - } else { - username = identity.handle; - getLogger(["fedify", "runtime", "docloader"]).warn( - 'The "handle" property is deprecated; use "identifier" or ' + - '"username" instead.', - { identity }, - ); - } + if ("username" in identity) { + const username = identity.username; const mapper = this.federation.actorCallbacks?.handleMapper; if (mapper == null) { identifierPromise = Promise.resolve(username); @@ -2228,8 +2149,7 @@ export class ContextImpl implements Context { | SenderKeyPair | SenderKeyPair[] | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, recipients: Recipient | Recipient[] | "followers", activity: Activity, options: SendActivityOptionsForCollection = {}, @@ -2281,8 +2201,7 @@ export class ContextImpl implements Context { | SenderKeyPair | SenderKeyPair[] | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, recipients: Recipient | Recipient[] | "followers", activity: Activity, options: SendActivityOptionsForCollection, @@ -2291,21 +2210,11 @@ export class ContextImpl implements Context { const logger = getLogger(["fedify", "federation", "outbox"]); let keys: SenderKeyPair[]; let identifier: string | null = null; - if ("identifier" in sender || "username" in sender || "handle" in sender) { + if ("identifier" in sender || "username" in sender) { if ("identifier" in sender) { identifier = sender.identifier; } else { - let username: string; - if ("username" in sender) { - username = sender.username; - } else { - username = sender.handle; - logger.warn( - 'The "handle" property for the sender parameter is deprecated; ' + - 'use "identifier" or "username" instead.', - { sender }, - ); - } + const username = sender.username; if (this.federation.actorCallbacks?.handleMapper == null) { identifier = username; } else { @@ -2850,16 +2759,14 @@ export class InboxContextImpl extends ContextImpl | SenderKeyPair | SenderKeyPair[] | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, recipients: Recipient | Recipient[], options?: ForwardActivityOptions, ): Promise; forwardActivity( forwarder: | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, recipients: "followers", options?: ForwardActivityOptions, ): Promise; @@ -2868,8 +2775,7 @@ export class InboxContextImpl extends ContextImpl | SenderKeyPair | SenderKeyPair[] | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, recipients: Recipient | Recipient[] | "followers", options?: ForwardActivityOptions, ): Promise { @@ -2906,8 +2812,7 @@ export class InboxContextImpl extends ContextImpl | SenderKeyPair | SenderKeyPair[] | { identifier: string } - | { username: string } - | { handle: string }, + | { username: string }, recipients: Recipient | Recipient[] | "followers", options?: ForwardActivityOptions, ): Promise { @@ -2915,23 +2820,12 @@ export class InboxContextImpl extends ContextImpl let keys: SenderKeyPair[]; let identifier: string | null = null; if ( - "identifier" in forwarder || "username" in forwarder || - "handle" in forwarder + "identifier" in forwarder || "username" in forwarder ) { if ("identifier" in forwarder) { identifier = forwarder.identifier; } else { - let username: string; - if ("username" in forwarder) { - username = forwarder.username; - } else { - username = forwarder.handle; - logger.warn( - 'The "handle" property for the forwarder parameter is deprecated; ' + - 'use "identifier" or "username" instead.', - { forwarder }, - ); - } + const username = forwarder.username; if (this.federation.actorCallbacks?.handleMapper == null) { identifier = username; } else { diff --git a/packages/fedify/src/federation/webfinger.test.ts b/packages/fedify/src/federation/webfinger.test.ts index 0ee8c7109..6bd9167cf 100644 --- a/packages/fedify/src/federation/webfinger.test.ts +++ b/packages/fedify/src/federation/webfinger.test.ts @@ -41,9 +41,6 @@ test("handleWebFinger()", async (t) => { return { type: "actor", identifier, - get handle(): string { - throw new Error("ParseUriResult.handle is deprecated!"); - }, }; }, }); diff --git a/packages/testing/src/mock.ts b/packages/testing/src/mock.ts index a3b4d0712..5984de1fc 100644 --- a/packages/testing/src/mock.ts +++ b/packages/testing/src/mock.ts @@ -838,7 +838,6 @@ class MockContext implements Context { return { type: "actor", identifier: parts[2], - handle: parts[2], }; } } From eb3181a0ae02102db637ddbd64ab3f07598e23a8 Mon Sep 17 00:00:00 2001 From: ChanHaeng Lee <2chanhaeng@gmail.com> Date: Sat, 14 Feb 2026 19:39:01 +0000 Subject: [PATCH 3/4] Remove `{handle}` pattern --- packages/fedify/src/federation/builder.ts | 90 ++++--------------- packages/fedify/src/federation/federation.ts | 36 ++------ .../fedify/src/federation/handler.test.ts | 76 ++++++++-------- .../fedify/src/federation/middleware.test.ts | 2 +- packages/fedify/src/federation/middleware.ts | 42 +++++---- packages/testing/src/mock.ts | 10 +-- 6 files changed, 87 insertions(+), 169 deletions(-) diff --git a/packages/fedify/src/federation/builder.ts b/packages/fedify/src/federation/builder.ts index d4cd5b18e..091a7704b 100644 --- a/packages/fedify/src/federation/builder.ts +++ b/packages/fedify/src/federation/builder.ts @@ -197,7 +197,7 @@ export class FederationBuilderImpl } setActorDispatcher( - path: `${string}{identifier}${string}` | `${string}{handle}${string}`, + path: `${string}{identifier}${string}`, dispatcher: ActorDispatcher, ): ActorCallbackSetters { if (this.router.has("actor")) { @@ -206,18 +206,12 @@ export class FederationBuilderImpl const variables = this.router.add(path, "actor"); if ( variables.size !== 1 || - !(variables.has("identifier") || variables.has("handle")) + !variables.has("identifier") ) { throw new RouterError( "Path for actor dispatcher must have one variable: {identifier}", ); } - if (variables.has("handle")) { - getLogger(["fedify", "federation", "actor"]).warn( - "The {{handle}} variable in the actor dispatcher path is deprecated. " + - "Use {{identifier}} instead.", - ); - } const callbacks: ActorCallbacks = { dispatcher: async (context, identifier) => { const actor = await this._getTracer().startActiveSpan( @@ -622,7 +616,7 @@ export class FederationBuilderImpl } setInboxDispatcher( - path: `${string}{identifier}${string}` | `${string}{handle}${string}`, + path: `${string}{identifier}${string}`, dispatcher: CollectionDispatcher< Activity, RequestContext, @@ -647,18 +641,12 @@ export class FederationBuilderImpl const variables = this.router.add(path, "inbox"); if ( variables.size !== 1 || - !(variables.has("identifier") || variables.has("handle")) + !variables.has("identifier") ) { throw new RouterError( "Path for inbox dispatcher must have one variable: {identifier}", ); } - if (variables.has("handle")) { - getLogger(["fedify", "federation", "inbox"]).warn( - "The {{handle}} variable in the inbox dispatcher path is deprecated. " + - "Use {{identifier}} instead.", - ); - } this.inboxPath = path; } const callbacks: CollectionCallbacks< @@ -706,7 +694,7 @@ export class FederationBuilderImpl } setOutboxDispatcher( - path: `${string}{identifier}${string}` | `${string}{handle}${string}`, + path: `${string}{identifier}${string}`, dispatcher: CollectionDispatcher< Activity, RequestContext, @@ -724,18 +712,12 @@ export class FederationBuilderImpl const variables = this.router.add(path, "outbox"); if ( variables.size !== 1 || - !(variables.has("identifier") || variables.has("handle")) + !variables.has("identifier") ) { throw new RouterError( "Path for outbox dispatcher must have one variable: {identifier}", ); } - if (variables.has("handle")) { - getLogger(["fedify", "federation", "outbox"]).warn( - "The {{handle}} variable in the outbox dispatcher path is deprecated. " + - "Use {{identifier}} instead.", - ); - } const callbacks: CollectionCallbacks< Activity, RequestContext, @@ -781,7 +763,7 @@ export class FederationBuilderImpl } setFollowingDispatcher( - path: `${string}{identifier}${string}` | `${string}{handle}${string}`, + path: `${string}{identifier}${string}`, dispatcher: CollectionDispatcher< Actor | URL, RequestContext, @@ -799,19 +781,13 @@ export class FederationBuilderImpl const variables = this.router.add(path, "following"); if ( variables.size !== 1 || - !(variables.has("identifier") || variables.has("handle")) + !variables.has("identifier") ) { throw new RouterError( "Path for following collection dispatcher must have one variable: " + "{identifier}", ); } - if (variables.has("handle")) { - getLogger(["fedify", "federation", "collection"]).warn( - "The {{handle}} variable in the following collection dispatcher path " + - "is deprecated. Use {{identifier}} instead.", - ); - } const callbacks: CollectionCallbacks< Actor | URL, RequestContext, @@ -857,7 +833,7 @@ export class FederationBuilderImpl } setFollowersDispatcher( - path: `${string}{identifier}${string}` | `${string}{handle}${string}`, + path: `${string}{identifier}${string}`, dispatcher: CollectionDispatcher< Recipient, Context, @@ -871,19 +847,13 @@ export class FederationBuilderImpl const variables = this.router.add(path, "followers"); if ( variables.size !== 1 || - !(variables.has("identifier") || variables.has("handle")) + !variables.has("identifier") ) { throw new RouterError( "Path for followers collection dispatcher must have one variable: " + "{identifier}", ); } - if (variables.has("handle")) { - getLogger(["fedify", "federation", "collection"]).warn( - "The {{handle}} variable in the followers collection dispatcher path " + - "is deprecated. Use {{identifier}} instead.", - ); - } const callbacks: CollectionCallbacks< Recipient, Context, @@ -921,7 +891,7 @@ export class FederationBuilderImpl } setLikedDispatcher( - path: `${string}{identifier}${string}` | `${string}{handle}${string}`, + path: `${string}{identifier}${string}`, dispatcher: CollectionDispatcher< Like, RequestContext, @@ -939,19 +909,13 @@ export class FederationBuilderImpl const variables = this.router.add(path, "liked"); if ( variables.size !== 1 || - !(variables.has("identifier") || variables.has("handle")) + !variables.has("identifier") ) { throw new RouterError( "Path for liked collection dispatcher must have one variable: " + "{identifier}", ); } - if (variables.has("handle")) { - getLogger(["fedify", "federation", "collection"]).warn( - "The {{handle}} variable in the liked collection dispatcher path " + - "is deprecated. Use {{identifier}} instead.", - ); - } const callbacks: CollectionCallbacks< Like, RequestContext, @@ -997,7 +961,7 @@ export class FederationBuilderImpl } setFeaturedDispatcher( - path: `${string}{identifier}${string}` | `${string}{handle}${string}`, + path: `${string}{identifier}${string}`, dispatcher: CollectionDispatcher< Object, RequestContext, @@ -1015,19 +979,13 @@ export class FederationBuilderImpl const variables = this.router.add(path, "featured"); if ( variables.size !== 1 || - !(variables.has("identifier") || variables.has("handle")) + !variables.has("identifier") ) { throw new RouterError( "Path for featured collection dispatcher must have one variable: " + "{identifier}", ); } - if (variables.has("handle")) { - getLogger(["fedify", "federation", "collection"]).warn( - "The {{handle}} variable in the featured collection dispatcher path " + - "is deprecated. Use {{identifier}} instead.", - ); - } const callbacks: CollectionCallbacks< Object, RequestContext, @@ -1073,7 +1031,7 @@ export class FederationBuilderImpl } setFeaturedTagsDispatcher( - path: `${string}{identifier}${string}` | `${string}{handle}${string}`, + path: `${string}{identifier}${string}`, dispatcher: CollectionDispatcher< Hashtag, RequestContext, @@ -1091,19 +1049,13 @@ export class FederationBuilderImpl const variables = this.router.add(path, "featuredTags"); if ( variables.size !== 1 || - !(variables.has("identifier") || variables.has("handle")) + !variables.has("identifier") ) { throw new RouterError( "Path for featured tags collection dispatcher must have one " + "variable: {identifier}", ); } - if (variables.has("handle")) { - getLogger(["fedify", "federation", "collection"]).warn( - "The {{handle}} variable in the featured tags collection dispatcher " + - "path is deprecated. Use {{identifier}} instead.", - ); - } const callbacks: CollectionCallbacks< Hashtag, RequestContext, @@ -1149,7 +1101,7 @@ export class FederationBuilderImpl } setInboxListeners( - inboxPath: `${string}{identifier}${string}` | `${string}{handle}${string}`, + inboxPath: `${string}{identifier}${string}`, sharedInboxPath?: string, ): InboxListenerSetters { if (this.inboxListeners != null) { @@ -1165,19 +1117,13 @@ export class FederationBuilderImpl const variables = this.router.add(inboxPath, "inbox"); if ( variables.size !== 1 || - !(variables.has("identifier") || variables.has("handle")) + !variables.has("identifier") ) { throw new RouterError( "Path for inbox must have one variable: {identifier}", ); } this.inboxPath = inboxPath; - if (variables.has("handle")) { - getLogger(["fedify", "federation", "inbox"]).warn( - "The {{handle}} variable in the inbox path is deprecated. " + - "Use {{identifier}} instead.", - ); - } } if (sharedInboxPath != null) { const siVars = this.router.add(sharedInboxPath, "sharedInbox"); diff --git a/packages/fedify/src/federation/federation.ts b/packages/fedify/src/federation/federation.ts index adae8fe08..cc2c39cb2 100644 --- a/packages/fedify/src/federation/federation.ts +++ b/packages/fedify/src/federation/federation.ts @@ -118,9 +118,7 @@ export interface Federatable { * @throws {RouterError} Thrown if the path pattern is invalid. */ setActorDispatcher( - path: - | `${string}${Rfc6570Expression<"identifier">}${string}` - | `${string}${Rfc6570Expression<"handle">}${string}`, + path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: ActorDispatcher, ): ActorCallbackSetters; @@ -257,9 +255,7 @@ export interface Federatable { * @throws {@link RouterError} Thrown if the path pattern is invalid. */ setInboxDispatcher( - path: - | `${string}${Rfc6570Expression<"identifier">}${string}` - | `${string}${Rfc6570Expression<"handle">}${string}`, + path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher< Activity, RequestContext, @@ -296,9 +292,7 @@ export interface Federatable { * @throws {@link RouterError} Thrown if the path pattern is invalid. */ setOutboxDispatcher( - path: - | `${string}${Rfc6570Expression<"identifier">}${string}` - | `${string}${Rfc6570Expression<"handle">}${string}`, + path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher< Activity, RequestContext, @@ -323,9 +317,7 @@ export interface Federatable { * @throws {RouterError} Thrown if the path pattern is invalid. */ setFollowingDispatcher( - path: - | `${string}${Rfc6570Expression<"identifier">}${string}` - | `${string}${Rfc6570Expression<"handle">}${string}`, + path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher< Actor | URL, RequestContext, @@ -350,9 +342,7 @@ export interface Federatable { * @throws {@link RouterError} Thrown if the path pattern is invalid. */ setFollowersDispatcher( - path: - | `${string}${Rfc6570Expression<"identifier">}${string}` - | `${string}${Rfc6570Expression<"handle">}${string}`, + path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher< Recipient, Context, @@ -373,9 +363,7 @@ export interface Federatable { * @throws {@link RouterError} Thrown if the path pattern is invalid. */ setLikedDispatcher( - path: - | `${string}${Rfc6570Expression<"identifier">}${string}` - | `${string}${Rfc6570Expression<"handle">}${string}`, + path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher< Object | URL, RequestContext, @@ -400,9 +388,7 @@ export interface Federatable { * @throws {@link RouterError} Thrown if the path pattern is invalid. */ setFeaturedDispatcher( - path: - | `${string}${Rfc6570Expression<"identifier">}${string}` - | `${string}${Rfc6570Expression<"handle">}${string}`, + path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher< Object, RequestContext, @@ -427,9 +413,7 @@ export interface Federatable { * @throws {@link RouterError} Thrown if the path pattern is invalid. */ setFeaturedTagsDispatcher( - path: - | `${string}${Rfc6570Expression<"identifier">}${string}` - | `${string}${Rfc6570Expression<"handle">}${string}`, + path: `${string}${Rfc6570Expression<"identifier">}${string}`, dispatcher: CollectionDispatcher< Hashtag, RequestContext, @@ -472,9 +456,7 @@ export interface Federatable { * @throws {RouterError} Thrown if the path pattern is invalid. */ setInboxListeners( - inboxPath: - | `${string}${Rfc6570Expression<"identifier">}${string}` - | `${string}${Rfc6570Expression<"handle">}${string}`, + inboxPath: `${string}${Rfc6570Expression<"identifier">}${string}`, sharedInboxPath?: string, ): InboxListenerSetters; diff --git a/packages/fedify/src/federation/handler.test.ts b/packages/fedify/src/federation/handler.test.ts index 37a37cd14..1dd257c2a 100644 --- a/packages/fedify/src/federation/handler.test.ts +++ b/packages/fedify/src/federation/handler.test.ts @@ -57,10 +57,10 @@ test("handleActor()", async () => { return new URL(`https://example.com/users/${identifier}`); }, }); - const actorDispatcher: ActorDispatcher = (ctx, handle) => { - if (handle !== "someone") return null; + const actorDispatcher: ActorDispatcher = (ctx, identifier) => { + if (identifier !== "someone") return null; return new Person({ - id: ctx.getActorUri(handle), + id: ctx.getActorUri(identifier), name: "Someone", }); }; @@ -284,7 +284,7 @@ test("handleObject()", async () => { values: Record, ) { return new URL( - `https://example.com/users/${values.handle}/notes/${values.id}`, + `https://example.com/users/${values.identifier}/notes/${values.id}`, ); }, }); @@ -292,7 +292,7 @@ test("handleObject()", async () => { ctx, values, ) => { - if (values.handle !== "someone" || values.id !== "123") return null; + if (values.identifier !== "someone" || values.id !== "123") return null; return new Note({ id: ctx.getObjectUri(Note, values), summary: "Hello, world!", @@ -312,7 +312,7 @@ test("handleObject()", async () => { context.request, { context, - values: { handle: "someone", id: "123" }, + values: { identifier: "someone", id: "123" }, onNotFound, onUnauthorized, }, @@ -326,7 +326,7 @@ test("handleObject()", async () => { context.request, { context, - values: { handle: "someone", id: "123" }, + values: { identifier: "someone", id: "123" }, objectDispatcher, onNotFound, onUnauthorized, @@ -340,7 +340,7 @@ test("handleObject()", async () => { context.request, { context, - values: { handle: "no-one", id: "123" }, + values: { identifier: "no-one", id: "123" }, objectDispatcher, onNotFound, onUnauthorized, @@ -355,7 +355,7 @@ test("handleObject()", async () => { context.request, { context, - values: { handle: "someone", id: "not-exist" }, + values: { identifier: "someone", id: "not-exist" }, objectDispatcher, onNotFound, onUnauthorized, @@ -378,7 +378,7 @@ test("handleObject()", async () => { context.request, { context, - values: { handle: "someone", id: "123" }, + values: { identifier: "someone", id: "123" }, objectDispatcher, onNotFound, onUnauthorized, @@ -420,7 +420,7 @@ test("handleObject()", async () => { context.request, { context, - values: { handle: "no-one", id: "123" }, + values: { identifier: "no-one", id: "123" }, objectDispatcher, onNotFound, onUnauthorized, @@ -435,7 +435,7 @@ test("handleObject()", async () => { context.request, { context, - values: { handle: "someone", id: "not-exist" }, + values: { identifier: "someone", id: "not-exist" }, objectDispatcher, onNotFound, onUnauthorized, @@ -450,7 +450,7 @@ test("handleObject()", async () => { context.request, { context, - values: { handle: "someone", id: "123" }, + values: { identifier: "someone", id: "123" }, objectDispatcher, authorizePredicate: (_ctx, _values, signedKey, signedKeyOwner) => signedKey != null && signedKeyOwner != null, @@ -472,7 +472,7 @@ test("handleObject()", async () => { context.request, { context, - values: { handle: "someone", id: "123" }, + values: { identifier: "someone", id: "123" }, objectDispatcher, authorizePredicate: (_ctx, _values, signedKey, signedKeyOwner) => signedKey != null && signedKeyOwner != null, @@ -530,10 +530,10 @@ test("handleCollection()", async () => { void > = ( _ctx, - handle, + identifier, cursor, ) => { - if (handle !== "someone") return null; + if (identifier !== "someone") return null; const items = [ new Create({ id: new URL("https://example.com/activities/1") }), new Create({ id: new URL("https://example.com/activities/2") }), @@ -549,16 +549,16 @@ test("handleCollection()", async () => { } return { items }; }; - const counter: CollectionCounter = (_ctx, handle) => - handle === "someone" ? 3 : null; + const counter: CollectionCounter = (_ctx, identifier) => + identifier === "someone" ? 3 : null; const firstCursor: CollectionCursor, void, void> = ( _ctx, - handle, - ) => handle === "someone" ? "0" : null; + identifier, + ) => identifier === "someone" ? "0" : null; const lastCursor: CollectionCursor, void, void> = ( _ctx, - handle, - ) => handle === "someone" ? "2" : null; + identifier, + ) => identifier === "someone" ? "2" : null; let onNotFoundCalled: Request | null = null; const onNotFound = (request: Request) => { onNotFoundCalled = request; @@ -1433,7 +1433,7 @@ test("handleCustomCollection()", async () => { values: Record, cursor: string | null, ) => { - if (values.handle !== "someone") return null; + if (values.identifier !== "someone") return null; const items = [ new Create({ id: new URL("https://example.com/activities/1") }), new Create({ id: new URL("https://example.com/activities/2") }), @@ -1453,7 +1453,7 @@ test("handleCustomCollection()", async () => { const counter: CustomCollectionCounter = ( _ctx: RequestContext, values: Record, - ) => values.handle === "someone" ? 3 : null; + ) => values.identifier === "someone" ? 3 : null; const firstCursor: CustomCollectionCursor< string, @@ -1462,7 +1462,7 @@ test("handleCustomCollection()", async () => { > = ( _ctx: RequestContext, values: Record, - ) => values.handle === "someone" ? "0" : null; + ) => values.identifier === "someone" ? "0" : null; const lastCursor: CustomCollectionCursor< string, @@ -1471,7 +1471,7 @@ test("handleCustomCollection()", async () => { > = ( _ctx: RequestContext, values: Record, - ) => values.handle === "someone" ? "2" : null; + ) => values.identifier === "someone" ? "2" : null; const callbacks: CustomCollectionCallbacks< Create, @@ -1506,7 +1506,7 @@ test("handleCustomCollection()", async () => { { context, name: "custom collection", - values: { handle: "someone" }, + values: { identifier: "someone" }, ...errorHandlers, }, ); @@ -1514,7 +1514,7 @@ test("handleCustomCollection()", async () => { assertEquals(onNotFoundCalled, context.request); assertEquals(onUnauthorizedCalled, null); - // Test with unknown handle (should return 404) + // Test with unknown identifier (should return 404) context = createRequestContext({ ...context, request: new Request(context.url, { @@ -1528,7 +1528,7 @@ test("handleCustomCollection()", async () => { { context, name: "custom collection", - values: { handle: "no-one" }, + values: { identifier: "no-one" }, collectionCallbacks: { dispatcher }, ...errorHandlers, }, @@ -1544,7 +1544,7 @@ test("handleCustomCollection()", async () => { { context, name: "custom collection", - values: { handle: "someone" }, + values: { identifier: "someone" }, collectionCallbacks: { dispatcher }, ...errorHandlers, }, @@ -1631,7 +1631,7 @@ test("handleCustomCollection()", async () => { { context, name: "custom collection", - values: { handle: "someone" }, + values: { identifier: "someone" }, collectionCallbacks: { dispatcher, authorizePredicate: (_ctx, _values, key, keyOwner) => @@ -1656,7 +1656,7 @@ test("handleCustomCollection()", async () => { { context, name: "custom collection", - values: { handle: "someone" }, + values: { identifier: "someone" }, collectionCallbacks: { dispatcher, authorizePredicate: (_ctx, _values, key, keyOwner) => @@ -1701,7 +1701,7 @@ test("handleCustomCollection()", async () => { { context, name: "custom collection", - values: { handle: "someone" }, + values: { identifier: "someone" }, collectionCallbacks: callbacks, ...errorHandlers, }, @@ -1738,7 +1738,7 @@ test("handleCustomCollection()", async () => { { context, name: "custom collection", - values: { handle: "someone" }, + values: { identifier: "someone" }, collectionCallbacks: callbacks, ...errorHandlers, }, @@ -1779,7 +1779,7 @@ test("handleCustomCollection()", async () => { { context, name: "custom collection", - values: { handle: "someone" }, + values: { identifier: "someone" }, collectionCallbacks: callbacks, ...errorHandlers, }, @@ -1845,10 +1845,10 @@ test("handleInbox() records OpenTelemetry span events", async () => { }, }); - const actorDispatcher: ActorDispatcher = (ctx, handle) => { - if (handle !== "someone") return null; + const actorDispatcher: ActorDispatcher = (ctx, identifier) => { + if (identifier !== "someone") return null; return new Person({ - id: ctx.getActorUri(handle), + id: ctx.getActorUri(identifier), name: "Someone", inbox: new URL("https://example.com/users/someone/inbox"), publicKey: rsaPublicKey2, diff --git a/packages/fedify/src/federation/middleware.test.ts b/packages/fedify/src/federation/middleware.test.ts index 2265db3a8..dd2cb5a48 100644 --- a/packages/fedify/src/federation/middleware.test.ts +++ b/packages/fedify/src/federation/middleware.test.ts @@ -1260,7 +1260,7 @@ test("Federation.setInboxListeners()", async (t) => { RouterError, ); assertThrows( - () => federation.setInboxListeners("/users/{identifier}/inbox/{handle}"), + () => federation.setInboxListeners("/users/{identifier}/inbox/{extra}"), RouterError, ); assertThrows( diff --git a/packages/fedify/src/federation/middleware.ts b/packages/fedify/src/federation/middleware.ts index 0994b23cf..6d3b62527 100644 --- a/packages/fedify/src/federation/middleware.ts +++ b/packages/fedify/src/federation/middleware.ts @@ -1402,11 +1402,11 @@ export class FederationImpl case "actor": context = this.#createContext(request, contextData, { invokedFromActorDispatcher: { - identifier: route.values.identifier ?? route.values.handle, + identifier: route.values.identifier, }, }); return await handleActor(request, { - identifier: route.values.identifier ?? route.values.handle, + identifier: route.values.identifier, context, actorDispatcher: this.actorCallbacks?.dispatcher, authorizePredicate: this.actorCallbacks?.authorizePredicate, @@ -1432,7 +1432,7 @@ export class FederationImpl case "outbox": return await handleCollection(request, { name: "outbox", - identifier: route.values.identifier ?? route.values.handle, + identifier: route.values.identifier, uriGetter: context.getOutboxUri.bind(context), context, collectionCallbacks: this.outboxCallbacks, @@ -1444,7 +1444,7 @@ export class FederationImpl if (request.method !== "POST") { return await handleCollection(request, { name: "inbox", - identifier: route.values.identifier ?? route.values.handle, + identifier: route.values.identifier, uriGetter: context.getInboxUri.bind(context), context, collectionCallbacks: this.inboxCallbacks, @@ -1455,7 +1455,7 @@ export class FederationImpl } context = this.#createContext(request, contextData, { documentLoader: await context.getDocumentLoader({ - identifier: route.values.identifier ?? route.values.handle, + identifier: route.values.identifier, }), }); // falls through @@ -1472,7 +1472,7 @@ export class FederationImpl } if (!this.manuallyStartQueue) this._startQueueInternal(contextData); return await handleInbox(request, { - recipient: route.values.identifier ?? route.values.handle ?? null, + recipient: route.values.identifier ?? null, context, inboxContextFactory: context.toInboxContext.bind(context), kv: this.kv, @@ -1490,7 +1490,7 @@ export class FederationImpl case "following": return await handleCollection(request, { name: "following", - identifier: route.values.identifier ?? route.values.handle, + identifier: route.values.identifier, uriGetter: context.getFollowingUri.bind(context), context, collectionCallbacks: this.followingCallbacks, @@ -1510,7 +1510,7 @@ export class FederationImpl } return await handleCollection(request, { name: "followers", - identifier: route.values.identifier ?? route.values.handle, + identifier: route.values.identifier, uriGetter: baseUrl == null ? context.getFollowersUri.bind(context) : (identifier) => { @@ -1535,7 +1535,7 @@ export class FederationImpl case "liked": return await handleCollection(request, { name: "liked", - identifier: route.values.identifier ?? route.values.handle, + identifier: route.values.identifier, uriGetter: context.getLikedUri.bind(context), context, collectionCallbacks: this.likedCallbacks, @@ -1546,7 +1546,7 @@ export class FederationImpl case "featured": return await handleCollection(request, { name: "featured", - identifier: route.values.identifier ?? route.values.handle, + identifier: route.values.identifier, uriGetter: context.getFeaturedUri.bind(context), context, collectionCallbacks: this.featuredCallbacks, @@ -1557,7 +1557,7 @@ export class FederationImpl case "featuredTags": return await handleCollection(request, { name: "featured tags", - identifier: route.values.identifier ?? route.values.handle, + identifier: route.values.identifier, uriGetter: context.getFeaturedTagsUri.bind(context), context, collectionCallbacks: this.featuredTagsCallbacks, @@ -1707,7 +1707,7 @@ export class ContextImpl implements Context { getActorUri(identifier: string): URL { const path = this.federation.router.build( "actor", - { identifier, handle: identifier }, + { identifier }, ); if (path == null) { throw new RouterError("No actor dispatcher registered."); @@ -1741,7 +1741,7 @@ export class ContextImpl implements Context { getOutboxUri(identifier: string): URL { const path = this.federation.router.build( "outbox", - { identifier, handle: identifier }, + { identifier }, ); if (path == null) { throw new RouterError("No outbox dispatcher registered."); @@ -1761,7 +1761,7 @@ export class ContextImpl implements Context { } const path = this.federation.router.build( "inbox", - { identifier, handle: identifier }, + { identifier }, ); if (path == null) { throw new RouterError("No inbox path registered."); @@ -1772,7 +1772,7 @@ export class ContextImpl implements Context { getFollowingUri(identifier: string): URL { const path = this.federation.router.build( "following", - { identifier, handle: identifier }, + { identifier }, ); if (path == null) { throw new RouterError("No following collection path registered."); @@ -1783,7 +1783,7 @@ export class ContextImpl implements Context { getFollowersUri(identifier: string): URL { const path = this.federation.router.build( "followers", - { identifier, handle: identifier }, + { identifier }, ); if (path == null) { throw new RouterError("No followers collection path registered."); @@ -1794,7 +1794,7 @@ export class ContextImpl implements Context { getLikedUri(identifier: string): URL { const path = this.federation.router.build( "liked", - { identifier, handle: identifier }, + { identifier }, ); if (path == null) { throw new RouterError("No liked collection path registered."); @@ -1805,7 +1805,7 @@ export class ContextImpl implements Context { getFeaturedUri(identifier: string): URL { const path = this.federation.router.build( "featured", - { identifier, handle: identifier }, + { identifier }, ); if (path == null) { throw new RouterError("No featured collection path registered."); @@ -1816,7 +1816,7 @@ export class ContextImpl implements Context { getFeaturedTagsUri(identifier: string): URL { const path = this.federation.router.build( "featuredTags", - { identifier, handle: identifier }, + { identifier }, ); if (path == null) { throw new RouterError("No featured tags collection path registered."); @@ -1854,9 +1854,7 @@ export class ContextImpl implements Context { identifier: undefined, }; } - const identifier = "identifier" in route.values - ? route.values.identifier - : route.values.handle; + const identifier = route.values.identifier; if (route.name === "actor") { return { type: "actor", diff --git a/packages/testing/src/mock.ts b/packages/testing/src/mock.ts index 5984de1fc..a77fedcb5 100644 --- a/packages/testing/src/mock.ts +++ b/packages/testing/src/mock.ts @@ -52,7 +52,7 @@ const noopTracerProvider: any = { /** * Helper function to expand URI templates with values. - * Supports simple placeholders like {identifier}, {handle}, etc. + * Supports simple placeholders like {identifier}, etc. * @param template The URI template pattern * @param values The values to substitute * @returns The expanded URI path @@ -695,7 +695,6 @@ class MockContext implements Context { ) { const path = expandUriTemplate(this.federation.actorPath, { identifier, - handle: identifier, }); return new URL(path, this.origin); } @@ -725,7 +724,6 @@ class MockContext implements Context { ) { const path = expandUriTemplate(this.federation.outboxPath, { identifier, - handle: identifier, }); return new URL(path, this.origin); } @@ -739,7 +737,6 @@ class MockContext implements Context { ) { const path = expandUriTemplate(this.federation.inboxPath, { identifier, - handle: identifier, }); return new URL(path, this.origin); } @@ -760,7 +757,6 @@ class MockContext implements Context { ) { const path = expandUriTemplate(this.federation.followingPath, { identifier, - handle: identifier, }); return new URL(path, this.origin); } @@ -773,7 +769,6 @@ class MockContext implements Context { ) { const path = expandUriTemplate(this.federation.followersPath, { identifier, - handle: identifier, }); return new URL(path, this.origin); } @@ -786,7 +781,6 @@ class MockContext implements Context { ) { const path = expandUriTemplate(this.federation.likedPath, { identifier, - handle: identifier, }); return new URL(path, this.origin); } @@ -799,7 +793,6 @@ class MockContext implements Context { ) { const path = expandUriTemplate(this.federation.featuredPath, { identifier, - handle: identifier, }); return new URL(path, this.origin); } @@ -813,7 +806,6 @@ class MockContext implements Context { ) { const path = expandUriTemplate(this.federation.featuredTagsPath, { identifier, - handle: identifier, }); return new URL(path, this.origin); } From 8d8b45a7bfb476c23767dd1db4ee39b739aee2d5 Mon Sep 17 00:00:00 2001 From: ChanHaeng Lee <2chanhaeng@gmail.com> Date: Sat, 14 Feb 2026 19:51:22 +0000 Subject: [PATCH 4/4] Replace `handle` to `identifier` --- CHANGES.md | 11 +++++++++++ docs/manual/federation.md | 14 +++++++------- docs/manual/integration.md | 10 +++++----- examples/express/federation.ts | 8 ++++---- examples/express/index.ts | 4 ++-- examples/h3/federation.ts | 8 ++++---- examples/h3/index.ts | 4 ++-- examples/koa/federation.ts | 8 ++++---- 8 files changed, 39 insertions(+), 28 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ad24859f0..d7424a7a7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -30,6 +30,17 @@ To be released. `FederationOptions` interface in favor of `documentLoaderFactory` option for better flexibility. [[#376], [#393] by Hasang Cho] + - Remove `CreateFederationOptions` interface (which was + deprecated since 1.6.0). Use `FederationOptions` instead. + [[#376]] + + - Remove `fetchDocumentLoader()` function (which was deprecated since 0.14.0). + Use `getDocumentLoader()` from `@fedify/vocab-runtime` instead. [[#376]] + + - Remove `{ handle: string }` parameter form from `sendActivity()`, + `forwardActivity()`, `getDocumentLoader()`, and `ParseUriResult`. + Use `{ identifier: string }` or `{ username: string }` instead. [[#376]] + - Changed NodeInfo `software.version` field type from `SemVer` to `string` to properly handle non-SemVer version strings in accordance with the NodeInfo specification. [[#366], [#433] by Hyeonseo Kim] diff --git a/docs/manual/federation.md b/docs/manual/federation.md index 05ad46935..c6d7175c6 100644 --- a/docs/manual/federation.md +++ b/docs/manual/federation.md @@ -468,8 +468,8 @@ export const builder = createFederationBuilder(); // Register your dispatchers and listeners here... builder.setActorDispatcher( - "/users/{handle}", - async (ctx, handle) => { + "/users/{identifier}", + async (ctx, identifier) => { // Omitted for brevity } ); @@ -499,8 +499,8 @@ import { Person } from "@fedify/vocab"; const builder = null as unknown as FederationBuilder; // ---cut-before--- builder.setActorDispatcher( - "/users/{handle}", - async (ctx, handle) => { + "/users/{identifier}", + async (ctx, identifier) => { const federation = ctx.federation; // Access the `Federation` object // Omitted for brevity // ---cut-start--- @@ -853,7 +853,7 @@ parameter within the `Context` object: import { type Federation } from "@fedify/fedify"; const federation = null as unknown as Federation; // ---cut-before--- -federation.setActorDispatcher("/users/{handle}", async (ctx, handle) => { +federation.setActorDispatcher("/users/{identifier}", async (ctx, identifier) => { // There is a database connection in `ctx.data`. }); ~~~~ @@ -882,8 +882,8 @@ the virtual host information: import { type Federation } from "@fedify/fedify"; const federation = null as unknown as Federation; // ---cut-before--- -federation.setActorDispatcher("/@{handle}", (ctx, handle) => { - const fullHandle = `${handle}@${ctx.host}`; +federation.setActorDispatcher("/@{identifier}", (ctx, identifier) => { + const fullHandle = `${identifier}@${ctx.host}`; // Omitted for brevity }); ~~~~ diff --git a/docs/manual/integration.md b/docs/manual/integration.md index c760a746d..c0f49f674 100644 --- a/docs/manual/integration.md +++ b/docs/manual/integration.md @@ -23,12 +23,12 @@ and port. For example, if you make a request to */.well-known/webfinger* Fedify will handle the request by itself, but if you make a request to */users/alice* -(assuming your web framework has a handler for `/users/:handle`) with +(assuming your web framework has a handler for `/users/:identifier`) with `Accept: text/html` header, Fedify will dispatch the request to the web -framework's appropriate handler for `/users/:handle`. Or if you define an -actor dispatcher for `/users/{handle}` in Fedify, and the request is made with -`Accept: application/activity+json` header, Fedify will dispatch the request to -the appropriate actor dispatcher. +framework's appropriate handler for `/users/:identifier`. Or if you define an +actor dispatcher for `/users/{identifier}` in Fedify, and the request is made +with `Accept: application/activity+json` header, Fedify will dispatch the +request to the appropriate actor dispatcher. Here is a diagram that illustrates the architecture: diff --git a/examples/express/federation.ts b/examples/express/federation.ts index adecd0360..73eb1bef6 100644 --- a/examples/express/federation.ts +++ b/examples/express/federation.ts @@ -5,16 +5,16 @@ export const federation = createFederation({ kv: new MemoryKvStore(), }); -federation.setActorDispatcher("/users/{handle}", (ctx, handle) => { +federation.setActorDispatcher("/users/{identifier}", (ctx, identifier) => { return new Person({ - id: ctx.getActorUri(handle), - preferredUsername: handle, + id: ctx.getActorUri(identifier), + preferredUsername: identifier, }); }); federation.setObjectDispatcher( Note, - "/users/{handle}/{id}", + "/users/{identifier}/{id}", (ctx, values) => { return new Note({ id: ctx.getObjectUri(Note, values), diff --git a/examples/express/index.ts b/examples/express/index.ts index a847e15c7..364709692 100644 --- a/examples/express/index.ts +++ b/examples/express/index.ts @@ -8,8 +8,8 @@ app.set("trust proxy", true); app.use(integrateFederation(federation, () => undefined)); -app.get("/users/:handle", (req, res) => { - res.type("html").send(`

Hello, ${req.params.handle}!

`); +app.get("/users/:identifier", (req, res) => { + res.type("html").send(`

Hello, ${req.params.identifier}!

`); }); app.listen(3000, () => { diff --git a/examples/h3/federation.ts b/examples/h3/federation.ts index adecd0360..73eb1bef6 100644 --- a/examples/h3/federation.ts +++ b/examples/h3/federation.ts @@ -5,16 +5,16 @@ export const federation = createFederation({ kv: new MemoryKvStore(), }); -federation.setActorDispatcher("/users/{handle}", (ctx, handle) => { +federation.setActorDispatcher("/users/{identifier}", (ctx, identifier) => { return new Person({ - id: ctx.getActorUri(handle), - preferredUsername: handle, + id: ctx.getActorUri(identifier), + preferredUsername: identifier, }); }); federation.setObjectDispatcher( Note, - "/users/{handle}/{id}", + "/users/{identifier}/{id}", (ctx, values) => { return new Note({ id: ctx.getObjectUri(Note, values), diff --git a/examples/h3/index.ts b/examples/h3/index.ts index 3235c064b..fd775ae2f 100644 --- a/examples/h3/index.ts +++ b/examples/h3/index.ts @@ -18,10 +18,10 @@ const router = createRouter(); app.use(router); router.get( - "/users/:handle", + "/users/:identifier", defineEventHandler((event) => { setResponseHeader(event, "Content-Type", "text/html"); - return `

Hello ${event.context.params?.["handle"]}

`; + return `

Hello ${event.context.params?.["identifier"]}

`; }), ); diff --git a/examples/koa/federation.ts b/examples/koa/federation.ts index adecd0360..73eb1bef6 100644 --- a/examples/koa/federation.ts +++ b/examples/koa/federation.ts @@ -5,16 +5,16 @@ export const federation = createFederation({ kv: new MemoryKvStore(), }); -federation.setActorDispatcher("/users/{handle}", (ctx, handle) => { +federation.setActorDispatcher("/users/{identifier}", (ctx, identifier) => { return new Person({ - id: ctx.getActorUri(handle), - preferredUsername: handle, + id: ctx.getActorUri(identifier), + preferredUsername: identifier, }); }); federation.setObjectDispatcher( Note, - "/users/{handle}/{id}", + "/users/{identifier}/{id}", (ctx, values) => { return new Note({ id: ctx.getObjectUri(Note, values),