### Run Development Server Source: https://github.com/mon842/threads/blob/main/README.md Use these commands to start the development server for the Next.js project. Open http://localhost:3000 in your browser to view the application. ```bash npm run dev # or yarn dev # or pnpm dev # or bun run dev ``` -------------------------------- ### Establish Singleton MongoDB Connection Source: https://context7.com/mon842/threads/llms.txt Ensures a single Mongoose connection is active. Call this at the start of any database operation. Requires `MONGODB_URL` in environment variables. ```typescript // lib/mongoose.ts import { connectToDB } from "@/lib/mongoose"; // Call at the top of every Server Action before any DB operation await connectToDB(); // Environment variable required in .env.local: // MONGODB_URL=mongodb+srv://:@cluster.mongodb.net/threads ``` -------------------------------- ### Zod Schemas for Form Validation Source: https://context7.com/mon842/threads/llms.txt Utilize Zod schemas for validating form inputs before invoking server actions. Examples include thread creation, comment replies, and user profile updates. ```typescript import { ThreadValidation, CommentValidation } from "@/lib/validations/thread"; import { UserValidation } from "@/lib/validations/user"; // Thread creation — used in PostThread form const threadData = ThreadValidation.parse({ thread: "My new thread content", // min 3 characters accountId: "64b1f2e3c4a5d60012345678", }); // Comment/reply — used in Comment form const commentData = CommentValidation.parse({ thread: "My reply", // min 3 characters }); // User profile — used in AccountProfile form const profileData = UserValidation.parse({ profile_photo: "https://uploadthing.com/f/photo.jpg", // must be valid URL name: "John Doe", // 3–30 characters username: "johndoe", // 3–30 characters bio: "I build things", // 3–1000 characters }); ``` -------------------------------- ### Database Connection Source: https://context7.com/mon842/threads/llms.txt Establishes a singleton MongoDB connection using the MONGODB_URL environment variable. It's recommended to call this at the top of every Server Action before any database operations. ```APIDOC ## Database Connection ### `connectToDB` — Establish a singleton MongoDB connection Creates or reuses a Mongoose connection using the `MONGODB_URL` environment variable. Uses a module-level `isConnected` flag to prevent duplicate connections in serverless environments. ```typescript // lib/mongoose.ts import { connectToDB } from "@/lib/mongoose"; // Call at the top of every Server Action before any DB operation await connectToDB(); // Environment variable required in .env.local: // MONGODB_URL=mongodb+srv://:@cluster.mongodb.net/threads ``` ``` -------------------------------- ### UploadThing Media FileRoute Configuration Source: https://context7.com/mon842/threads/llms.txt Configure UploadThing for handling profile and community images. Authenticates uploads via Clerk's currentUser() and restricts to single image files up to 4MB. The 'media' slug is used for this route. ```typescript import { generateReactHelpers } from "@uploadthing/react"; import type { OurFileRouter } from "@/app/api/uploadthing/core"; const { useUploadThing } = generateReactHelpers(); // Usage inside a React component: function ProfilePhotoUploader() { const { startUpload } = useUploadThing("media"); const handleFileChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; const res = await startUpload([file]); // res[0].url → CDN URL of the uploaded image // Pass this URL to updateUser({ image: res[0].url, ... }) }; } // Route config: // Slug: "media" // Allowed types: image (PNG, JPEG, GIF, WebP) // Max file size: 4MB // Max file count: 1 // Auth: requires active Clerk session (throws "Unauthorized" if not signed in) ``` -------------------------------- ### Fetch a user by Clerk ID Source: https://context7.com/mon842/threads/llms.txt Looks up a User document using the Clerk ID and populates the user's community memberships. If the user is not onboarded, it redirects to the onboarding page. ```typescript import { fetchUser } from "@/lib/actions/user.actions"; const userInfo = await fetchUser("user_2NkLm8XyZ"); // userInfo.id → "user_2NkLm8XyZ" (Clerk ID) // userInfo.username → "johndoe" // userInfo.name → "John Doe" // userInfo.bio → "Software engineer" // userInfo.image → "https://img.clerk.com/..." // userInfo.onboarded → true // userInfo.communities → Community[] (populated) if (!userInfo?.onboarded) redirect("/onboarding"); ``` -------------------------------- ### Create or update a user profile (upsert) Source: https://context7.com/mon842/threads/llms.txt Upserts a User document based on the Clerk `userId`, setting `onboarded` to true. If called from the profile edit page, it revalidates that path. Throws an error on failure. ```typescript import { updateUser } from "@/lib/actions/user.actions"; await updateUser({ userId: "user_2NkLm8XyZ", username: "johndoe", name: "John Doe", bio: "Building cool things with Next.js", image: "https://uploadthing.com/f/abc123.jpg", path: "/profile/edit", }); // Returns: void — throws Error on failure // Side effect: sets onboarded=true (used to redirect away from onboarding) ``` -------------------------------- ### fetchCommunityDetails Source: https://context7.com/mon842/threads/llms.txt Fetches a community document along with its creator and all members, including their name, username, image, and ID. ```APIDOC ## fetchCommunityDetails — Fetch community with members Returns the Community document with `createdBy` and all `members` populated (name, username, image, id fields). ```typescript import { fetchCommunityDetails } from "@/lib/actions/community.actions"; const community = await fetchCommunityDetails("org_2abc123XYZ"); // community.name → "Next.js Developers" // community.bio → "A community for Next.js enthusiasts" // community.createdBy → User document // community.members → [{ name, username, image, _id, id }] // community.threads → ObjectId[] (not populated here) ``` ``` -------------------------------- ### Create New Thread Source: https://context7.com/mon842/threads/llms.txt Creates a new thread or community post. Updates author and community thread arrays. Revalidates the Next.js cache. Use `communityId: null` for personal posts. ```typescript // lib/actions/thread.actions.ts import { createThread } from "@/lib/actions/thread.actions"; // Personal post (no community) await createThread({ text: "Hello, Threads!", author: "64b1f2e3c4a5d60012345678", // MongoDB _id of the User communityId: null, path: "/", }); // Community post await createThread({ text: "Check out our new project 🚀", author: "64b1f2e3c4a5d60012345678", communityId: "org_2abc123XYZ", // Clerk organization ID path: "/", }); // Returns: void — throws Error on failure ``` -------------------------------- ### fetchUser Source: https://context7.com/mon842/threads/llms.txt Fetches a user by their Clerk ID and populates their community memberships. ```APIDOC ## fetchUser — Fetch a user by Clerk ID Looks up the User document by Clerk's string `id` field (not the MongoDB `_id`) and populates the user's community memberships. ### Method Signature ```typescript fetchUser(clerkId: string): Promise ``` ### Parameters - **clerkId** (string) - The Clerk ID of the user to fetch. ### Returns - **Promise** - The User document with populated community memberships, or null if not found. ### User Object Fields - **id** (string) - Clerk ID. - **username** (string) - **name** (string) - **bio** (string) - **image** (string) - **onboarded** (boolean) - **communities** (Community[]) - Populated community memberships. ### Example Usage ```typescript const userInfo = await fetchUser("user_2NkLm8XyZ"); if (!userInfo?.onboarded) redirect("/onboarding"); ``` ``` -------------------------------- ### Create a community linked to a Clerk Organization Source: https://context7.com/mon842/threads/llms.txt Creates a Community document and associates it with a Clerk Organization. It also adds the new community's ID to the founding user's `communities` array. This is typically called from a Clerk webhook. ```typescript import { createCommunity } from "@/lib/actions/community.actions"; const community = await createCommunity( "org_2abc123XYZ", // Clerk organization ID "Next.js Developers", // name "nextjs-devs", // username/slug "https://img.clerk.com/org.jpg", // image URL "A community for Next.js enthusiasts", // bio "user_2NkLm8XyZ" // Clerk ID of the creating user ); // Returns: Community document // Side effect: pushes community._id into user.communities ``` -------------------------------- ### Fetch Community Details with Members Source: https://context7.com/mon842/threads/llms.txt Retrieves a Community document, populating the 'createdBy' user and all 'members' with their name, username, image, and ID. ```typescript import { fetchCommunityDetails } from "@/lib/actions/community.actions"; const community = await fetchCommunityDetails("org_2abc123XYZ"); // community.name → "Next.js Developers" // community.bio → "A community for Next.js enthusiasts" // community.createdBy → User document // community.members → [{ name, username, image, _id, id }] // community.threads → ObjectId[] (not populated here) ``` -------------------------------- ### Search and paginate users Source: https://context7.com/mon842/threads/llms.txt Fetches users, excluding the current user, with optional case-insensitive search, pagination, and sorting. Returns the list of users and a boolean indicating if more pages are available. ```typescript import { fetchUsers } from "@/lib/actions/user.actions"; const { users, isNext } = await fetchUsers({ userId: "user_2NkLm8XyZ", // excluded from results searchString: "jane", // searches username and name pageNumber: 1, pageSize: 25, sortBy: "desc", // SortOrder: "asc" | "desc" }); // users: User[] — matching users (id, username, name, image) // isNext: boolean — true if more pages remain ``` -------------------------------- ### getActivity Source: https://context7.com/mon842/threads/llms.txt Fetches replies to the current user's threads, used for notifications. ```APIDOC ## getActivity — Fetch replies to the current user's threads Returns all threads that are replies (comments) to the authenticated user's posts, excluding self-replies. Used to power the Activity/notifications feed. ### Method Signature ```typescript getActivity(userId: string): Promise ``` ### Parameters - **userId** (string) - The MongoDB `_id` (ObjectId) of the authenticated user. ### Returns - **Promise** - An array of `Thread` objects representing replies to the user's posts. ### Thread Object Fields (relevant for replies) - **author** ({ name: string, image: string, _id: string }) - **parentId** (string) - **text** (string) ### Example Usage ```typescript const replies = await getActivity(userInfo._id); replies.map((reply) => (

