Loading CHANGES.md +66 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,72 @@ Version 1.0.0 To be released. - The term `handle` for dispatching actors is deprecated in favor of `identifier`. - The URI template for the following methods now accepts variable `{identifier}` instead of `{handle}`: - `Federation.setActorDispatcher()` - `Federation.setInboxDispatcher()` - `Federation.setOutboxDispatcher()` - `Federation.setFollowingDispatcher()` - `Federation.setFollowersDispatcher()` - `Federation.setLikedDispatcher()` - `Federation.setFeaturedDispatcher()` - `Federation.setFeaturedTagsDispatcher()` - `Federation.setInboxListeners()` The `{handle}` variable is deprecated, and it will be removed in the future. - The type of `Federation.setActorDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setInboxDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setOutboxDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setFollowingDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setFollowersDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setLikedDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setFeaturedDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setFeaturedTagsDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setInboxListeners()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Context.getDocumentLoader()` method's first parameter became `{ identifier: string } | { username: string } | { handle: string } | { keyId: URL; privateKey: CryptoKey }` (was `{ handle: string } | { keyId: URL; privateKey: CryptoKey }`). - Passing `{ handle: string }` to `Context.getDocumentLoader()` method is deprecated in favor of `{ username: string }`. - The type of `Context.sendActivity()` method's first parameter became `SenderKeyPair | SenderKeyPair[] | { identifier: string } | { username: string } | { handle: string }` (was `SenderKeyPair | SenderKeyPair[] | { handle: string }`). - All properties of `ParseUriResult` type became readonly. - Added `identifier` properties next to `handle` properties in `ParseUriResult` type. - The `handle` properties of `ParseUriResult` type are deprecated in favor of `identifier` properties. - The return type of `SharedInboxKeyDispatcher` callback type became `SenderKeyPair | { identifier: string } | { username: string } | { handle: string } | null | Promise<SenderKeyPair | { identifier: string } | { username: string } | { handle: string } | null>` (was `SenderKeyPair | { handle: string } | null | Promise<SenderKeyPair | { handle: string } | null>`). - Fedify now supports [Linked Data Signatures], which is outdated but still widely used in the fediverse. Loading cli/inbox.tsx +35 −30 Original line number Diff line number Diff line Loading @@ -96,7 +96,9 @@ export const command = new Command() } if (options.follow != null && options.follow.length > 0) { spinner.text = "Following actors..."; const documentLoader = await fedCtx.getDocumentLoader({ handle: "i" }); const documentLoader = await fedCtx.getDocumentLoader({ identifier: "i", }); for (const uri of options.follow) { spinner.text = `Following ${colors.green(uri)}...`; const actor = await lookupObject(uri, { documentLoader }); Loading @@ -107,7 +109,7 @@ export const command = new Command() } if (actor.id != null) peers[actor.id?.href] = actor; await fedCtx.sendActivity( { handle: "i" }, { identifier: "i" }, actor, new Follow({ id: new URL(`#follows/${actor.id?.href}`, fedCtx.getActorUri("i")), Loading @@ -132,34 +134,34 @@ const time = Temporal.Now.instant(); let actorKeyPairs: CryptoKeyPair[] | undefined = undefined; federation .setActorDispatcher("/{handle}", async (ctx, handle) => { if (handle !== "i") return null; .setActorDispatcher("/{identifier}", async (ctx, identifier) => { if (identifier !== "i") return null; return new Application({ id: ctx.getActorUri(handle), preferredUsername: handle, id: ctx.getActorUri(identifier), preferredUsername: identifier, name: "Fedify Ephemeral Inbox", summary: "An ephemeral ActivityPub inbox for testing purposes.", inbox: ctx.getInboxUri(handle), inbox: ctx.getInboxUri(identifier), endpoints: new Endpoints({ sharedInbox: ctx.getInboxUri(), }), followers: ctx.getFollowersUri(handle), following: ctx.getFollowingUri(handle), outbox: ctx.getOutboxUri(handle), followers: ctx.getFollowersUri(identifier), following: ctx.getFollowingUri(identifier), outbox: ctx.getOutboxUri(identifier), manuallyApprovesFollowers: true, published: time, icon: new Image({ url: new URL("https://fedify.dev/logo.png"), mediaType: "image/png", }), publicKey: (await ctx.getActorKeyPairs(handle))[0].cryptographicKey, assertionMethods: (await ctx.getActorKeyPairs(handle)) publicKey: (await ctx.getActorKeyPairs(identifier))[0].cryptographicKey, assertionMethods: (await ctx.getActorKeyPairs(identifier)) .map((pair) => pair.multikey), url: ctx.getActorUri(handle), url: ctx.getActorUri(identifier), }); }) .setKeyPairsDispatcher(async (_ctxData, handle) => { if (handle !== "i") return []; .setKeyPairsDispatcher(async (_ctxData, identifier) => { if (identifier !== "i") return []; if (actorKeyPairs == null) { actorKeyPairs = [ await generateCryptoKeyPair("RSASSA-PKCS1-v1_5"), Loading Loading @@ -195,7 +197,7 @@ async function sendDeleteToPeers(server: TemporaryServer): Promise<void> { const ctx = federation.createContext(server.url, -1); const actorId = ctx.getActorUri("i"); await ctx.sendActivity( { handle: "i" }, { identifier: "i" }, Object.values(peers), new Delete({ id: new URL(`#delete`, actorId), Loading @@ -209,8 +211,8 @@ async function sendDeleteToPeers(server: TemporaryServer): Promise<void> { const followers: Record<string, Actor> = {}; federation .setInboxListeners("/{handle}/inbox", "/inbox") .setSharedKeyDispatcher((_) => ({ handle: "i" })) .setInboxListeners("/{identifier}/inbox", "/inbox") .setSharedKeyDispatcher((_) => ({ identifier: "i" })) .on(Activity, async (ctx, activity) => { activities[ctx.data].activity = activity; for await (const actor of activity.getActors()) { Loading @@ -224,8 +226,8 @@ federation const objectId = activity.objectId; if (objectId == null) return; const parsed = ctx.parseUri(objectId); if (parsed?.type !== "actor" || parsed.handle !== "i") return; const { handle } = parsed; if (parsed?.type !== "actor" || parsed.identifier !== "i") return; const { identifier } = parsed; const follower = await activity.getActor(); if (!isActor(follower)) return; const accepts = await acceptsFollowFrom(follower); Loading @@ -240,11 +242,11 @@ federation }); followers[activity.id.href] = follower; await ctx.sendActivity( { handle }, { identifier }, follower, new Accept({ id: new URL(`#accepts/${follower.id?.href}`, ctx.getActorUri("i")), actor: ctx.getActorUri(handle), actor: ctx.getActorUri(identifier), object: activity.id, }), ); Loading @@ -252,8 +254,8 @@ federation }); federation .setFollowersDispatcher("/{handle}/followers", (_ctx, handle) => { if (handle !== "i") return null; .setFollowersDispatcher("/{identifier}/followers", (_ctx, identifier) => { if (identifier !== "i") return null; const items: Recipient[] = []; for (const follower of Object.values(followers)) { if (follower.id == null) continue; Loading @@ -261,18 +263,21 @@ federation } return { items }; }) .setCounter((_ctx, handle) => { if (handle !== "i") return null; .setCounter((_ctx, identifier) => { if (identifier !== "i") return null; return Object.keys(followers).length; }); federation .setFollowingDispatcher("/{handle}/following", (_ctx, _handle) => null) .setCounter((_ctx, _handle) => 0); .setFollowingDispatcher( "/{identifier}/following", (_ctx, _identifier) => null, ) .setCounter((_ctx, _identifier) => 0); federation .setOutboxDispatcher("/{handle}/outbox", (_ctx, _handle) => null) .setCounter((_ctx, _handle) => 0); .setOutboxDispatcher("/{identifier}/outbox", (_ctx, _identifier) => null) .setCounter((_ctx, _identifier) => 0); federation.setNodeInfoDispatcher("/nodeinfo/2.1", (_ctx) => { return { Loading cli/init.ts +4 −4 Original line number Diff line number Diff line Loading @@ -845,11 +845,11 @@ const federation = createFederation({ queue: ${mqDesc.object}, }); federation.setActorDispatcher("/users/{handle}", async (ctx, handle) => { federation.setActorDispatcher("/users/{identifier}", async (ctx, identifier) => { return new Person({ id: ctx.getActorUri(handle), preferredUsername: handle, name: handle, id: ctx.getActorUri(identifier), preferredUsername: identifier, name: identifier, }); }); Loading docs/manual/access-control.md +16 −14 Original line number Diff line number Diff line Loading @@ -42,11 +42,11 @@ import type { Actor, Federation } from "@fedify/fedify"; const federation = null as unknown as Federation<void>; /** * A hypothetical function that checks if the user blocks the actor. * @param handle The handle of the user to check if the actor is blocked. * @param userId The ID of the user to check if the actor is blocked. * @param signedKeyOwner The actor who signed the request. * @returns `true` if the actor is blocked; otherwise, `false`. */ async function isBlocked(handle: string, signedKeyOwner: Actor): Promise<boolean> { async function isBlocked(userId: string, signedKeyOwner: Actor): Promise<boolean> { return false; } // ---cut-before--- Loading @@ -54,12 +54,12 @@ import { federation } from "./your-federation.ts"; import { isBlocked } from "./your-blocklist.ts"; federation .setActorDispatcher("/users/{handle}", async (ctx, handle) => { .setActorDispatcher("/users/{identifier}", async (ctx, identifier) => { // Omitted for brevity; see the related section for details. }) .authorize(async (ctx, handle, signedKey, signedKeyOwner) => { .authorize(async (ctx, identifier, signedKey, signedKeyOwner) => { if (signedKeyOwner == null) return false; return !await isBlocked(handle, signedKeyOwner); return !await isBlocked(identifier, signedKeyOwner); }); ~~~~ Loading @@ -74,11 +74,11 @@ import type { Actor, Federation } from "@fedify/fedify"; const federation = null as unknown as Federation<void>; /** * A hypothetical function that checks if the user blocks the actor. * @param handle The handle of the user to check if the actor is blocked. * @param userId The ID of the user to check if the actor is blocked. * @param signedKeyOwner The actor who signed the request. * @returns `true` if the actor is blocked; otherwise, `false`. */ async function isBlocked(handle: string, signedKeyOwner: Actor): Promise<boolean> { async function isBlocked(userId: string, signedKeyOwner: Actor): Promise<boolean> { return false; } // ---cut-before--- Loading @@ -86,12 +86,12 @@ import { federation } from "./your-federation.ts"; import { isBlocked } from "./your-blocklist.ts"; federation .setOutboxDispatcher("/users/{handle}/outbox", async (ctx, handle) => { .setOutboxDispatcher("/users/{identifier}/outbox", async (ctx, identifier) => { // Omitted for brevity; see the related section for details. }) .authorize(async (ctx, handle, signedKey, signedKeyOwner) => { .authorize(async (ctx, identifier, signedKey, signedKeyOwner) => { if (signedKeyOwner == null) return false; return !await isBlocked(handle, signedKeyOwner); return !await isBlocked(identifier, signedKeyOwner); }); ~~~~ Loading Loading @@ -126,10 +126,10 @@ interface Post { } /** * A hypothetical function that gets posts from the database. * @param handle The handle of the user to get posts. * @param userId The ID of the user to get posts. * @returns The posts of the user. */ async function getPosts(handle: string): Promise<Post[]> { async function getPosts(userId: string): Promise<Post[]> { return []; } /** Loading @@ -145,8 +145,8 @@ import { federation } from "./your-federation.ts"; import { getPosts, toCreate } from "./your-model.ts"; federation .setOutboxDispatcher("/users/{handle}/outbox", async (ctx, handle) => { const posts = await getPosts(handle); // Get posts from the database .setOutboxDispatcher("/users/{identifier}/outbox", async (ctx, identifier) => { const posts = await getPosts(identifier); // Get posts from the database const keyOwner = await ctx.getSignedKeyOwner(); // Get the actor who signed the request if (keyOwner == null) return { items: [] }; // Return an empty array if the actor is not found const items = posts Loading @@ -155,3 +155,5 @@ federation return { items }; }); ~~~~ <!-- cSpell: ignore blocklist --> docs/manual/actor.md +107 −42 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
CHANGES.md +66 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,72 @@ Version 1.0.0 To be released. - The term `handle` for dispatching actors is deprecated in favor of `identifier`. - The URI template for the following methods now accepts variable `{identifier}` instead of `{handle}`: - `Federation.setActorDispatcher()` - `Federation.setInboxDispatcher()` - `Federation.setOutboxDispatcher()` - `Federation.setFollowingDispatcher()` - `Federation.setFollowersDispatcher()` - `Federation.setLikedDispatcher()` - `Federation.setFeaturedDispatcher()` - `Federation.setFeaturedTagsDispatcher()` - `Federation.setInboxListeners()` The `{handle}` variable is deprecated, and it will be removed in the future. - The type of `Federation.setActorDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setInboxDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setOutboxDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setFollowingDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setFollowersDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setLikedDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setFeaturedDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setFeaturedTagsDispatcher()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Federation.setInboxListeners()` method's first parameter became ```${string}{identifier}${string}` | `${string}{handle}${string}``` (was ```${string}{handle}${string}```). - The type of `Context.getDocumentLoader()` method's first parameter became `{ identifier: string } | { username: string } | { handle: string } | { keyId: URL; privateKey: CryptoKey }` (was `{ handle: string } | { keyId: URL; privateKey: CryptoKey }`). - Passing `{ handle: string }` to `Context.getDocumentLoader()` method is deprecated in favor of `{ username: string }`. - The type of `Context.sendActivity()` method's first parameter became `SenderKeyPair | SenderKeyPair[] | { identifier: string } | { username: string } | { handle: string }` (was `SenderKeyPair | SenderKeyPair[] | { handle: string }`). - All properties of `ParseUriResult` type became readonly. - Added `identifier` properties next to `handle` properties in `ParseUriResult` type. - The `handle` properties of `ParseUriResult` type are deprecated in favor of `identifier` properties. - The return type of `SharedInboxKeyDispatcher` callback type became `SenderKeyPair | { identifier: string } | { username: string } | { handle: string } | null | Promise<SenderKeyPair | { identifier: string } | { username: string } | { handle: string } | null>` (was `SenderKeyPair | { handle: string } | null | Promise<SenderKeyPair | { handle: string } | null>`). - Fedify now supports [Linked Data Signatures], which is outdated but still widely used in the fediverse. Loading
cli/inbox.tsx +35 −30 Original line number Diff line number Diff line Loading @@ -96,7 +96,9 @@ export const command = new Command() } if (options.follow != null && options.follow.length > 0) { spinner.text = "Following actors..."; const documentLoader = await fedCtx.getDocumentLoader({ handle: "i" }); const documentLoader = await fedCtx.getDocumentLoader({ identifier: "i", }); for (const uri of options.follow) { spinner.text = `Following ${colors.green(uri)}...`; const actor = await lookupObject(uri, { documentLoader }); Loading @@ -107,7 +109,7 @@ export const command = new Command() } if (actor.id != null) peers[actor.id?.href] = actor; await fedCtx.sendActivity( { handle: "i" }, { identifier: "i" }, actor, new Follow({ id: new URL(`#follows/${actor.id?.href}`, fedCtx.getActorUri("i")), Loading @@ -132,34 +134,34 @@ const time = Temporal.Now.instant(); let actorKeyPairs: CryptoKeyPair[] | undefined = undefined; federation .setActorDispatcher("/{handle}", async (ctx, handle) => { if (handle !== "i") return null; .setActorDispatcher("/{identifier}", async (ctx, identifier) => { if (identifier !== "i") return null; return new Application({ id: ctx.getActorUri(handle), preferredUsername: handle, id: ctx.getActorUri(identifier), preferredUsername: identifier, name: "Fedify Ephemeral Inbox", summary: "An ephemeral ActivityPub inbox for testing purposes.", inbox: ctx.getInboxUri(handle), inbox: ctx.getInboxUri(identifier), endpoints: new Endpoints({ sharedInbox: ctx.getInboxUri(), }), followers: ctx.getFollowersUri(handle), following: ctx.getFollowingUri(handle), outbox: ctx.getOutboxUri(handle), followers: ctx.getFollowersUri(identifier), following: ctx.getFollowingUri(identifier), outbox: ctx.getOutboxUri(identifier), manuallyApprovesFollowers: true, published: time, icon: new Image({ url: new URL("https://fedify.dev/logo.png"), mediaType: "image/png", }), publicKey: (await ctx.getActorKeyPairs(handle))[0].cryptographicKey, assertionMethods: (await ctx.getActorKeyPairs(handle)) publicKey: (await ctx.getActorKeyPairs(identifier))[0].cryptographicKey, assertionMethods: (await ctx.getActorKeyPairs(identifier)) .map((pair) => pair.multikey), url: ctx.getActorUri(handle), url: ctx.getActorUri(identifier), }); }) .setKeyPairsDispatcher(async (_ctxData, handle) => { if (handle !== "i") return []; .setKeyPairsDispatcher(async (_ctxData, identifier) => { if (identifier !== "i") return []; if (actorKeyPairs == null) { actorKeyPairs = [ await generateCryptoKeyPair("RSASSA-PKCS1-v1_5"), Loading Loading @@ -195,7 +197,7 @@ async function sendDeleteToPeers(server: TemporaryServer): Promise<void> { const ctx = federation.createContext(server.url, -1); const actorId = ctx.getActorUri("i"); await ctx.sendActivity( { handle: "i" }, { identifier: "i" }, Object.values(peers), new Delete({ id: new URL(`#delete`, actorId), Loading @@ -209,8 +211,8 @@ async function sendDeleteToPeers(server: TemporaryServer): Promise<void> { const followers: Record<string, Actor> = {}; federation .setInboxListeners("/{handle}/inbox", "/inbox") .setSharedKeyDispatcher((_) => ({ handle: "i" })) .setInboxListeners("/{identifier}/inbox", "/inbox") .setSharedKeyDispatcher((_) => ({ identifier: "i" })) .on(Activity, async (ctx, activity) => { activities[ctx.data].activity = activity; for await (const actor of activity.getActors()) { Loading @@ -224,8 +226,8 @@ federation const objectId = activity.objectId; if (objectId == null) return; const parsed = ctx.parseUri(objectId); if (parsed?.type !== "actor" || parsed.handle !== "i") return; const { handle } = parsed; if (parsed?.type !== "actor" || parsed.identifier !== "i") return; const { identifier } = parsed; const follower = await activity.getActor(); if (!isActor(follower)) return; const accepts = await acceptsFollowFrom(follower); Loading @@ -240,11 +242,11 @@ federation }); followers[activity.id.href] = follower; await ctx.sendActivity( { handle }, { identifier }, follower, new Accept({ id: new URL(`#accepts/${follower.id?.href}`, ctx.getActorUri("i")), actor: ctx.getActorUri(handle), actor: ctx.getActorUri(identifier), object: activity.id, }), ); Loading @@ -252,8 +254,8 @@ federation }); federation .setFollowersDispatcher("/{handle}/followers", (_ctx, handle) => { if (handle !== "i") return null; .setFollowersDispatcher("/{identifier}/followers", (_ctx, identifier) => { if (identifier !== "i") return null; const items: Recipient[] = []; for (const follower of Object.values(followers)) { if (follower.id == null) continue; Loading @@ -261,18 +263,21 @@ federation } return { items }; }) .setCounter((_ctx, handle) => { if (handle !== "i") return null; .setCounter((_ctx, identifier) => { if (identifier !== "i") return null; return Object.keys(followers).length; }); federation .setFollowingDispatcher("/{handle}/following", (_ctx, _handle) => null) .setCounter((_ctx, _handle) => 0); .setFollowingDispatcher( "/{identifier}/following", (_ctx, _identifier) => null, ) .setCounter((_ctx, _identifier) => 0); federation .setOutboxDispatcher("/{handle}/outbox", (_ctx, _handle) => null) .setCounter((_ctx, _handle) => 0); .setOutboxDispatcher("/{identifier}/outbox", (_ctx, _identifier) => null) .setCounter((_ctx, _identifier) => 0); federation.setNodeInfoDispatcher("/nodeinfo/2.1", (_ctx) => { return { Loading
cli/init.ts +4 −4 Original line number Diff line number Diff line Loading @@ -845,11 +845,11 @@ const federation = createFederation({ queue: ${mqDesc.object}, }); federation.setActorDispatcher("/users/{handle}", async (ctx, handle) => { federation.setActorDispatcher("/users/{identifier}", async (ctx, identifier) => { return new Person({ id: ctx.getActorUri(handle), preferredUsername: handle, name: handle, id: ctx.getActorUri(identifier), preferredUsername: identifier, name: identifier, }); }); Loading
docs/manual/access-control.md +16 −14 Original line number Diff line number Diff line Loading @@ -42,11 +42,11 @@ import type { Actor, Federation } from "@fedify/fedify"; const federation = null as unknown as Federation<void>; /** * A hypothetical function that checks if the user blocks the actor. * @param handle The handle of the user to check if the actor is blocked. * @param userId The ID of the user to check if the actor is blocked. * @param signedKeyOwner The actor who signed the request. * @returns `true` if the actor is blocked; otherwise, `false`. */ async function isBlocked(handle: string, signedKeyOwner: Actor): Promise<boolean> { async function isBlocked(userId: string, signedKeyOwner: Actor): Promise<boolean> { return false; } // ---cut-before--- Loading @@ -54,12 +54,12 @@ import { federation } from "./your-federation.ts"; import { isBlocked } from "./your-blocklist.ts"; federation .setActorDispatcher("/users/{handle}", async (ctx, handle) => { .setActorDispatcher("/users/{identifier}", async (ctx, identifier) => { // Omitted for brevity; see the related section for details. }) .authorize(async (ctx, handle, signedKey, signedKeyOwner) => { .authorize(async (ctx, identifier, signedKey, signedKeyOwner) => { if (signedKeyOwner == null) return false; return !await isBlocked(handle, signedKeyOwner); return !await isBlocked(identifier, signedKeyOwner); }); ~~~~ Loading @@ -74,11 +74,11 @@ import type { Actor, Federation } from "@fedify/fedify"; const federation = null as unknown as Federation<void>; /** * A hypothetical function that checks if the user blocks the actor. * @param handle The handle of the user to check if the actor is blocked. * @param userId The ID of the user to check if the actor is blocked. * @param signedKeyOwner The actor who signed the request. * @returns `true` if the actor is blocked; otherwise, `false`. */ async function isBlocked(handle: string, signedKeyOwner: Actor): Promise<boolean> { async function isBlocked(userId: string, signedKeyOwner: Actor): Promise<boolean> { return false; } // ---cut-before--- Loading @@ -86,12 +86,12 @@ import { federation } from "./your-federation.ts"; import { isBlocked } from "./your-blocklist.ts"; federation .setOutboxDispatcher("/users/{handle}/outbox", async (ctx, handle) => { .setOutboxDispatcher("/users/{identifier}/outbox", async (ctx, identifier) => { // Omitted for brevity; see the related section for details. }) .authorize(async (ctx, handle, signedKey, signedKeyOwner) => { .authorize(async (ctx, identifier, signedKey, signedKeyOwner) => { if (signedKeyOwner == null) return false; return !await isBlocked(handle, signedKeyOwner); return !await isBlocked(identifier, signedKeyOwner); }); ~~~~ Loading Loading @@ -126,10 +126,10 @@ interface Post { } /** * A hypothetical function that gets posts from the database. * @param handle The handle of the user to get posts. * @param userId The ID of the user to get posts. * @returns The posts of the user. */ async function getPosts(handle: string): Promise<Post[]> { async function getPosts(userId: string): Promise<Post[]> { return []; } /** Loading @@ -145,8 +145,8 @@ import { federation } from "./your-federation.ts"; import { getPosts, toCreate } from "./your-model.ts"; federation .setOutboxDispatcher("/users/{handle}/outbox", async (ctx, handle) => { const posts = await getPosts(handle); // Get posts from the database .setOutboxDispatcher("/users/{identifier}/outbox", async (ctx, identifier) => { const posts = await getPosts(identifier); // Get posts from the database const keyOwner = await ctx.getSignedKeyOwner(); // Get the actor who signed the request if (keyOwner == null) return { items: [] }; // Return an empty array if the actor is not found const items = posts Loading @@ -155,3 +155,5 @@ federation return { items }; }); ~~~~ <!-- cSpell: ignore blocklist -->
docs/manual/actor.md +107 −42 File changed.Preview size limit exceeded, changes collapsed. Show changes