Repository: hiteshchoudhary/chai-backend
Branch: main
Commit: d1d939021155
Files: 41
Total size: 40.6 KB
Directory structure:
gitextract_8a_1uytj/
├── .gitignore
├── .prettierignore
├── .prettierrc
├── Readme.md
├── package.json
├── public/
│ └── temp/
│ └── .gitkeep
└── src/
├── app.js
├── constants.js
├── controllers/
│ ├── comment.controller.js
│ ├── dashboard.controller.js
│ ├── healthcheck.controller.js
│ ├── like.controller.js
│ ├── playlist.controller.js
│ ├── subscription.controller.js
│ ├── tweet.controller.js
│ ├── user.controller.js
│ └── video.controller.js
├── db/
│ └── index.js
├── index.js
├── middlewares/
│ ├── auth.middleware.js
│ └── multer.middleware.js
├── models/
│ ├── comment.model.js
│ ├── like.model.js
│ ├── playlist.model.js
│ ├── subscription.model.js
│ ├── tweet.model.js
│ ├── user.model.js
│ └── video.model.js
├── routes/
│ ├── comment.routes.js
│ ├── dashboard.routes.js
│ ├── healthcheck.routes.js
│ ├── like.routes.js
│ ├── playlist.routes.js
│ ├── subscription.routes.js
│ ├── tweet.routes.js
│ ├── user.routes.js
│ └── video.routes.js
└── utils/
├── ApiError.js
├── ApiResponse.js
├── asyncHandler.js
└── cloudinary.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
.env.production
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# End of https://mrkandreev.name/snippets/gitignore-generator/#Node
.DS_Store
================================================
FILE: .prettierignore
================================================
/.vscode
/node_modules
./dist
*.env
.env
.env.*
================================================
FILE: .prettierrc
================================================
{
"singleQuote": false,
"bracketSpacing": true,
"tabWidth": 2,
"trailingComma": "es5",
"semi": true
}
================================================
FILE: Readme.md
================================================
# chai aur backend series
This is a video series on backend with javascript
- [Model link](https://app.eraser.io/workspace/YtPqZ1VogxGy1jzIDkzj?origin=share)
- [Video playlist](https://www.youtube.com/watch?v=EH3vGeqeIAo&list=PLu71SKxNbfoBGh_8p_NS-ZAh6v7HhYqHW)
---
# Summary of this project
This project is a complex backend project that is built with nodejs, expressjs, mongodb, mongoose, jwt, bcrypt, and many more. This project is a complete backend project that has all the features that a backend project should have.
We are building a complete video hosting website similar to youtube with all the features like login, signup, upload video, like, dislike, comment, reply, subscribe, unsubscribe, and many more.
Project uses all standard practices like JWT, bcrypt, access tokens, refresh Tokens and many more. We have spent a lot of time in building this project and we are sure that you will learn a lot from this project.
---
Top Contributer to complete all TODOs
1. Spiderman (just sample) [Link to Repo](https://www.youtube.com/@chaiaurcode)
---
## How to contribute in this open source Project
First, please understand that this is not your regular project to merge your PR. This repo requires you to finish all assignments that are in controller folder. We don't accept half work, please finish all controllers and then reach us out on [Discord](https://hitesh.ai/discord) or [Twitter](https://twitter.com/@hiteshdotcom) and after checking your repo, I will add link to your repo in this readme.
================================================
FILE: package.json
================================================
{
"name": "chai-backend",
"version": "1.0.0",
"description": "a backend at chai aur code channel - youtube",
"type": "module",
"main": "index.js",
"scripts": {
"dev": "nodemon -r dotenv/config --experimental-json-modules src/index.js"
},
"keywords": [
"javascript",
"backend",
"chai"
],
"author": "Hitesh Choudhary",
"license": "ISC",
"devDependencies": {
"nodemon": "^3.0.1",
"prettier": "^3.0.3"
},
"dependencies": {
"bcrypt": "^5.1.1",
"cloudinary": "^1.41.0",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.0.0",
"mongoose-aggregate-paginate-v2": "^1.0.6",
"multer": "^1.4.5-lts.1"
}
}
================================================
FILE: public/temp/.gitkeep
================================================
================================================
FILE: src/app.js
================================================
import express from "express"
import cors from "cors"
import cookieParser from "cookie-parser"
const app = express()
app.use(cors({
origin: process.env.CORS_ORIGIN,
credentials: true
}))
app.use(express.json({limit: "16kb"}))
app.use(express.urlencoded({extended: true, limit: "16kb"}))
app.use(express.static("public"))
app.use(cookieParser())
//routes import
import userRouter from './routes/user.routes.js'
import healthcheckRouter from "./routes/healthcheck.routes.js"
import tweetRouter from "./routes/tweet.routes.js"
import subscriptionRouter from "./routes/subscription.routes.js"
import videoRouter from "./routes/video.routes.js"
import commentRouter from "./routes/comment.routes.js"
import likeRouter from "./routes/like.routes.js"
import playlistRouter from "./routes/playlist.routes.js"
import dashboardRouter from "./routes/dashboard.routes.js"
//routes declaration
app.use("/api/v1/healthcheck", healthcheckRouter)
app.use("/api/v1/users", userRouter)
app.use("/api/v1/tweets", tweetRouter)
app.use("/api/v1/subscriptions", subscriptionRouter)
app.use("/api/v1/videos", videoRouter)
app.use("/api/v1/comments", commentRouter)
app.use("/api/v1/likes", likeRouter)
app.use("/api/v1/playlist", playlistRouter)
app.use("/api/v1/dashboard", dashboardRouter)
// http://localhost:8000/api/v1/users/register
export { app }
================================================
FILE: src/constants.js
================================================
export const DB_NAME = "videotube"
================================================
FILE: src/controllers/comment.controller.js
================================================
import mongoose from "mongoose"
import {Comment} from "../models/comment.model.js"
import {ApiError} from "../utils/ApiError.js"
import {ApiResponse} from "../utils/ApiResponse.js"
import {asyncHandler} from "../utils/asyncHandler.js"
const getVideoComments = asyncHandler(async (req, res) => {
//TODO: get all comments for a video
const {videoId} = req.params
const {page = 1, limit = 10} = req.query
})
const addComment = asyncHandler(async (req, res) => {
// TODO: add a comment to a video
})
const updateComment = asyncHandler(async (req, res) => {
// TODO: update a comment
})
const deleteComment = asyncHandler(async (req, res) => {
// TODO: delete a comment
})
export {
getVideoComments,
addComment,
updateComment,
deleteComment
}
================================================
FILE: src/controllers/dashboard.controller.js
================================================
import mongoose from "mongoose"
import {Video} from "../models/video.model.js"
import {Subscription} from "../models/subscription.model.js"
import {Like} from "../models/like.model.js"
import {ApiError} from "../utils/ApiError.js"
import {ApiResponse} from "../utils/ApiResponse.js"
import {asyncHandler} from "../utils/asyncHandler.js"
const getChannelStats = asyncHandler(async (req, res) => {
// TODO: Get the channel stats like total video views, total subscribers, total videos, total likes etc.
})
const getChannelVideos = asyncHandler(async (req, res) => {
// TODO: Get all the videos uploaded by the channel
})
export {
getChannelStats,
getChannelVideos
}
================================================
FILE: src/controllers/healthcheck.controller.js
================================================
import {ApiError} from "../utils/ApiError.js"
import {ApiResponse} from "../utils/ApiResponse.js"
import {asyncHandler} from "../utils/asyncHandler.js"
const healthcheck = asyncHandler(async (req, res) => {
//TODO: build a healthcheck response that simply returns the OK status as json with a message
})
export {
healthcheck
}
================================================
FILE: src/controllers/like.controller.js
================================================
import mongoose, {isValidObjectId} from "mongoose"
import {Like} from "../models/like.model.js"
import {ApiError} from "../utils/ApiError.js"
import {ApiResponse} from "../utils/ApiResponse.js"
import {asyncHandler} from "../utils/asyncHandler.js"
const toggleVideoLike = asyncHandler(async (req, res) => {
const {videoId} = req.params
//TODO: toggle like on video
})
const toggleCommentLike = asyncHandler(async (req, res) => {
const {commentId} = req.params
//TODO: toggle like on comment
})
const toggleTweetLike = asyncHandler(async (req, res) => {
const {tweetId} = req.params
//TODO: toggle like on tweet
}
)
const getLikedVideos = asyncHandler(async (req, res) => {
//TODO: get all liked videos
})
export {
toggleCommentLike,
toggleTweetLike,
toggleVideoLike,
getLikedVideos
}
================================================
FILE: src/controllers/playlist.controller.js
================================================
import mongoose, {isValidObjectId} from "mongoose"
import {Playlist} from "../models/playlist.model.js"
import {ApiError} from "../utils/ApiError.js"
import {ApiResponse} from "../utils/ApiResponse.js"
import {asyncHandler} from "../utils/asyncHandler.js"
const createPlaylist = asyncHandler(async (req, res) => {
const {name, description} = req.body
//TODO: create playlist
})
const getUserPlaylists = asyncHandler(async (req, res) => {
const {userId} = req.params
//TODO: get user playlists
})
const getPlaylistById = asyncHandler(async (req, res) => {
const {playlistId} = req.params
//TODO: get playlist by id
})
const addVideoToPlaylist = asyncHandler(async (req, res) => {
const {playlistId, videoId} = req.params
})
const removeVideoFromPlaylist = asyncHandler(async (req, res) => {
const {playlistId, videoId} = req.params
// TODO: remove video from playlist
})
const deletePlaylist = asyncHandler(async (req, res) => {
const {playlistId} = req.params
// TODO: delete playlist
})
const updatePlaylist = asyncHandler(async (req, res) => {
const {playlistId} = req.params
const {name, description} = req.body
//TODO: update playlist
})
export {
createPlaylist,
getUserPlaylists,
getPlaylistById,
addVideoToPlaylist,
removeVideoFromPlaylist,
deletePlaylist,
updatePlaylist
}
================================================
FILE: src/controllers/subscription.controller.js
================================================
import mongoose, {isValidObjectId} from "mongoose"
import {User} from "../models/user.model.js"
import { Subscription } from "../models/subscription.model.js"
import {ApiError} from "../utils/ApiError.js"
import {ApiResponse} from "../utils/ApiResponse.js"
import {asyncHandler} from "../utils/asyncHandler.js"
const toggleSubscription = asyncHandler(async (req, res) => {
const {channelId} = req.params
// TODO: toggle subscription
})
// controller to return subscriber list of a channel
const getUserChannelSubscribers = asyncHandler(async (req, res) => {
const {channelId} = req.params
})
// controller to return channel list to which user has subscribed
const getSubscribedChannels = asyncHandler(async (req, res) => {
const { subscriberId } = req.params
})
export {
toggleSubscription,
getUserChannelSubscribers,
getSubscribedChannels
}
================================================
FILE: src/controllers/tweet.controller.js
================================================
import mongoose, { isValidObjectId } from "mongoose"
import {Tweet} from "../models/tweet.model.js"
import {User} from "../models/user.model.js"
import {ApiError} from "../utils/ApiError.js"
import {ApiResponse} from "../utils/ApiResponse.js"
import {asyncHandler} from "../utils/asyncHandler.js"
const createTweet = asyncHandler(async (req, res) => {
//TODO: create tweet
})
const getUserTweets = asyncHandler(async (req, res) => {
// TODO: get user tweets
})
const updateTweet = asyncHandler(async (req, res) => {
//TODO: update tweet
})
const deleteTweet = asyncHandler(async (req, res) => {
//TODO: delete tweet
})
export {
createTweet,
getUserTweets,
updateTweet,
deleteTweet
}
================================================
FILE: src/controllers/user.controller.js
================================================
import { asyncHandler } from "../utils/asyncHandler.js";
import {ApiError} from "../utils/ApiError.js"
import { User} from "../models/user.model.js"
import {uploadOnCloudinary} from "../utils/cloudinary.js"
import { ApiResponse } from "../utils/ApiResponse.js";
import jwt from "jsonwebtoken"
import mongoose from "mongoose";
const generateAccessAndRefereshTokens = async(userId) =>{
try {
const user = await User.findById(userId)
const accessToken = user.generateAccessToken()
const refreshToken = user.generateRefreshToken()
user.refreshToken = refreshToken
await user.save({ validateBeforeSave: false })
return {accessToken, refreshToken}
} catch (error) {
throw new ApiError(500, "Something went wrong while generating referesh and access token")
}
}
const registerUser = asyncHandler( async (req, res) => {
// get user details from frontend
// validation - not empty
// check if user already exists: username, email
// check for images, check for avatar
// upload them to cloudinary, avatar
// create user object - create entry in db
// remove password and refresh token field from response
// check for user creation
// return res
const {fullName, email, username, password } = req.body
//console.log("email: ", email);
if (
[fullName, email, username, password].some((field) => field?.trim() === "")
) {
throw new ApiError(400, "All fields are required")
}
const existedUser = await User.findOne({
$or: [{ username }, { email }]
})
if (existedUser) {
throw new ApiError(409, "User with email or username already exists")
}
//console.log(req.files);
const avatarLocalPath = req.files?.avatar[0]?.path;
//const coverImageLocalPath = req.files?.coverImage[0]?.path;
let coverImageLocalPath;
if (req.files && Array.isArray(req.files.coverImage) && req.files.coverImage.length > 0) {
coverImageLocalPath = req.files.coverImage[0].path
}
if (!avatarLocalPath) {
throw new ApiError(400, "Avatar file is required")
}
const avatar = await uploadOnCloudinary(avatarLocalPath)
const coverImage = await uploadOnCloudinary(coverImageLocalPath)
if (!avatar) {
throw new ApiError(400, "Avatar file is required")
}
const user = await User.create({
fullName,
avatar: avatar.url,
coverImage: coverImage?.url || "",
email,
password,
username: username.toLowerCase()
})
const createdUser = await User.findById(user._id).select(
"-password -refreshToken"
)
if (!createdUser) {
throw new ApiError(500, "Something went wrong while registering the user")
}
return res.status(201).json(
new ApiResponse(200, createdUser, "User registered Successfully")
)
} )
const loginUser = asyncHandler(async (req, res) =>{
// req body -> data
// username or email
//find the user
//password check
//access and referesh token
//send cookie
const {email, username, password} = req.body
console.log(email);
if (!username && !email) {
throw new ApiError(400, "username or email is required")
}
// Here is an alternative of above code based on logic discussed in video:
// if (!(username || email)) {
// throw new ApiError(400, "username or email is required")
// }
const user = await User.findOne({
$or: [{username}, {email}]
})
if (!user) {
throw new ApiError(404, "User does not exist")
}
const isPasswordValid = await user.isPasswordCorrect(password)
if (!isPasswordValid) {
throw new ApiError(401, "Invalid user credentials")
}
const {accessToken, refreshToken} = await generateAccessAndRefereshTokens(user._id)
const loggedInUser = await User.findById(user._id).select("-password -refreshToken")
const options = {
httpOnly: true,
secure: true
}
return res
.status(200)
.cookie("accessToken", accessToken, options)
.cookie("refreshToken", refreshToken, options)
.json(
new ApiResponse(
200,
{
user: loggedInUser, accessToken, refreshToken
},
"User logged In Successfully"
)
)
})
const logoutUser = asyncHandler(async(req, res) => {
await User.findByIdAndUpdate(
req.user._id,
{
$unset: {
refreshToken: 1 // this removes the field from document
}
},
{
new: true
}
)
const options = {
httpOnly: true,
secure: true
}
return res
.status(200)
.clearCookie("accessToken", options)
.clearCookie("refreshToken", options)
.json(new ApiResponse(200, {}, "User logged Out"))
})
const refreshAccessToken = asyncHandler(async (req, res) => {
const incomingRefreshToken = req.cookies.refreshToken || req.body.refreshToken
if (!incomingRefreshToken) {
throw new ApiError(401, "unauthorized request")
}
try {
const decodedToken = jwt.verify(
incomingRefreshToken,
process.env.REFRESH_TOKEN_SECRET
)
const user = await User.findById(decodedToken?._id)
if (!user) {
throw new ApiError(401, "Invalid refresh token")
}
if (incomingRefreshToken !== user?.refreshToken) {
throw new ApiError(401, "Refresh token is expired or used")
}
const options = {
httpOnly: true,
secure: true
}
const {accessToken, newRefreshToken} = await generateAccessAndRefereshTokens(user._id)
return res
.status(200)
.cookie("accessToken", accessToken, options)
.cookie("refreshToken", newRefreshToken, options)
.json(
new ApiResponse(
200,
{accessToken, refreshToken: newRefreshToken},
"Access token refreshed"
)
)
} catch (error) {
throw new ApiError(401, error?.message || "Invalid refresh token")
}
})
const changeCurrentPassword = asyncHandler(async(req, res) => {
const {oldPassword, newPassword} = req.body
const user = await User.findById(req.user?._id)
const isPasswordCorrect = await user.isPasswordCorrect(oldPassword)
if (!isPasswordCorrect) {
throw new ApiError(400, "Invalid old password")
}
user.password = newPassword
await user.save({validateBeforeSave: false})
return res
.status(200)
.json(new ApiResponse(200, {}, "Password changed successfully"))
})
const getCurrentUser = asyncHandler(async(req, res) => {
return res
.status(200)
.json(new ApiResponse(
200,
req.user,
"User fetched successfully"
))
})
const updateAccountDetails = asyncHandler(async(req, res) => {
const {fullName, email} = req.body
if (!fullName || !email) {
throw new ApiError(400, "All fields are required")
}
const user = await User.findByIdAndUpdate(
req.user?._id,
{
$set: {
fullName,
email: email
}
},
{new: true}
).select("-password")
return res
.status(200)
.json(new ApiResponse(200, user, "Account details updated successfully"))
});
const updateUserAvatar = asyncHandler(async(req, res) => {
const avatarLocalPath = req.file?.path
if (!avatarLocalPath) {
throw new ApiError(400, "Avatar file is missing")
}
//TODO: delete old image - assignment
const avatar = await uploadOnCloudinary(avatarLocalPath)
if (!avatar.url) {
throw new ApiError(400, "Error while uploading on avatar")
}
const user = await User.findByIdAndUpdate(
req.user?._id,
{
$set:{
avatar: avatar.url
}
},
{new: true}
).select("-password")
return res
.status(200)
.json(
new ApiResponse(200, user, "Avatar image updated successfully")
)
})
const updateUserCoverImage = asyncHandler(async(req, res) => {
const coverImageLocalPath = req.file?.path
if (!coverImageLocalPath) {
throw new ApiError(400, "Cover image file is missing")
}
//TODO: delete old image - assignment
const coverImage = await uploadOnCloudinary(coverImageLocalPath)
if (!coverImage.url) {
throw new ApiError(400, "Error while uploading on avatar")
}
const user = await User.findByIdAndUpdate(
req.user?._id,
{
$set:{
coverImage: coverImage.url
}
},
{new: true}
).select("-password")
return res
.status(200)
.json(
new ApiResponse(200, user, "Cover image updated successfully")
)
})
const getUserChannelProfile = asyncHandler(async(req, res) => {
const {username} = req.params
if (!username?.trim()) {
throw new ApiError(400, "username is missing")
}
const channel = await User.aggregate([
{
$match: {
username: username?.toLowerCase()
}
},
{
$lookup: {
from: "subscriptions",
localField: "_id",
foreignField: "channel",
as: "subscribers"
}
},
{
$lookup: {
from: "subscriptions",
localField: "_id",
foreignField: "subscriber",
as: "subscribedTo"
}
},
{
$addFields: {
subscribersCount: {
$size: "$subscribers"
},
channelsSubscribedToCount: {
$size: "$subscribedTo"
},
isSubscribed: {
$cond: {
if: {$in: [req.user?._id, "$subscribers.subscriber"]},
then: true,
else: false
}
}
}
},
{
$project: {
fullName: 1,
username: 1,
subscribersCount: 1,
channelsSubscribedToCount: 1,
isSubscribed: 1,
avatar: 1,
coverImage: 1,
email: 1
}
}
])
if (!channel?.length) {
throw new ApiError(404, "channel does not exists")
}
return res
.status(200)
.json(
new ApiResponse(200, channel[0], "User channel fetched successfully")
)
})
const getWatchHistory = asyncHandler(async(req, res) => {
const user = await User.aggregate([
{
$match: {
_id: new mongoose.Types.ObjectId(req.user._id)
}
},
{
$lookup: {
from: "videos",
localField: "watchHistory",
foreignField: "_id",
as: "watchHistory",
pipeline: [
{
$lookup: {
from: "users",
localField: "owner",
foreignField: "_id",
as: "owner",
pipeline: [
{
$project: {
fullName: 1,
username: 1,
avatar: 1
}
}
]
}
},
{
$addFields:{
owner:{
$first: "$owner"
}
}
}
]
}
}
])
return res
.status(200)
.json(
new ApiResponse(
200,
user[0].watchHistory,
"Watch history fetched successfully"
)
)
})
export {
registerUser,
loginUser,
logoutUser,
refreshAccessToken,
changeCurrentPassword,
getCurrentUser,
updateAccountDetails,
updateUserAvatar,
updateUserCoverImage,
getUserChannelProfile,
getWatchHistory
}
================================================
FILE: src/controllers/video.controller.js
================================================
import mongoose, {isValidObjectId} from "mongoose"
import {Video} from "../models/video.model.js"
import {User} from "../models/user.model.js"
import {ApiError} from "../utils/ApiError.js"
import {ApiResponse} from "../utils/ApiResponse.js"
import {asyncHandler} from "../utils/asyncHandler.js"
import {uploadOnCloudinary} from "../utils/cloudinary.js"
const getAllVideos = asyncHandler(async (req, res) => {
const { page = 1, limit = 10, query, sortBy, sortType, userId } = req.query
//TODO: get all videos based on query, sort, pagination
})
const publishAVideo = asyncHandler(async (req, res) => {
const { title, description} = req.body
// TODO: get video, upload to cloudinary, create video
})
const getVideoById = asyncHandler(async (req, res) => {
const { videoId } = req.params
//TODO: get video by id
})
const updateVideo = asyncHandler(async (req, res) => {
const { videoId } = req.params
//TODO: update video details like title, description, thumbnail
})
const deleteVideo = asyncHandler(async (req, res) => {
const { videoId } = req.params
//TODO: delete video
})
const togglePublishStatus = asyncHandler(async (req, res) => {
const { videoId } = req.params
})
export {
getAllVideos,
publishAVideo,
getVideoById,
updateVideo,
deleteVideo,
togglePublishStatus
}
================================================
FILE: src/db/index.js
================================================
import mongoose from "mongoose";
import { DB_NAME } from "../constants.js";
const connectDB = async () => {
try {
const connectionInstance = await mongoose.connect(`${process.env.MONGODB_URI}/${DB_NAME}`)
console.log(`\n MongoDB connected !! DB HOST: ${connectionInstance.connection.host}`);
} catch (error) {
console.log("MONGODB connection FAILED ", error);
process.exit(1)
}
}
export default connectDB
================================================
FILE: src/index.js
================================================
// require('dotenv').config({path: './env'})
import dotenv from "dotenv"
import connectDB from "./db/index.js";
import {app} from './app.js'
dotenv.config({
path: './.env'
})
connectDB()
.then(() => {
app.listen(process.env.PORT || 8000, () => {
console.log(`⚙️ Server is running at port : ${process.env.PORT}`);
})
})
.catch((err) => {
console.log("MONGO db connection failed !!! ", err);
})
/*
import express from "express"
const app = express()
( async () => {
try {
await mongoose.connect(`${process.env.MONGODB_URI}/${DB_NAME}`)
app.on("errror", (error) => {
console.log("ERRR: ", error);
throw error
})
app.listen(process.env.PORT, () => {
console.log(`App is listening on port ${process.env.PORT}`);
})
} catch (error) {
console.error("ERROR: ", error)
throw err
}
})()
*/
================================================
FILE: src/middlewares/auth.middleware.js
================================================
import { ApiError } from "../utils/ApiError.js";
import { asyncHandler } from "../utils/asyncHandler.js";
import jwt from "jsonwebtoken"
import { User } from "../models/user.model.js";
export const verifyJWT = asyncHandler(async(req, _, next) => {
try {
const token = req.cookies?.accessToken || req.header("Authorization")?.replace("Bearer ", "")
// console.log(token);
if (!token) {
throw new ApiError(401, "Unauthorized request")
}
const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET)
const user = await User.findById(decodedToken?._id).select("-password -refreshToken")
if (!user) {
throw new ApiError(401, "Invalid Access Token")
}
req.user = user;
next()
} catch (error) {
throw new ApiError(401, error?.message || "Invalid access token")
}
})
================================================
FILE: src/middlewares/multer.middleware.js
================================================
import multer from "multer";
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./public/temp")
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
export const upload = multer({
storage,
})
================================================
FILE: src/models/comment.model.js
================================================
import mongoose, {Schema} from "mongoose";
import mongooseAggregatePaginate from "mongoose-aggregate-paginate-v2";
const commentSchema = new Schema(
{
content: {
type: String,
required: true
},
video: {
type: Schema.Types.ObjectId,
ref: "Video"
},
owner: {
type: Schema.Types.ObjectId,
ref: "User"
}
},
{
timestamps: true
}
)
commentSchema.plugin(mongooseAggregatePaginate)
export const Comment = mongoose.model("Comment", commentSchema)
================================================
FILE: src/models/like.model.js
================================================
import mongoose, {Schema} from "mongoose";
const likeSchema = new Schema({
video: {
type: Schema.Types.ObjectId,
ref: "Video"
},
comment: {
type: Schema.Types.ObjectId,
ref: "Comment"
},
tweet: {
type: Schema.Types.ObjectId,
ref: "Tweet"
},
likedBy: {
type: Schema.Types.ObjectId,
ref: "User"
},
}, {timestamps: true})
export const Like = mongoose.model("Like", likeSchema)
================================================
FILE: src/models/playlist.model.js
================================================
import mongoose, {Schema} from "mongoose";
const playlistSchema = new Schema({
name: {
type: String,
required: true
},
description: {
type: String,
required: true
},
videos: [
{
type: Schema.Types.ObjectId,
ref: "Video"
}
],
owner: {
type: Schema.Types.ObjectId,
ref: "User"
},
}, {timestamps: true})
export const Playlist = mongoose.model("Playlist", playlistSchema)
================================================
FILE: src/models/subscription.model.js
================================================
import mongoose, {Schema} from "mongoose"
const subscriptionSchema = new Schema({
subscriber: {
type: Schema.Types.ObjectId, // one who is subscribing
ref: "User"
},
channel: {
type: Schema.Types.ObjectId, // one to whom 'subscriber' is subscribing
ref: "User"
}
}, {timestamps: true})
export const Subscription = mongoose.model("Subscription", subscriptionSchema)
================================================
FILE: src/models/tweet.model.js
================================================
import mongoose, {Schema} from "mongoose";
const tweetSchema = new Schema({
content: {
type: String,
required: true
},
owner: {
type: Schema.Types.ObjectId,
ref: "User"
}
}, {timestamps: true})
export const Tweet = mongoose.model("Tweet", tweetSchema)
================================================
FILE: src/models/user.model.js
================================================
import mongoose, {Schema} from "mongoose";
import jwt from "jsonwebtoken"
import bcrypt from "bcrypt"
const userSchema = new Schema(
{
username: {
type: String,
required: true,
unique: true,
lowercase: true,
trim: true,
index: true
},
email: {
type: String,
required: true,
unique: true,
lowecase: true,
trim: true,
},
fullName: {
type: String,
required: true,
trim: true,
index: true
},
avatar: {
type: String, // cloudinary url
required: true,
},
coverImage: {
type: String, // cloudinary url
},
watchHistory: [
{
type: Schema.Types.ObjectId,
ref: "Video"
}
],
password: {
type: String,
required: [true, 'Password is required']
},
refreshToken: {
type: String
}
},
{
timestamps: true
}
)
userSchema.pre("save", async function (next) {
if(!this.isModified("password")) return next();
this.password = await bcrypt.hash(this.password, 10)
next()
})
userSchema.methods.isPasswordCorrect = async function(password){
return await bcrypt.compare(password, this.password)
}
userSchema.methods.generateAccessToken = function(){
return jwt.sign(
{
_id: this._id,
email: this.email,
username: this.username,
fullName: this.fullName
},
process.env.ACCESS_TOKEN_SECRET,
{
expiresIn: process.env.ACCESS_TOKEN_EXPIRY
}
)
}
userSchema.methods.generateRefreshToken = function(){
return jwt.sign(
{
_id: this._id,
},
process.env.REFRESH_TOKEN_SECRET,
{
expiresIn: process.env.REFRESH_TOKEN_EXPIRY
}
)
}
export const User = mongoose.model("User", userSchema)
================================================
FILE: src/models/video.model.js
================================================
import mongoose, {Schema} from "mongoose";
import mongooseAggregatePaginate from "mongoose-aggregate-paginate-v2";
const videoSchema = new Schema(
{
videoFile: {
type: String, //cloudinary url
required: true
},
thumbnail: {
type: String, //cloudinary url
required: true
},
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
duration: {
type: Number,
required: true
},
views: {
type: Number,
default: 0
},
isPublished: {
type: Boolean,
default: true
},
owner: {
type: Schema.Types.ObjectId,
ref: "User"
}
},
{
timestamps: true
}
)
videoSchema.plugin(mongooseAggregatePaginate)
export const Video = mongoose.model("Video", videoSchema)
================================================
FILE: src/routes/comment.routes.js
================================================
import { Router } from 'express';
import {
addComment,
deleteComment,
getVideoComments,
updateComment,
} from "../controllers/comment.controller.js"
import {verifyJWT} from "../middlewares/auth.middleware.js"
const router = Router();
router.use(verifyJWT); // Apply verifyJWT middleware to all routes in this file
router.route("/:videoId").get(getVideoComments).post(addComment);
router.route("/c/:commentId").delete(deleteComment).patch(updateComment);
export default router
================================================
FILE: src/routes/dashboard.routes.js
================================================
import { Router } from 'express';
import {
getChannelStats,
getChannelVideos,
} from "../controllers/dashboard.controller.js"
import {verifyJWT} from "../middlewares/auth.middleware.js"
const router = Router();
router.use(verifyJWT); // Apply verifyJWT middleware to all routes in this file
router.route("/stats").get(getChannelStats);
router.route("/videos").get(getChannelVideos);
export default router
================================================
FILE: src/routes/healthcheck.routes.js
================================================
import { Router } from 'express';
import { healthcheck } from "../controllers/healthcheck.controller.js"
const router = Router();
router.route('/').get(healthcheck);
export default router
================================================
FILE: src/routes/like.routes.js
================================================
import { Router } from 'express';
import {
getLikedVideos,
toggleCommentLike,
toggleVideoLike,
toggleTweetLike,
} from "../controllers/like.controller.js"
import {verifyJWT} from "../middlewares/auth.middleware.js"
const router = Router();
router.use(verifyJWT); // Apply verifyJWT middleware to all routes in this file
router.route("/toggle/v/:videoId").post(toggleVideoLike);
router.route("/toggle/c/:commentId").post(toggleCommentLike);
router.route("/toggle/t/:tweetId").post(toggleTweetLike);
router.route("/videos").get(getLikedVideos);
export default router
================================================
FILE: src/routes/playlist.routes.js
================================================
import { Router } from 'express';
import {
addVideoToPlaylist,
createPlaylist,
deletePlaylist,
getPlaylistById,
getUserPlaylists,
removeVideoFromPlaylist,
updatePlaylist,
} from "../controllers/playlist.controller.js"
import {verifyJWT} from "../middlewares/auth.middleware.js"
const router = Router();
router.use(verifyJWT); // Apply verifyJWT middleware to all routes in this file
router.route("/").post(createPlaylist)
router
.route("/:playlistId")
.get(getPlaylistById)
.patch(updatePlaylist)
.delete(deletePlaylist);
router.route("/add/:videoId/:playlistId").patch(addVideoToPlaylist);
router.route("/remove/:videoId/:playlistId").patch(removeVideoFromPlaylist);
router.route("/user/:userId").get(getUserPlaylists);
export default router
================================================
FILE: src/routes/subscription.routes.js
================================================
import { Router } from 'express';
import {
getSubscribedChannels,
getUserChannelSubscribers,
toggleSubscription,
} from "../controllers/subscription.controller.js"
import {verifyJWT} from "../middlewares/auth.middleware.js"
const router = Router();
router.use(verifyJWT); // Apply verifyJWT middleware to all routes in this file
router
.route("/c/:channelId")
.get(getSubscribedChannels)
.post(toggleSubscription);
router.route("/u/:subscriberId").get(getUserChannelSubscribers);
export default router
================================================
FILE: src/routes/tweet.routes.js
================================================
import { Router } from 'express';
import {
createTweet,
deleteTweet,
getUserTweets,
updateTweet,
} from "../controllers/tweet.controller.js"
import {verifyJWT} from "../middlewares/auth.middleware.js"
const router = Router();
router.use(verifyJWT); // Apply verifyJWT middleware to all routes in this file
router.route("/").post(createTweet);
router.route("/user/:userId").get(getUserTweets);
router.route("/:tweetId").patch(updateTweet).delete(deleteTweet);
export default router
================================================
FILE: src/routes/user.routes.js
================================================
import { Router } from "express";
import {
loginUser,
logoutUser,
registerUser,
refreshAccessToken,
changeCurrentPassword,
getCurrentUser,
updateUserAvatar,
updateUserCoverImage,
getUserChannelProfile,
getWatchHistory,
updateAccountDetails
} from "../controllers/user.controller.js";
import {upload} from "../middlewares/multer.middleware.js"
import { verifyJWT } from "../middlewares/auth.middleware.js";
const router = Router()
router.route("/register").post(
upload.fields([
{
name: "avatar",
maxCount: 1
},
{
name: "coverImage",
maxCount: 1
}
]),
registerUser
)
router.route("/login").post(loginUser)
//secured routes
router.route("/logout").post(verifyJWT, logoutUser)
router.route("/refresh-token").post(refreshAccessToken)
router.route("/change-password").post(verifyJWT, changeCurrentPassword)
router.route("/current-user").get(verifyJWT, getCurrentUser)
router.route("/update-account").patch(verifyJWT, updateAccountDetails)
router.route("/avatar").patch(verifyJWT, upload.single("avatar"), updateUserAvatar)
router.route("/cover-image").patch(verifyJWT, upload.single("coverImage"), updateUserCoverImage)
router.route("/c/:username").get(verifyJWT, getUserChannelProfile)
router.route("/history").get(verifyJWT, getWatchHistory)
export default router
================================================
FILE: src/routes/video.routes.js
================================================
import { Router } from 'express';
import {
deleteVideo,
getAllVideos,
getVideoById,
publishAVideo,
togglePublishStatus,
updateVideo,
} from "../controllers/video.controller.js"
import {verifyJWT} from "../middlewares/auth.middleware.js"
import {upload} from "../middlewares/multer.middleware.js"
const router = Router();
router.use(verifyJWT); // Apply verifyJWT middleware to all routes in this file
router
.route("/")
.get(getAllVideos)
.post(
upload.fields([
{
name: "videoFile",
maxCount: 1,
},
{
name: "thumbnail",
maxCount: 1,
},
]),
publishAVideo
);
router
.route("/:videoId")
.get(getVideoById)
.delete(deleteVideo)
.patch(upload.single("thumbnail"), updateVideo);
router.route("/toggle/publish/:videoId").patch(togglePublishStatus);
export default router
================================================
FILE: src/utils/ApiError.js
================================================
class ApiError extends Error {
constructor(
statusCode,
message= "Something went wrong",
errors = [],
stack = ""
){
super(message)
this.statusCode = statusCode
this.data = null
this.message = message
this.success = false;
this.errors = errors
if (stack) {
this.stack = stack
} else{
Error.captureStackTrace(this, this.constructor)
}
}
}
export {ApiError}
================================================
FILE: src/utils/ApiResponse.js
================================================
class ApiResponse {
constructor(statusCode, data, message = "Success"){
this.statusCode = statusCode
this.data = data
this.message = message
this.success = statusCode < 400
}
}
export { ApiResponse }
================================================
FILE: src/utils/asyncHandler.js
================================================
const asyncHandler = (requestHandler) => {
return (req, res, next) => {
Promise.resolve(requestHandler(req, res, next)).catch((err) => next(err))
}
}
export { asyncHandler }
// const asyncHandler = () => {}
// const asyncHandler = (func) => () => {}
// const asyncHandler = (func) => async () => {}
// const asyncHandler = (fn) => async (req, res, next) => {
// try {
// await fn(req, res, next)
// } catch (error) {
// res.status(err.code || 500).json({
// success: false,
// message: err.message
// })
// }
// }
================================================
FILE: src/utils/cloudinary.js
================================================
import {v2 as cloudinary} from "cloudinary"
import fs from "fs"
cloudinary.config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET
});
const uploadOnCloudinary = async (localFilePath) => {
try {
if (!localFilePath) return null
//upload the file on cloudinary
const response = await cloudinary.uploader.upload(localFilePath, {
resource_type: "auto"
})
// file has been uploaded successfull
//console.log("file is uploaded on cloudinary ", response.url);
fs.unlinkSync(localFilePath)
return response;
} catch (error) {
fs.unlinkSync(localFilePath) // remove the locally saved temporary file as the upload operation got failed
return null;
}
}
export {uploadOnCloudinary}
gitextract_8a_1uytj/
├── .gitignore
├── .prettierignore
├── .prettierrc
├── Readme.md
├── package.json
├── public/
│ └── temp/
│ └── .gitkeep
└── src/
├── app.js
├── constants.js
├── controllers/
│ ├── comment.controller.js
│ ├── dashboard.controller.js
│ ├── healthcheck.controller.js
│ ├── like.controller.js
│ ├── playlist.controller.js
│ ├── subscription.controller.js
│ ├── tweet.controller.js
│ ├── user.controller.js
│ └── video.controller.js
├── db/
│ └── index.js
├── index.js
├── middlewares/
│ ├── auth.middleware.js
│ └── multer.middleware.js
├── models/
│ ├── comment.model.js
│ ├── like.model.js
│ ├── playlist.model.js
│ ├── subscription.model.js
│ ├── tweet.model.js
│ ├── user.model.js
│ └── video.model.js
├── routes/
│ ├── comment.routes.js
│ ├── dashboard.routes.js
│ ├── healthcheck.routes.js
│ ├── like.routes.js
│ ├── playlist.routes.js
│ ├── subscription.routes.js
│ ├── tweet.routes.js
│ ├── user.routes.js
│ └── video.routes.js
└── utils/
├── ApiError.js
├── ApiResponse.js
├── asyncHandler.js
└── cloudinary.js
SYMBOL INDEX (5 symbols across 3 files)
FILE: src/constants.js
constant DB_NAME (line 1) | const DB_NAME = "videotube"
FILE: src/utils/ApiError.js
class ApiError (line 1) | class ApiError extends Error {
method constructor (line 2) | constructor(
FILE: src/utils/ApiResponse.js
class ApiResponse (line 1) | class ApiResponse {
method constructor (line 2) | constructor(statusCode, data, message = "Success"){
Condensed preview — 41 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (46K chars).
[
{
"path": ".gitignore",
"chars": 1929,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Diagnostic reports"
},
{
"path": ".prettierignore",
"chars": 48,
"preview": "/.vscode\n/node_modules\n./dist\n\n*.env\n.env\n.env.*"
},
{
"path": ".prettierrc",
"chars": 121,
"preview": "{\n \"singleQuote\": false,\n \"bracketSpacing\": true,\n \"tabWidth\": 2,\n \"trailingComma\": \"es5\",\n \"semi\": true\n"
},
{
"path": "Readme.md",
"chars": 1521,
"preview": "# chai aur backend series \n\nThis is a video series on backend with javascript\n- [Model link](https://app.eraser.io/work"
},
{
"path": "package.json",
"chars": 767,
"preview": "{\n \"name\": \"chai-backend\",\n \"version\": \"1.0.0\",\n \"description\": \"a backend at chai aur code channel - youtube\",\n \"ty"
},
{
"path": "public/temp/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "src/app.js",
"chars": 1346,
"preview": "import express from \"express\"\nimport cors from \"cors\"\nimport cookieParser from \"cookie-parser\"\n\nconst app = express()\n\na"
},
{
"path": "src/constants.js",
"chars": 34,
"preview": "export const DB_NAME = \"videotube\""
},
{
"path": "src/controllers/comment.controller.js",
"chars": 791,
"preview": "import mongoose from \"mongoose\"\nimport {Comment} from \"../models/comment.model.js\"\nimport {ApiError} from \"../utils/ApiE"
},
{
"path": "src/controllers/dashboard.controller.js",
"chars": 687,
"preview": "import mongoose from \"mongoose\"\nimport {Video} from \"../models/video.model.js\"\nimport {Subscription} from \"../models/sub"
},
{
"path": "src/controllers/healthcheck.controller.js",
"chars": 346,
"preview": "import {ApiError} from \"../utils/ApiError.js\"\nimport {ApiResponse} from \"../utils/ApiResponse.js\"\nimport {asyncHandler} "
},
{
"path": "src/controllers/like.controller.js",
"chars": 833,
"preview": "import mongoose, {isValidObjectId} from \"mongoose\"\nimport {Like} from \"../models/like.model.js\"\nimport {ApiError} from \""
},
{
"path": "src/controllers/playlist.controller.js",
"chars": 1375,
"preview": "import mongoose, {isValidObjectId} from \"mongoose\"\nimport {Playlist} from \"../models/playlist.model.js\"\nimport {ApiError"
},
{
"path": "src/controllers/subscription.controller.js",
"chars": 874,
"preview": "import mongoose, {isValidObjectId} from \"mongoose\"\nimport {User} from \"../models/user.model.js\"\nimport { Subscription } "
},
{
"path": "src/controllers/tweet.controller.js",
"chars": 720,
"preview": "import mongoose, { isValidObjectId } from \"mongoose\"\nimport {Tweet} from \"../models/tweet.model.js\"\nimport {User} from \""
},
{
"path": "src/controllers/user.controller.js",
"chars": 12711,
"preview": "import { asyncHandler } from \"../utils/asyncHandler.js\";\nimport {ApiError} from \"../utils/ApiError.js\"\nimport { User} fr"
},
{
"path": "src/controllers/video.controller.js",
"chars": 1349,
"preview": "import mongoose, {isValidObjectId} from \"mongoose\"\nimport {Video} from \"../models/video.model.js\"\nimport {User} from \".."
},
{
"path": "src/db/index.js",
"chars": 451,
"preview": "import mongoose from \"mongoose\";\nimport { DB_NAME } from \"../constants.js\";\n\n\nconst connectDB = async () => {\n try {\n"
},
{
"path": "src/index.js",
"chars": 923,
"preview": "// require('dotenv').config({path: './env'})\nimport dotenv from \"dotenv\"\nimport connectDB from \"./db/index.js\";\nimport {"
},
{
"path": "src/middlewares/auth.middleware.js",
"chars": 940,
"preview": "import { ApiError } from \"../utils/ApiError.js\";\nimport { asyncHandler } from \"../utils/asyncHandler.js\";\nimport jwt fro"
},
{
"path": "src/middlewares/multer.middleware.js",
"chars": 294,
"preview": "import multer from \"multer\";\n\nconst storage = multer.diskStorage({\n destination: function (req, file, cb) {\n cb("
},
{
"path": "src/models/comment.model.js",
"chars": 585,
"preview": "import mongoose, {Schema} from \"mongoose\";\nimport mongooseAggregatePaginate from \"mongoose-aggregate-paginate-v2\";\n\ncons"
},
{
"path": "src/models/like.model.js",
"chars": 477,
"preview": "import mongoose, {Schema} from \"mongoose\";\n\n\nconst likeSchema = new Schema({\n video: {\n type: Schema.Types.Obj"
},
{
"path": "src/models/playlist.model.js",
"chars": 491,
"preview": "import mongoose, {Schema} from \"mongoose\";\n\nconst playlistSchema = new Schema({\n name: {\n type: String,\n "
},
{
"path": "src/models/subscription.model.js",
"chars": 416,
"preview": "import mongoose, {Schema} from \"mongoose\"\n\nconst subscriptionSchema = new Schema({\n subscriber: {\n type: Schem"
},
{
"path": "src/models/tweet.model.js",
"chars": 302,
"preview": "import mongoose, {Schema} from \"mongoose\";\n\nconst tweetSchema = new Schema({\n content: {\n type: String,\n "
},
{
"path": "src/models/user.model.js",
"chars": 2120,
"preview": "import mongoose, {Schema} from \"mongoose\";\nimport jwt from \"jsonwebtoken\"\nimport bcrypt from \"bcrypt\"\n\nconst userSchema "
},
{
"path": "src/models/video.model.js",
"chars": 1022,
"preview": "import mongoose, {Schema} from \"mongoose\";\nimport mongooseAggregatePaginate from \"mongoose-aggregate-paginate-v2\";\n\ncons"
},
{
"path": "src/routes/comment.routes.js",
"chars": 495,
"preview": "import { Router } from 'express';\nimport {\n addComment,\n deleteComment,\n getVideoComments,\n updateComment,\n}"
},
{
"path": "src/routes/dashboard.routes.js",
"chars": 416,
"preview": "import { Router } from 'express';\nimport {\n getChannelStats,\n getChannelVideos,\n} from \"../controllers/dashboard.c"
},
{
"path": "src/routes/healthcheck.routes.js",
"chars": 190,
"preview": "import { Router } from 'express';\nimport { healthcheck } from \"../controllers/healthcheck.controller.js\"\n\nconst router ="
},
{
"path": "src/routes/like.routes.js",
"chars": 583,
"preview": "import { Router } from 'express';\nimport {\n getLikedVideos,\n toggleCommentLike,\n toggleVideoLike,\n toggleTwe"
},
{
"path": "src/routes/playlist.routes.js",
"chars": 793,
"preview": "import { Router } from 'express';\nimport {\n addVideoToPlaylist,\n createPlaylist,\n deletePlaylist,\n getPlayli"
},
{
"path": "src/routes/subscription.routes.js",
"chars": 529,
"preview": "import { Router } from 'express';\nimport {\n getSubscribedChannels,\n getUserChannelSubscribers,\n toggleSubscript"
},
{
"path": "src/routes/tweet.routes.js",
"chars": 499,
"preview": "import { Router } from 'express';\nimport {\n createTweet,\n deleteTweet,\n getUserTweets,\n updateTweet,\n} from "
},
{
"path": "src/routes/user.routes.js",
"chars": 1421,
"preview": "import { Router } from \"express\";\nimport { \n loginUser, \n logoutUser, \n registerUser, \n refreshAccessToken, "
},
{
"path": "src/routes/video.routes.js",
"chars": 973,
"preview": "import { Router } from 'express';\nimport {\n deleteVideo,\n getAllVideos,\n getVideoById,\n publishAVideo,\n t"
},
{
"path": "src/utils/ApiError.js",
"chars": 497,
"preview": "class ApiError extends Error {\n constructor(\n statusCode,\n message= \"Something went wrong\",\n err"
},
{
"path": "src/utils/ApiResponse.js",
"chars": 240,
"preview": "class ApiResponse {\n constructor(statusCode, data, message = \"Success\"){\n this.statusCode = statusCode\n "
},
{
"path": "src/utils/asyncHandler.js",
"chars": 597,
"preview": "const asyncHandler = (requestHandler) => {\n return (req, res, next) => {\n Promise.resolve(requestHandler(req, "
},
{
"path": "src/utils/cloudinary.js",
"chars": 876,
"preview": "import {v2 as cloudinary} from \"cloudinary\"\nimport fs from \"fs\"\n\n\ncloudinary.config({ \n cloud_name: process.env.CLOUDIN"
}
]
About this extraction
This page contains the full source code of the hiteshchoudhary/chai-backend GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 41 files (40.6 KB), approximately 10.7k tokens, and a symbol index with 5 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.