Documentation Index
Fetch the complete documentation index at: https://mintlify.com/seyarhasir/AiVault/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Bookmarks API allows authenticated users to save and manage their favorite AI tools. All endpoints require authentication.
Queries
getBookmarks
Fetch all bookmarked tools for the authenticated user.
Source: /home/daytona/workspace/source/convex/bookmarks.ts:12
Authentication: Required
Parameters: None
Array of bookmarked tools (null entries are filtered out)
import { useQuery } from "convex/react";
import { api } from "../convex/_generated/api";
function BookmarksPage() {
const bookmarks = useQuery(api.bookmarks.getBookmarks, {});
return (
<div>
<h1>My Bookmarks</h1>
{bookmarks?.map(tool => (
<ToolCard key={tool._id} tool={tool} />
))}
</div>
);
}
Notes:
- Returns the full tool objects, not just bookmark records
- Automatically filters out any null tools (if a bookmarked tool was deleted)
- Tools are returned in the order they were bookmarked
Errors:
"Unauthenticated" - User is not signed in
isBookmarked
Check if a specific tool is bookmarked by the current user.
Source: /home/daytona/workspace/source/convex/bookmarks.ts:56
Authentication: Optional (returns false if not authenticated)
true if the tool is bookmarked, false otherwise
import { useQuery } from "convex/react";
import { api } from "../convex/_generated/api";
function ToolPage({ toolId }: { toolId: Id<"tools"> }) {
const isBookmarked = useQuery(api.bookmarks.isBookmarked, { toolId });
return (
<button>
{isBookmarked ? "Remove Bookmark" : "Add Bookmark"}
</button>
);
}
Notes:
- Returns
false if user is not authenticated (does not throw error)
- Useful for showing bookmark button states
Mutations
toggleBookmark
Add or remove a bookmark for a specific tool.
Source: /home/daytona/workspace/source/convex/bookmarks.ts:32
Authentication: Required
ID of the tool to bookmark/unbookmark
true if tool was bookmarked, false if it was unbookmarked
import { useMutation } from "convex/react";
import { api } from "../convex/_generated/api";
function BookmarkButton({ toolId }: { toolId: Id<"tools"> }) {
const toggleBookmark = useMutation(api.bookmarks.toggleBookmark);
const isBookmarked = useQuery(api.bookmarks.isBookmarked, { toolId });
const handleToggle = async () => {
const bookmarked = await toggleBookmark({ toolId });
if (bookmarked) {
console.log("Tool bookmarked!");
} else {
console.log("Bookmark removed");
}
};
return (
<button onClick={handleToggle}>
{isBookmarked ? "🔖 Bookmarked" : "Add Bookmark"}
</button>
);
}
Behavior:
- If tool is already bookmarked: removes the bookmark and returns
false
- If tool is not bookmarked: creates a bookmark and returns
true
- Uses composite index for efficient lookup
Errors:
"Unauthenticated" - User is not signed in
Schema
The bookmarks table has the following structure:
bookmarks: defineTable({
userId: v.string(), // Clerk user ID
toolId: v.id("tools") // Reference to tools table
})
.index("by_userId", ["userId"])
.index("by_toolId", ["toolId"])
.index("by_userId_and_toolId", ["userId", "toolId"])
Indices:
by_userId - Fast lookup of all bookmarks for a user
by_toolId - Fast lookup of all users who bookmarked a tool
by_userId_and_toolId - Fast lookup of specific bookmark (used by toggleBookmark and isBookmarked)
Example: Complete Bookmark Feature
import { useQuery, useMutation } from "convex/react";
import { api } from "../convex/_generated/api";
import { Id } from "../convex/_generated/dataModel";
function ToolDetailPage({ toolId }: { toolId: Id<"tools"> }) {
const tool = useQuery(api.tools.getToolById, { toolId });
const isBookmarked = useQuery(api.bookmarks.isBookmarked, { toolId });
const toggleBookmark = useMutation(api.bookmarks.toggleBookmark);
const handleBookmark = async () => {
try {
await toggleBookmark({ toolId });
} catch (error) {
if (error.message === "Unauthenticated") {
// Redirect to sign in
window.location.href = "/sign-in";
}
}
};
if (!tool) return <div>Loading...</div>;
return (
<div>
<h1>{tool.name}</h1>
<p>{tool.description}</p>
<button onClick={handleBookmark}>
{isBookmarked ? "Remove from Bookmarks" : "Bookmark This Tool"}
</button>
</div>
);
}
function BookmarksPage() {
const bookmarks = useQuery(api.bookmarks.getBookmarks, {});
return (
<div>
<h1>My Bookmarked Tools</h1>
{bookmarks === undefined ? (
<div>Loading...</div>
) : bookmarks.length === 0 ? (
<div>No bookmarks yet. Start exploring tools!</div>
) : (
<div className="grid">
{bookmarks.map(tool => (
<ToolCard key={tool._id} tool={tool} />
))}
</div>
)}
</div>
);
}