Loading examples/README.md +1 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ Currently, there is only few examples, but more examples will be added in the future.[^1] - [Actor lookup CLI](./actor-lookup-cli/) - [Custom collections example](./custom-collections/) - [Federated single-user blog](./blog/) - [Federated microblog](https://github.com/fedify-dev/microblog), which is a final result of Loading examples/custom-collections/README.md 0 → 100644 +11 −0 Original line number Diff line number Diff line Custom collections example ========================== This example demonstrates how to implement custom collections in Fedify. Custom collections allow you to define your own ActivityPub collections with custom logic for dispatching items and counting collection sizes. ~~~~ sh deno task codegen # At very first time only deno run -A ./main.ts ~~~~ examples/custom-collections/main.ts 0 → 100644 +117 −0 Original line number Diff line number Diff line import { createFederation, MemoryKvStore, Note } from "@fedify/fedify"; // Mock data - in a real application, this would query your database const POSTS = [ new Note({ id: new URL("https://example.com/posts/post-1"), content: "ActivityPub is a decentralized social networking protocol...", tags: [ new URL("https://example.com/tags/ActivityPub"), new URL("https://example.com/tags/Decentralization"), ], }), new Note({ id: new URL("https://example.com/posts/post-2"), content: "Fedify makes it easy to build federated applications...", }), new Note({ id: new URL("https://example.com/posts/post-3"), content: "WebFinger is a protocol for discovering information...", tags: [new URL("https://example.com/tags/ActivityPub")], }), new Note({ id: new URL("https://example.com/posts/post-4"), content: "HTTP Signatures provide authentication for ActivityPub...", }), new Note({ id: new URL("https://example.com/posts/post-5"), content: "Understanding ActivityPub's data model is crucial...", }), ]; function getTagFromUrl(url: string): string { const parts = url.split("/"); return parts[parts.length - 1]; } function getTaggedPostsByTag(tag: string): Note[] { return POSTS .filter((post) => { if (!post.tagIds) { return false; } return post.tagIds.some((tagId) => { return getTagFromUrl(tagId.toString()) === tag; }); }); } async function demonstrateCustomCollection(): Promise<Response> { // Federation instance created for demonstration const federation = createFederation<void>({ kv: new MemoryKvStore() }); federation.setCollectionDispatcher( "TaggedPosts", Note, "/users/{userId}/tags/{tag}", ( _ctx: { url: URL }, values: Record<string, string>, cursor: string | null, ) => { if (!values.tag) { throw new Error("Missing userId or tag in values"); } // Normally here you would look up posts from a database by user ID and tag name: const posts = getTaggedPostsByTag(values.tag); if (cursor != null) { const idx = Number.parseInt(cursor, 10); if (Number.isNaN(idx) || idx > posts.length || idx < 0) { return { items: [], nextCursor: null, prevCursor: null }; } return { items: idx < posts.length ? [posts[idx]] : [], nextCursor: idx < posts.length - 1 ? (idx + 1).toString() : null, prevCursor: idx > 0 ? (idx - 1).toString() : null, }; } return { items: posts, nextCursor: null, prevCursor: null }; }, ).setCounter((_ctx, values) => { // Return the total count of tagged posts const count = getTaggedPostsByTag(values.tag).length; return count; }); return await federation.fetch( new Request( "https://example.com/users/123/tags/ActivityPub", { headers: { Accept: "application/activity+json", }, }, ), { contextData: undefined, }, ); } if (import.meta.main) { const response = await demonstrateCustomCollection(); if (response.ok) { const jsonResponse = await response.json(); console.log("Custom collection data:", jsonResponse); } else { const errorText = await response.text(); console.log("Error response:", errorText); } } Loading
examples/README.md +1 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ Currently, there is only few examples, but more examples will be added in the future.[^1] - [Actor lookup CLI](./actor-lookup-cli/) - [Custom collections example](./custom-collections/) - [Federated single-user blog](./blog/) - [Federated microblog](https://github.com/fedify-dev/microblog), which is a final result of Loading
examples/custom-collections/README.md 0 → 100644 +11 −0 Original line number Diff line number Diff line Custom collections example ========================== This example demonstrates how to implement custom collections in Fedify. Custom collections allow you to define your own ActivityPub collections with custom logic for dispatching items and counting collection sizes. ~~~~ sh deno task codegen # At very first time only deno run -A ./main.ts ~~~~
examples/custom-collections/main.ts 0 → 100644 +117 −0 Original line number Diff line number Diff line import { createFederation, MemoryKvStore, Note } from "@fedify/fedify"; // Mock data - in a real application, this would query your database const POSTS = [ new Note({ id: new URL("https://example.com/posts/post-1"), content: "ActivityPub is a decentralized social networking protocol...", tags: [ new URL("https://example.com/tags/ActivityPub"), new URL("https://example.com/tags/Decentralization"), ], }), new Note({ id: new URL("https://example.com/posts/post-2"), content: "Fedify makes it easy to build federated applications...", }), new Note({ id: new URL("https://example.com/posts/post-3"), content: "WebFinger is a protocol for discovering information...", tags: [new URL("https://example.com/tags/ActivityPub")], }), new Note({ id: new URL("https://example.com/posts/post-4"), content: "HTTP Signatures provide authentication for ActivityPub...", }), new Note({ id: new URL("https://example.com/posts/post-5"), content: "Understanding ActivityPub's data model is crucial...", }), ]; function getTagFromUrl(url: string): string { const parts = url.split("/"); return parts[parts.length - 1]; } function getTaggedPostsByTag(tag: string): Note[] { return POSTS .filter((post) => { if (!post.tagIds) { return false; } return post.tagIds.some((tagId) => { return getTagFromUrl(tagId.toString()) === tag; }); }); } async function demonstrateCustomCollection(): Promise<Response> { // Federation instance created for demonstration const federation = createFederation<void>({ kv: new MemoryKvStore() }); federation.setCollectionDispatcher( "TaggedPosts", Note, "/users/{userId}/tags/{tag}", ( _ctx: { url: URL }, values: Record<string, string>, cursor: string | null, ) => { if (!values.tag) { throw new Error("Missing userId or tag in values"); } // Normally here you would look up posts from a database by user ID and tag name: const posts = getTaggedPostsByTag(values.tag); if (cursor != null) { const idx = Number.parseInt(cursor, 10); if (Number.isNaN(idx) || idx > posts.length || idx < 0) { return { items: [], nextCursor: null, prevCursor: null }; } return { items: idx < posts.length ? [posts[idx]] : [], nextCursor: idx < posts.length - 1 ? (idx + 1).toString() : null, prevCursor: idx > 0 ? (idx - 1).toString() : null, }; } return { items: posts, nextCursor: null, prevCursor: null }; }, ).setCounter((_ctx, values) => { // Return the total count of tagged posts const count = getTaggedPostsByTag(values.tag).length; return count; }); return await federation.fetch( new Request( "https://example.com/users/123/tags/ActivityPub", { headers: { Accept: "application/activity+json", }, }, ), { contextData: undefined, }, ); } if (import.meta.main) { const response = await demonstrateCustomCollection(); if (response.ok) { const jsonResponse = await response.json(); console.log("Custom collection data:", jsonResponse); } else { const errorText = await response.text(); console.log("Error response:", errorText); } }