{reply.author.name} replied to your thread: {reply.text}

)); ``` ``` -------------------------------- ### Fetch and Paginate Communities Source: https://context7.com/mon842/threads/llms.txt Searches and paginates communities based on a search string, page number, and page size. Supports case-insensitive search on name and username, and returns communities with populated members. ```typescript import { fetchCommunities } from "@/lib/actions/community.actions"; const { communities, isNext } = await fetchCommunities({ searchString: "react", pageNumber: 1, pageSize: 20, sortBy: "desc", }); // communities: Community[] with populated members // isNext: boolean ``` -------------------------------- ### fetchCommunityPosts Source: https://context7.com/mon842/threads/llms.txt Fetches all threads within a community, populating the author and children with their images. ```APIDOC ## fetchCommunityPosts — Fetch all threads in a community Returns the Community document with `threads` fully populated (author and children with author images). ```typescript import { fetchCommunityPosts } from "@/lib/actions/community.actions"; const communityPosts = await fetchCommunityPosts("64d1abc000ef123456789012"); // communityPosts.threads → Thread[] each with: // .author → { name, image, id } // .children → [{ author: { image, _id } }] ``` ``` -------------------------------- ### Utility Functions for Display Formatting Source: https://context7.com/mon842/threads/llms.txt Helper functions for formatting dates, thread counts, and detecting base64 image strings. `formatDateString` formats ISO dates, `formatThreadCount` displays thread counts appropriately, and `isBase64Image` checks for base64 data URIs. ```typescript import { formatDateString, formatThreadCount, isBase64Image } from "@/lib/utils"; // Format ISO date for display on thread cards formatDateString("2024-01-15T14:30:00.000Z"); // → "2:30 PM - Jan 15, 2024" // Format thread count for profile display formatThreadCount(0); // → "No Threads" formatThreadCount(1); // → "01 Thread" formatThreadCount(42); // → "42 Threads" // Detect if an image string is a base64 data URI (not yet uploaded) isBase64Image("data:image/png;base64,iVBORw0KGgo="); // → true isBase64Image("https://uploadthing.com/f/photo.jpg"); // → false // Used in AccountProfile form to decide whether to call startUpload() ``` -------------------------------- ### fetchUserPosts Source: https://context7.com/mon842/threads/llms.txt Fetches all threads authored by a user, populating community and children thread information. ```APIDOC ## fetchUserPosts — Fetch all threads authored by a user Returns the User document with all threads populated, including each thread's community and children (with their authors). ### Method Signature ```typescript fetchUserPosts(userId: string): Promise ``` ### Parameters - **userId** (string) - The ID of the user whose posts to fetch. ### Returns - **Promise** - The User document with populated threads, or null if not found. ### UserWithThreads Object Fields - **threads** (Thread[]) - An array of threads authored by the user. Each thread object includes: - **text** (string) - **createdAt** (Date) - **parentId** (string | null) - **community** ({ name: string, id: string, image: string, _id: string }) - **children** ([{ author: { name: string, image: string, id: string } }]) ### Example Usage ```typescript const userData = await fetchUserPosts("user_2NkLm8XyZ"); userData.threads.map((thread) => ( )); ``` ``` -------------------------------- ### Fetch Posts Source: https://context7.com/mon842/threads/llms.txt Fetches a paginated feed of top-level threads (posts without a parentId), sorted by newest first. It populates author, community, and first-level children for reply counts. ```APIDOC --- ### `fetchPosts` — Paginated feed of top-level threads Fetches threads that have no `parentId` (i.e., root-level posts), sorted by newest first. Populates author, community, and first-level children (for reply count display). ```typescript import { fetchPosts } from "@/lib/actions/thread.actions"; const { posts, isNext } = await fetchPosts(1, 20); // posts: Thread[] — each includes populated author, community, children // isNext: boolean — true if more pages exist // Render example (Next.js Server Component) posts.map((post) => ( )); ``` ``` -------------------------------- ### Fetch Community Posts (Threads) Source: https://context7.com/mon842/threads/llms.txt Fetches all threads within a community, populating the author and children with their images. Use this to display a community's content. ```typescript import { fetchCommunityPosts } from "@/lib/actions/community.actions"; const communityPosts = await fetchCommunityPosts("64d1abc000ef123456789012"); // communityPosts.threads → Thread[] each with: // .author → { name, image, id } // .children → [{ author: { image, _id } }] ``` -------------------------------- ### Create Thread Source: https://context7.com/mon842/threads/llms.txt Creates a new top-level thread or a post within a community. It updates the author's and community's thread lists and revalidates the Next.js cache. ```APIDOC ## Thread Actions ### `createThread` — Create a new top-level thread or community post Creates a thread document, pushes its `_id` into the author's `threads` array, and (if a community is specified) into the community's `threads` array. Revalidates the Next.js cache for the given path. ```typescript // lib/actions/thread.actions.ts import { createThread } from "@/lib/actions/thread.actions"; // Personal post (no community) await createThread({ text: "Hello, Threads!", author: "64b1f2e3c4a5d60012345678", // MongoDB _id of the User communityId: null, path: "/", }); // Community post await createThread({ text: "Check out our new project 🚀", author: "64b1f2e3c4a5d60012345678", communityId: "org_2abc123XYZ", // Clerk organization ID path: "/", }); // Returns: void — throws Error on failure ``` ``` -------------------------------- ### Fetch Paginated Top-Level Threads Source: https://context7.com/mon842/threads/llms.txt Retrieves root-level threads (no `parentId`) sorted by newest first. Populates author, community, and reply count. Returns posts and a boolean indicating if more pages exist. ```typescript import { fetchPosts } from "@/lib/actions/thread.actions"; const { posts, isNext } = await fetchPosts(1, 20); // posts: Thread[] — each includes populated author, community, children // isNext: boolean — true if more pages exist // Render example (Next.js Server Component) posts.map((post) => ( )); ``` -------------------------------- ### fetchUsers Source: https://context7.com/mon842/threads/llms.txt Searches and paginates users, excluding the current user, with optional search, pagination, and sorting. ```APIDOC ## fetchUsers — Search and paginate users Returns all users except the current user, with optional case-insensitive search across `username` and `name` fields, pagination, and sort order. ### Method Signature ```typescript fetchUsers(params: FetchUsersParams): Promise<{ users: User[]; isNext: boolean }> ``` ### Parameters - **params** (FetchUsersParams) - An object containing search and pagination parameters: - **userId** (string) - Required - The ID of the current user to exclude from results. - **searchString** (string) - Optional - Case-insensitive search string for `username` and `name` fields. - **pageNumber** (number) - Optional - The page number for pagination (defaults to 1). - **pageSize** (number) - Optional - The number of users per page (defaults to 25). - **sortBy** (SortOrder) - Optional - The sort order, either "asc" or "desc" (defaults to "desc"). ### Returns - **Promise<{ users: User[]; isNext: boolean }>** - An object containing an array of matching `User` objects and a boolean indicating if there are more pages. ### User Object Fields - **id** (string) - **username** (string) - **name** (string) - **image** (string) ### Example Usage ```typescript const { users, isNext } = await fetchUsers({ userId: "user_2NkLm8XyZ", searchString: "jane", pageNumber: 1, pageSize: 25, sortBy: "desc", }); ``` ``` -------------------------------- ### Fetch all threads authored by a user Source: https://context7.com/mon842/threads/llms.txt Returns a User document populated with all their authored threads, including community details and children threads with their authors. Used for displaying a user's posts. ```typescript import { fetchUserPosts } from "@/lib/actions/user.actions"; const userData = await fetchUserPosts("user_2NkLm8XyZ"); // userData.threads → Thread[] each with: // .text, .createdAt, .parentId // .community → { name, id, image, _id } // .children → [{ author: { name, image, id } }] userData.threads.map((thread) => ( )); ``` -------------------------------- ### fetchCommunities Source: https://context7.com/mon842/threads/llms.txt Searches and paginates communities, returning matching documents with populated members and supporting case-insensitive search. ```APIDOC ## fetchCommunities — Search and paginate communities Returns matching Community documents with `members` populated, supporting case-insensitive search across `name` and `username`. ```typescript import { fetchCommunities } from "@/lib/actions/community.actions"; const { communities, isNext } = await fetchCommunities({ searchString: "react", pageNumber: 1, pageSize: 20, sortBy: "desc", }); // communities: Community[] with populated members // isNext: boolean ``` ``` -------------------------------- ### createCommunity Source: https://context7.com/mon842/threads/llms.txt Creates a community linked to a Clerk Organization and adds it to the founding user's communities array. ```APIDOC ## createCommunity — Create a community linked to a Clerk Organization Creates a Community document and adds it to the founding user's `communities` array. Called automatically from the Clerk webhook when an Organization is created. ### Method Signature ```typescript createCommunity( clerkOrgId: string, name: string, username: string, image: string, bio: string, creatorUserId: string ): Promise ``` ### Parameters - **clerkOrgId** (string) - The Clerk organization ID. - **name** (string) - The name of the community. - **username** (string) - The unique username/slug for the community. - **image** (string) - The URL of the community's image. - **bio** (string) - The description of the community. - **creatorUserId** (string) - The Clerk ID of the user creating the community. ### Returns - **Promise** - The created Community document. ### Side Effects - Pushes the new community's `_id` into the `communities` array of the `User` document corresponding to `creatorUserId`. ### Example Usage ```typescript const community = await createCommunity( "org_2abc123XYZ", "Next.js Developers", "nextjs-devs", "https://img.clerk.com/org.jpg", "A community for Next.js enthusiasts", "user_2NkLm8XyZ" ); ``` ``` -------------------------------- ### addMemberToCommunity Source: https://context7.com/mon842/threads/llms.txt Adds a user to a community by validating existence and membership status, then updating both user and community documents. ```APIDOC ## addMemberToCommunity — Add a user to a community Validates that both community and user exist and that the user isn't already a member, then pushes the IDs into each other's arrays bi-directionally. Called from the Clerk webhook on `organizationMembership.created`. ```typescript import { addMemberToCommunity } from "@/lib/actions/community.actions"; const updatedCommunity = await addMemberToCommunity( "org_2abc123XYZ", // Clerk organization ID "user_2NkLm8XyZ" // Clerk user ID ); // Returns: updated Community document // Throws: "User is already a member of the community" ``` ``` -------------------------------- ### updateUser Source: https://context7.com/mon842/threads/llms.txt Creates or updates a user profile (upsert) by Clerk ID, setting onboarded to true and revalidating the profile edit path if applicable. ```APIDOC ## updateUser — Create or update a user profile (upsert) Upserts the User document matching the Clerk `userId`. Sets `onboarded: true`. Revalidates the profile edit path if called from the edit page. ### Method Signature ```typescript updateUser(userData: UserUpdateData): Promise ``` ### Parameters - **userData** (UserUpdateData) - An object containing user details: - **userId** (string) - Required - The Clerk ID of the user. - **username** (string) - Optional - The user's username. - **name** (string) - Optional - The user's full name. - **bio** (string) - Optional - The user's biography. - **image** (string) - Optional - The URL of the user's profile image. - **path** (string) - Optional - The path to revalidate. ### Example Usage ```typescript await updateUser({ userId: "user_2NkLm8XyZ", username: "johndoe", name: "John Doe", bio: "Building cool things with Next.js", image: "https://uploadthing.com/f/abc123.jpg", path: "/profile/edit", }); ``` ### Returns - **void** — Throws an Error on failure. ### Side Effects - Sets `onboarded` to `true` for the user. ``` -------------------------------- ### Clerk Webhook Handler for Organization Events Source: https://context7.com/mon842/threads/llms.txt Verifies Svix webhook signatures and maps Clerk organization lifecycle events to corresponding MongoDB actions. This endpoint synchronizes Clerk's organization management with the application's database. ```typescript // app/api/webhook/clerk/route.ts // Handles these Clerk event types: // - organization.created → createCommunity() // - organizationMembership.created → addMemberToCommunity() // - organizationMembership.deleted → removeUserFromCommunity() // - organization.updated → updateCommunityInfo() // - organization.deleted → deleteCommunity() // Example: Clerk sends this payload on org creation // POST /api/webhook/clerk // Headers: svix-id, svix-timestamp, svix-signature // Body: { "type": "organization.created", "data": { "id": "org_2abc123XYZ", "name": "Next.js Developers", "slug": "nextjs-devs", "image_url": "https://img.clerk.com/org.jpg", "created_by": "user_2NkLm8XyZ" } } // Response 201: { "message": "User created" } // Response 400: webhook verification failed // Response 500: internal server error // Environment variable required: // NEXT_CLERK_WEBHOOK_SECRET=whsec_xxxx ``` -------------------------------- ### Fetch Thread by ID with Nested Replies Source: https://context7.com/mon842/threads/llms.txt Retrieves a specific thread and its entire nested reply structure. Deeply populates author, community, and all levels of children with their authors. Used for thread detail views. ```typescript import { fetchThreadById } from "@/lib/actions/thread.actions"; const thread = await fetchThreadById("64c9f0e1234abc0012ab1234"); // thread.text → "Original post content" // thread.author → { _id, id, name, image } // thread.community → { _id, id, name, image } | null // thread.children → Reply threads, each with populated author and grandchildren // thread.children[0].children → Grandchild replies if (!thread) throw new Error("Thread not found"); ``` -------------------------------- ### POST /api/webhook/clerk Source: https://context7.com/mon842/threads/llms.txt Handles Clerk Webhook events to synchronize Clerk Organization lifecycle events with MongoDB community data. ```APIDOC ## Clerk Webhook Handler ### `POST /api/webhook/clerk` — Sync Clerk Organization events to MongoDB Verifies Svix webhook signatures and maps Clerk Organization lifecycle events to community actions. This is the integration point between Clerk's organization management and the app's MongoDB data. ```typescript // app/api/webhook/clerk/route.ts // Handles these Clerk event types: // - organization.created → createCommunity() // - organizationMembership.created → addMemberToCommunity() // - organizationMembership.deleted → removeUserFromCommunity() // - organization.updated → updateCommunityInfo() // - organization.deleted → deleteCommunity() // Example: Clerk sends this payload on org creation // POST /api/webhook/clerk // Headers: svix-id, svix-timestamp, svix-signature // Body: { "type": "organization.created", "data": { "id": "org_2abc123XYZ", "name": "Next.js Developers", "slug": "nextjs-devs", "image_url": "https://img.clerk.com/org.jpg", "created_by": "user_2NkLm8XyZ" } } // Response 201: { "message": "User created" } // Response 400: webhook verification failed // Response 500: internal server error // Environment variable required: // NEXT_CLERK_WEBHOOK_SECRET=whsec_xxxx ``` ``` -------------------------------- ### Fetch replies to the current user's threads Source: https://context7.com/mon842/threads/llms.txt Retrieves all threads that are replies to the authenticated user's posts, excluding self-replies. This is used for populating the activity or notifications feed. Requires the MongoDB `_id` of the user. ```typescript import { getActivity } from "@/lib/actions/user.actions"; // userId here is the MongoDB _id (ObjectId), not the Clerk ID const replies = await getActivity(userInfo._id); // replies: Thread[] each with populated author: { name, image, _id } replies.map((reply) => (

