Custom collections cookbook example#722
Conversation
Add an in-repository custom collections example that keeps the bookmark domain small and focuses on dispatcher patterns. The example shows cursor-based pagination, URI template filtering, actor collection links, and requester-aware followers-only collections. Link the manual's custom collections section to the runnable example and add a changelog entry for the accepted issue. fedify-dev#694 Assisted-by: Codex:gpt-5.5
6d3c451 to
5d9dd09
Compare
|
@codex review |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds documentation and a runnable example implementing custom ActivityPub collections for bookmarks: cursor-based pagination, URI-template tag filtering, collection counters, actor collection links, and requester-aware authorization via Changes
Sequence Diagram(s)sequenceDiagram
participant Client as External Client/Requester
participant Federation as Fedify Federation
participant ActorDisp as Actor Dispatcher
participant CollDisp as Collection Dispatcher
participant BookmarkStore as In-Memory Bookmarks
Client->>Federation: GET /actor
activate Federation
Federation->>ActorDisp: Dispatch actor request
activate ActorDisp
ActorDisp->>BookmarkStore: Query bookmark metadata
BookmarkStore-->>ActorDisp: Return counts
ActorDisp-->>Federation: Return Person with collection links
deactivate ActorDisp
Federation-->>Client: ActivityPub Person JSON
deactivate Federation
rect rgba(100, 150, 200, 0.5)
Note over Client,BookmarkStore: Public Collection Flow
Client->>Federation: GET /collections/public?page=1
activate Federation
Federation->>CollDisp: Dispatch public collection
activate CollDisp
CollDisp->>BookmarkStore: Query public bookmarks with cursor
BookmarkStore-->>CollDisp: Return paginated results
CollDisp-->>Federation: OrderedCollection with items & cursors
deactivate CollDisp
Federation-->>Client: Paginated ActivityPub Collection
deactivate Federation
end
rect rgba(200, 150, 100, 0.5)
Note over Client,BookmarkStore: Filtered Collection Flow
Client->>Federation: GET /collections/tag/work?page=1
activate Federation
Federation->>CollDisp: Dispatch tagged collection
activate CollDisp
CollDisp->>BookmarkStore: Query bookmarks matching tag
BookmarkStore-->>CollDisp: Return filtered results
CollDisp-->>Federation: OrderedCollection with tag filter
deactivate CollDisp
Federation-->>Client: Filtered ActivityPub Collection
deactivate Federation
end
rect rgba(150, 200, 100, 0.5)
Note over Client,BookmarkStore: Access-Controlled Collection Flow
Client->>Federation: GET /collections/followers-only (with signature)
activate Federation
Federation->>CollDisp: Dispatch with signed request
activate CollDisp
CollDisp->>BookmarkStore: Check requester follows owner
alt Requester is authorized follower
BookmarkStore-->>CollDisp: Return followers bookmarks
CollDisp-->>Federation: OrderedCollection with items
else Requester not authorized
BookmarkStore-->>CollDisp: Deny access
CollDisp-->>Federation: Empty OrderedCollection
end
deactivate CollDisp
Federation-->>Client: Conditional ActivityPub Collection
deactivate Federation
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request replaces the basic custom collections example with a comprehensive cookbook demonstrating advanced patterns. It features cursor-based pagination, URI-template filtering for parameterized collections, and requester-aware collections utilizing ctx.getSignedKeyOwner(). The updates span the example code, documentation, and the project's changelog to provide a clear, runnable reference for developers. I have no feedback to provide.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d9dd09f38
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Adds a runnable in-repo cookbook example demonstrating Fedify custom ordered collections (pagination, filtering, and requester-aware authorization) and links it from the manual with a changelog entry.
Changes:
- Reworks
examples/custom-collections/main.tsinto a bookmark-based cookbook covering public, tag-filtered, and followers-only ordered collections. - Expands
examples/custom-collections/README.mdwith pattern explanations and run instructions. - Links the manual’s custom collections section to the runnable example and adds a
CHANGES.mdentry.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| examples/custom-collections/main.ts | New runnable cookbook script implementing 3 custom ordered collection patterns. |
| examples/custom-collections/README.md | Updated documentation describing the cookbook patterns and how to run it. |
| docs/manual/collections.md | Adds a link from the manual to the runnable cookbook example. |
| CHANGES.md | Adds a changelog entry and reference links for the new example. |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/custom-collections/main.ts`:
- Around line 134-145: The callbacks (setCounter, setFirstCursor, setLastCursor
and the dispatcher) repeatedly call publicBookmarks(), taggedBookmarks(...), and
followersOnlyBookmarks(), causing redundant re-filtering/sorting (and repeated
tag normalization); fix by computing the filtered/sorted list once per incoming
request and reusing it across those callbacks: e.g., inside the dispatcher or
the registration scope, call
publicBookmarks()/taggedBookmarks()/followersOnlyBookmarks() a single time (or
memoize keyed by values.identifier / tag params) and store the result in a local
variable that the functions setCounter, setFirstCursor, setLastCursor reference;
update the taggedBookmarks path to normalize tags once and reuse that normalized
list so each callback reuses the precomputed array instead of recomputing.
- Around line 268-288: The toArticle function builds an HTML string into the
Article.content field by concatenating bookmark.href and bookmark.title without
escaping; update toArticle to sanitize or escape bookmark.title and
bookmark.href before embedding into the content string (or add an inline comment
next to content reminding callers to sanitize user-supplied data) so downstream
apps don't introduce XSS vulnerabilities when using bookmark.title/bookmark.href
in Article.content.
- Around line 123-132: The dispatcher currently returns null when cursor == null
which causes empty public/tagged collections to be treated as "not found";
instead, modify the dispatcher used in TAGGED_BOOKMARKS (and the similar
authenticated-follower branch) so that when cursor == null it returns an empty
collection page object matching the followers-only dispatcher's shape (i.e., an
OrderedCollectionPage with no items and appropriate id/links) rather than null;
update the anonymous/public dispatcher (the (ctx, values, cursor) => { ... }
block that calls pageBookmarks(ctx, publicBookmarks(), cursor)) and the
TAGGED_BOOKMARKS dispatcher to return that empty page shape for cursor == null.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: d1ea26c1-cb22-40f3-bf90-3ec9d4920db6
📒 Files selected for processing (4)
CHANGES.mddocs/manual/collections.mdexamples/custom-collections/README.mdexamples/custom-collections/main.ts
Codecov Report✅ All modified and coverable lines are covered by tests. 🚀 New features to boost your workflow:
|
Keep tag-filtered collections limited to public bookmarks so the public route does not expose followers-only bookmark existence. Return an empty item set for cursorless empty collections so valid empty custom collections serialize instead of becoming 404 responses. Escape bookmark fields before embedding them in Article content HTML so the cookbook does not model unsafe rendering for user-supplied bookmark data. fedify-dev#722 (comment) fedify-dev#722 (comment) fedify-dev#722 (comment) fedify-dev#722 (comment) fedify-dev#722 (comment) fedify-dev#722 (comment) fedify-dev#722 (comment) Assisted-by: Codex:gpt-5
|
@codex review |
|
/gemini review |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/custom-collections/main.ts`:
- Around line 98-114: The Actor object is advertising custom collections using
the attachments property; change this to use streams instead so the Actor uses
the AP-canonical property. Replace the array assigned to attachments with a
streams array that contains the same collectionLink(...) entries (using
collectionLink, ctx.getCollectionUri, and the constants PUBLIC_BOOKMARKS,
TAGGED_BOOKMARKS, FOLLOWERS_ONLY_BOOKMARKS) and keep the rel="collection"
semantics; update any code that consumes the Actor payload to read streams if
necessary and remove or leave attachments only if used for other profile
metadata.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7642f8ee-6672-4a55-b8cd-78654f2d1968
📒 Files selected for processing (2)
examples/custom-collections/README.mdexamples/custom-collections/main.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 10d1fdffa6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive cookbook example for custom ActivityPub collections, demonstrating patterns for cursor-based pagination, URI-template filtering, and requester-aware authorization. The implementation includes a new federation setup, mock data utilities, and updated documentation. Feedback suggests optimizing the collection dispatcher to return null when the cursor is absent, which allows the framework to serve collection metadata rather than the entire item set in a single response.
Handle getSignedKeyOwner() failures as unauthenticated follower-only collection requests. Malformed signature input should keep the cookbook's restricted collection path on the same unauthorized branch instead of surfacing as a server error. fedify-dev#722 (comment) Assisted-by: Codex:gpt-5.5
|
@codex review |
|
/gemini review |
|
Codex Review: Didn't find any major issues. Can't wait for the next one! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
Code Review
This pull request updates the custom collections example into a comprehensive cookbook demonstrating cursor-based pagination, URI-template filtering, and requester-aware collections. The changes include a new federation setup, a mock data library, and an updated demonstration script. A review comment suggests improving the pagination example by returning null when no cursor is provided, which allows Fedify to generate standard collection metadata that links to the first page.
|
@codex review |
|
/gemini review |
|
Codex Review: Didn't find any major issues. Breezy! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
Code Review
This pull request adds a custom collections cookbook example to the Fedify project, showcasing various ActivityPub collection patterns including cursor pagination, URI-template filtering, and signed requester-aware collections. The implementation includes a federation setup, mock data library, and a demonstration script. A suggestion was made to improve the efficiency and idiomatic style of the escapeHtml utility function by using a regular expression and a lookup map.
Keep the cookbook's HTML escaping helper compact by replacing matched characters through a shared lookup table. This avoids chaining multiple string replacements while preserving the same escaped output. fedify-dev#722 (comment) Assisted-by: Codex:gpt-5.5
|
@codex review |
|
/gemini review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive cookbook example for custom ActivityPub collections, featuring cursor-based pagination, URI-template filtering, and requester-aware access control. Feedback focuses on adhering to the project's documentation standards by adding JSDoc comments to public APIs in the new example files. Additionally, it is noted that the current implementation of collection dispatchers performs redundant data fetching, which should be optimized for production-ready code.
Closes #694.
Summary
This PR adds an in-repository cookbook-style example for custom collection dispatchers under examples/custom-collections/.
The example uses a small single-user bookmark domain, but keeps the focus on Fedify collection patterns rather than a full CRUD app or tutorial. It demonstrates public ordered collections, URI-template-based tag filtering, cursor pagination, collection counters, actor stream links to custom collections, and requester-aware followers-only results using
ctx.getSignedKeyOwner().Closes #694.
Changes
/users/alice/collections/public/users/alice/collections/tags/{tag}/users/alice/collections/followers-onlyVerification
deno check examples/custom-collections/main.tsdeno lint examples/custom-collections/main.tsdeno run --allow-all examples/custom-collections/main.tsdeno run -A examples/test-examples/mod.ts custom-collectionsDeno.serve()federation servers to verify:The example runner still reports the pre-existing unrelated warning that
solidstartis not registered in the example test runner.