{reply.author.name} replied to your thread: {reply.text}

)); ``` -------------------------------- ### Fetch Thread By ID Source: https://context7.com/mon842/threads/llms.txt Retrieves a single thread by its MongoDB `_id`, including deep population of its author, community, and all nested replies (children and grandchildren) with their authors. ```APIDOC --- ### `fetchThreadById` — Fetch a single thread with full nested replies Retrieves a thread by its MongoDB `_id` with deep population: author, community, children (with their authors), and grandchildren (with their authors). Used to render the thread detail page. ```typescript import { fetchThreadById } from "@/lib/actions/thread.actions"; const thread = await fetchThreadById("64c9f0e1234abc0012ab1234"); // thread.text → "Original post content" // thread.author → { _id, id, name, image } // thread.community → { _id, id, name, image } | null // thread.children → Reply threads, each with populated author and grandchildren // thread.children[0].children → Grandchild replies if (!thread) throw new Error("Thread not found"); ``` ``` -------------------------------- ### Add Member to Community Source: https://context7.com/mon842/threads/llms.txt Adds a user to a community by updating both the user's and community's member lists bi-directionally. This function is typically called from the Clerk webhook on `organizationMembership.created`. ```typescript import { addMemberToCommunity } from "@/lib/actions/community.actions"; const updatedCommunity = await addMemberToCommunity( "org_2abc123XYZ", // Clerk organization ID "user_2NkLm8XyZ" // Clerk user ID ); // Returns: updated Community document // Throws: "User is already a member of the community" ``` -------------------------------- ### Add Comment to Thread Source: https://context7.com/mon842/threads/llms.txt Creates a new reply thread, setting its `parentId` and updating the parent thread's `children` array. Revalidates the specified path. Requires parent thread ID, comment text, and user ID. ```typescript import { addCommentToThread } from "@/lib/actions/thread.actions"; // Used inside the Comment form component await addCommentToThread( "64c9f0e1234abc0012ab1234", // threadId (parent) "Great post! Totally agree.", // commentText "64b1f2e3c4a5d60012345678", // userId (MongoDB _id, JSON.parsed from string) "/thread/64c9f0e1234abc0012ab1234" // path to revalidate ); // Returns: void — throws Error on failure ``` -------------------------------- ### updateCommunityInfo Source: https://context7.com/mon842/threads/llms.txt Updates the community's metadata, including name, username, and image, based on the provided Clerk organization ID. ```APIDOC ## updateCommunityInfo — Update community metadata Updates `name`, `username`, and `image` on the community matching the given Clerk organization ID. Called from the webhook on `organization.updated`. ```typescript import { updateCommunityInfo } from "@/lib/actions/community.actions"; await updateCommunityInfo( "org_2abc123XYZ", "Next.js & React Developers", "nextjs-react-devs", "https://uploadthing.com/f/newlogo.jpg" ); // Returns: old Community document (pre-update) ``` ``` -------------------------------- ### Add Comment To Thread Source: https://context7.com/mon842/threads/llms.txt Adds a comment to a specific thread. This action creates a new Thread document with the `parentId` set to the target thread's ID and updates the parent thread's `children` array. ```APIDOC --- ### `addCommentToThread` — Reply to a thread Creates a new Thread document with `parentId` set to the target thread, then pushes the new comment's `_id` into the parent's `children` array. ```typescript import { addCommentToThread } from "@/lib/actions/thread.actions"; // Used inside the Comment form component await addCommentToThread( "64c9f0e1234abc0012ab1234", // threadId (parent) "Great post! Totally agree.", // commentText "64b1f2e3c4a5d60012345678", // userId (MongoDB _id, JSON.parsed from string) "/thread/64c9f0e1234abc0012ab1234" // path to revalidate ); // Returns: void — throws Error on failure ``` ``` -------------------------------- ### deleteThread Source: https://context7.com/mon842/threads/llms.txt Deletes a thread and all its descendants recursively. It also removes references from User and Community documents and revalidates the provided path. ```APIDOC ## deleteThread — Delete a thread and all descendants Recursively collects all child and grandchild thread IDs, bulk-deletes them, and removes their references from all affected User and Community documents. ### Method Signature ```typescript deleteThread(threadId: string, path: string): Promise ``` ### Parameters - **threadId** (string) - The ID of the thread to delete. - **path** (string) - The path to revalidate after deletion. ### Example Usage ```typescript await deleteThread("64c9f0e1234abc0012ab1234", "/profile/user_abc"); ``` ### Returns - **void** — Throws an Error on failure. ### Side Effects - Deletes the main thread and all child/grandchild threads. - Updates `User.threads` and `Community.threads` arrays by removing deleted IDs. - Revalidates the provided path. ``` -------------------------------- ### Delete a thread and its descendants Source: https://context7.com/mon842/threads/llms.txt Recursively deletes a thread and all its child threads. It also updates the `threads` arrays in affected User and Community documents and revalidates the provided path. Throws an error on failure. ```typescript import { deleteThread } from "@/lib/actions/thread.actions"; await deleteThread("64c9f0e1234abc0012ab1234", "/profile/user_abc"); // Deletes: main thread + all child/grandchild threads // Updates: User.threads and Community.threads arrays (pulls deleted IDs) // Revalidates: the provided path // Returns: void — throws Error on failure ``` -------------------------------- ### Update Community Information Source: https://context7.com/mon842/threads/llms.txt Updates the name, username, and image of a community based on its Clerk organization ID. This function is triggered by the Clerk webhook on `organization.updated`. ```typescript import { updateCommunityInfo } from "@/lib/actions/community.actions"; await updateCommunityInfo( "org_2abc123XYZ", "Next.js & React Developers", "nextjs-react-devs", "https://uploadthing.com/f/newlogo.jpg" ); // Returns: old Community document (pre-update) ``` -------------------------------- ### Remove User from Community Source: https://context7.com/mon842/threads/llms.txt Removes a user from a community by pulling their ID from the community's members array and the community's ID from the user's communities array. This is used by the Clerk webhook on `organizationMembership.deleted`. ```typescript import { removeUserFromCommunity } from "@/lib/actions/community.actions"; const result = await removeUserFromCommunity( "user_2NkLm8XyZ", // Clerk user ID "org_2abc123XYZ" // Clerk organization ID ); // Returns: { success: true } ``` -------------------------------- ### deleteCommunity Source: https://context7.com/mon842/threads/llms.txt Deletes a community and all its associated content, including threads and references in member arrays. ```APIDOC ## deleteCommunity — Delete a community and its content Deletes the Community document, all threads belonging to it, and removes the community reference from every member's `communities` array. ```typescript import { deleteCommunity } from "@/lib/actions/community.actions"; await deleteCommunity("org_2abc123XYZ"); // Deletes: Community document // Deletes: all Thread documents with community === communityId // Updates: all member User documents (pulls communityId from communities array) // Returns: deleted Community document ``` ``` -------------------------------- ### Delete Community and its Content Source: https://context7.com/mon842/threads/llms.txt Deletes a community, all its associated threads, and removes the community reference from all member user documents. This is called from the Clerk webhook on `organization.deleted`. ```typescript import { deleteCommunity } from "@/lib/actions/community.actions"; await deleteCommunity("org_2abc123XYZ"); // Deletes: Community document // Deletes: all Thread documents with community === communityId // Updates: all member User documents (pulls communityId from communities array) // Returns: deleted Community document ``` -------------------------------- ### removeUserFromCommunity Source: https://context7.com/mon842/threads/llms.txt Removes a user from a community by updating both the user's and community's member arrays. ```APIDOC ## removeUserFromCommunity — Remove a user from a community Pulls the user's `_id` from the community's `members` array and the community's `_id` from the user's `communities` array. Called from the Clerk webhook on `organizationMembership.deleted`. ```typescript import { removeUserFromCommunity } from "@/lib/actions/community.actions"; const result = await removeUserFromCommunity( "user_2NkLm8XyZ", // Clerk user ID "org_2abc123XYZ" // Clerk organization ID ); // Returns: { success: true } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.