Function bodies 143 total
AdminCodesPage function · typescript · L32-L367 (336 LOC)app/(admin)/admin/codes/page.tsx
export default function AdminCodesPage() {
const [codes, setCodes] = useState<AccessCode[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [showCreateModal, setShowCreateModal] = useState(false);
const [copiedCode, setCopiedCode] = useState<string | null>(null);
const [isCreating, setIsCreating] = useState(false);
const [newCode, setNewCode] = useState({
code: "",
type: "coins",
value: 100,
plan: "pro",
maxUses: 1,
expiresAt: "",
});
useEffect(() => {
fetchCodes();
}, [page]);
const fetchCodes = async () => {
setIsLoading(true);
const result = await adminApi.codes.list(page, 20);
if (result.success && result.data) {
const data = result.data as {
codes: AccessCode[];
pagination: { totalPages: number };
};
setCodes(data.codes);
setTotalPages(data.pagination.totalPages);
}
setIsAdminGenerationsPage function · typescript · L23-L198 (176 LOC)app/(admin)/admin/generations/page.tsx
export default function AdminGenerationsPage() {
const [generations, setGenerations] = useState<Generation[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [totals, setTotals] = useState({ total: 0, tokens: 0 });
const [typeFilter, setTypeFilter] = useState("");
useEffect(() => {
fetchGenerations();
}, [page, typeFilter]);
const fetchGenerations = async () => {
setIsLoading(true);
const result = await adminApi.generations.list(
page,
20,
typeFilter || undefined
);
if (result.success && result.data) {
const data = result.data as {
generations: Generation[];
pagination: { totalPages: number };
totals: { total: number; tokens: number };
};
setGenerations(data.generations);
setTotalPages(data.pagination.totalPages);
setTotals(data.totals);
}
setIsLoading(false);
};
reAdminOverviewPage function · typescript · L44-L251 (208 LOC)app/(admin)/admin/page.tsx
export default function AdminOverviewPage() {
const [stats, setStats] = useState<Stats | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetchStats();
}, []);
const fetchStats = async () => {
const result = await adminApi.stats();
if (result.success && result.data) {
setStats(result.data as Stats);
}
setIsLoading(false);
};
if (isLoading) {
return (
<div className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{[1, 2, 3, 4].map((i) => (
<div key={i} className="glass-card p-6 animate-pulse">
<div className="h-4 bg-white/10 rounded w-1/2 mb-2" />
<div className="h-8 bg-white/10 rounded w-1/3" />
</div>
))}
</div>
</div>
);
}
if (!stats) return null;
const statCards = [
{
label: "Total Users",
value: stats.users.total,
change: `+${stats.usersAdminUsersPage function · typescript · L30-L322 (293 LOC)app/(admin)/admin/users/page.tsx
export default function AdminUsersPage() {
const [users, setUsers] = useState<User[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [search, setSearch] = useState("");
const [planFilter, setPlanFilter] = useState("");
const [selectedUser, setSelectedUser] = useState<User | null>(null);
const [showEditModal, setShowEditModal] = useState(false);
const [editData, setEditData] = useState({ plan: "", coins: 0, role: "" });
const [isSaving, setIsSaving] = useState(false);
useEffect(() => {
fetchUsers();
}, [page, planFilter]);
const fetchUsers = async () => {
setIsLoading(true);
const result = await adminApi.users.list(page, 20, search, planFilter);
if (result.success && result.data) {
const data = result.data as {
users: User[];
pagination: { totalPages: number };
};
setUsers(data.users);
setTotalPages(data.pAdminLayout function · typescript · L30-L117 (88 LOC)app/(admin)/layout.tsx
export default function AdminLayout({
children,
}: {
children: React.ReactNode;
}) {
const router = useRouter();
const pathname = usePathname();
const { user, isLoading, isAdmin, logout } = useAuth();
useEffect(() => {
if (!isLoading && !isAdmin) {
router.push("/dashboard");
}
}, [isLoading, isAdmin, router]);
if (isLoading) {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-purple-500" />
</div>
);
}
if (!isAdmin) {
return null;
}
return (
<div className="min-h-screen flex font-body">
{/* Sidebar */}
<aside className="sidebar">
<Link href="/" className="block mb-2">
<Image
src="/logo.png"
alt="ThreadN"
width={140}
height={40}
className="h-9 w-auto"
/>
</Link>
<p className="text-xs text-yellow-400 mb-6 plGET function · typescript · L8-L121 (114 LOC)app/api/achievements/route.ts
export async function GET(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
// Get unlocked achievements
const unlockedAchievements = await UserAchievement.find({
userId: session.user.id,
}).lean();
const unlockedMap = new Map(
unlockedAchievements.map(a => [a.achievementId, a])
);
// Get user stats for progress calculation
const user = await User.findById(session.user.id);
if (!user) {
return NextResponse.json(
{ success: false, error: "User not found" },
{ status: 404 }
);
}
// Get streak info
const streak = await UserStreak.findOne({ userId: session.user.id });
// Get counts for various achievements
const [templateCount, collectionCount, scheduledCount] = await Promise.all([
TemplaPATCH function · typescript · L13-L72 (60 LOC)app/api/admin/codes/[id]/route.ts
export async function PATCH(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
await requireAdmin();
await dbConnect();
const { id } = await params;
const body = await request.json();
const validation = UpdateCodeSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const updates: Record<string, unknown> = {};
const data = validation.data;
if (data.isActive !== undefined) updates.isActive = data.isActive;
if (data.maxUses !== undefined) updates.maxUses = data.maxUses;
if (data.expiresAt !== undefined) {
updates.expiresAt = data.expiresAt ? new Date(data.expiresAt) : null;
}
const code = await AccessCode.findByIdAndUpdate(
id,
{ $set: updates },
{ new: true }
).lean();
if (!code) {
return NextResponse.json(
{ sucRepobility · open methodology · https://repobility.com/research/
DELETE function · typescript · L74-L109 (36 LOC)app/api/admin/codes/[id]/route.ts
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
await requireAdmin();
await dbConnect();
const { id } = await params;
const code = await AccessCode.findByIdAndDelete(id);
if (!code) {
return NextResponse.json(
{ success: false, error: "Code not found" },
{ status: 404 }
);
}
return NextResponse.json({
success: true,
message: "Code deleted successfully",
});
} catch (error) {
console.error("Admin delete code error:", error);
if ((error as Error).message === "Forbidden") {
return NextResponse.json(
{ success: false, error: "Admin access required" },
{ status: 403 }
);
}
return NextResponse.json(
{ success: false, error: "Failed to delete code" },
{ status: 500 }
);
}
}GET function · typescript · L17-L76 (60 LOC)app/api/admin/codes/route.ts
export async function GET(request: NextRequest) {
try {
await requireAdmin();
await dbConnect();
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get("page") || "1");
const limit = parseInt(searchParams.get("limit") || "20");
const type = searchParams.get("type") || "";
const active = searchParams.get("active");
const skip = (page - 1) * limit;
// Build query
const query: Record<string, unknown> = {};
if (type) {
query.type = type;
}
if (active !== null) {
query.isActive = active === "true";
}
// Get codes
const [codes, total] = await Promise.all([
AccessCode.find(query)
.sort({ createdAt: -1 })
.skip(skip)
.limit(limit)
.lean(),
AccessCode.countDocuments(query),
]);
return NextResponse.json({
success: true,
data: {
codes,
pagination: {
page,
limit,
total,
POST function · typescript · L78-L136 (59 LOC)app/api/admin/codes/route.ts
export async function POST(request: NextRequest) {
try {
const session = await requireAdmin();
await dbConnect();
const body = await request.json();
const validation = CreateCodeSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const data = validation.data;
// Generate code if not provided
const codeString = data.code || generateCode();
// Check if code exists
const existing = await AccessCode.findOne({ code: codeString.toUpperCase() });
if (existing) {
return NextResponse.json(
{ success: false, error: "Code already exists" },
{ status: 400 }
);
}
// Create code
const code = await AccessCode.create({
code: codeString.toUpperCase(),
type: data.type,
value: data.value,
plan: data.plan,
maxUses: data.maxUses,
expiresAt: dGET function · typescript · L7-L91 (85 LOC)app/api/admin/generations/route.ts
export async function GET(request: NextRequest) {
try {
await requireAdmin();
await dbConnect();
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get("page") || "1");
const limit = parseInt(searchParams.get("limit") || "20");
const type = searchParams.get("type") || "";
const userId = searchParams.get("userId") || "";
const skip = (page - 1) * limit;
// Build query
const query: Record<string, unknown> = {};
if (type) {
query.type = type;
}
if (userId) {
query.userId = userId;
}
// Get generations with user info
const [generations, total] = await Promise.all([
Generation.find(query)
.sort({ createdAt: -1 })
.skip(skip)
.limit(limit)
.lean(),
Generation.countDocuments(query),
]);
// Get user info for each generation
const userIds = [...new Set(generations.map((g) => g.userId))];
const users = await User.find({ _iGET function · typescript · L54-L117 (64 LOC)app/api/admin/settings/route.ts
export async function GET() {
try {
await requireAdmin();
await dbConnect();
// Get all settings from database
const dbSettings = await Setting.find().lean();
// Merge with defaults
const settings = { ...DEFAULT_SETTINGS };
for (const setting of dbSettings) {
if (setting.key in settings) {
(settings as Record<string, unknown>)[setting.key] = setting.value;
}
}
return NextResponse.json({
success: true,
data: {
settings,
categories: {
pricing: ["pricing_free", "pricing_starter", "pricing_pro", "pricing_enterprise"],
limits: [
"limits_free_daily_threads",
"limits_starter_daily_threads",
"limits_pro_daily_threads",
"limits_enterprise_daily_threads",
],
costs: [
"cost_free_daily", "cost_free_monthly",
"cost_starter_daily", "cost_starter_monthly",
"cost_pro_daily", "cost_pro_monthlyPATCH function · typescript · L119-L180 (62 LOC)app/api/admin/settings/route.ts
export async function PATCH(request: NextRequest) {
try {
const session = await requireAdmin();
await dbConnect();
const updates = await request.json();
// Validate keys
const validKeys = Object.keys(DEFAULT_SETTINGS);
const invalidKeys = Object.keys(updates).filter((key) => !validKeys.includes(key));
if (invalidKeys.length > 0) {
return NextResponse.json(
{ success: false, error: `Invalid settings: ${invalidKeys.join(", ")}` },
{ status: 400 }
);
}
// Update each setting
const bulkOps = Object.entries(updates).map(([key, value]) => ({
updateOne: {
filter: { key },
update: {
$set: {
key,
value,
category: key.split("_")[0],
updatedBy: session.user?.id,
updatedAt: new Date(),
},
},
upsert: true,
},
}));
await Setting.bulkWrite(bulkOps);
// Get updated settings
const dbSettingGET function · typescript · L8-L246 (239 LOC)app/api/admin/stats/route.ts
export async function GET(request: NextRequest) {
try {
await requireAdmin();
await dbConnect();
const { searchParams } = new URL(request.url);
const includeCharts = searchParams.get("charts") === "true";
// Get date ranges
const now = new Date();
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const thisMonth = new Date(now.getFullYear(), now.getMonth(), 1);
const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
const last7Days = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
const last30Days = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
// Parallel queries for stats
const [
totalUsers,
newUsersToday,
newUsersMonth,
newUsersLastMonth,
totalGenerations,
generationsToday,
generationsMonth,
generationsLastMonth,
totalCodes,
activeSubscriptions,
activeCodes,
planDistribution,
recentGenerations,
recGET function · typescript · L15-L50 (36 LOC)app/api/admin/users/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
await requireAdmin();
await dbConnect();
const { id } = await params;
const user = await User.findById(id).lean();
if (!user) {
return NextResponse.json(
{ success: false, error: "User not found" },
{ status: 404 }
);
}
return NextResponse.json({
success: true,
data: { user },
});
} catch (error) {
console.error("Admin get user error:", error);
if ((error as Error).message === "Forbidden") {
return NextResponse.json(
{ success: false, error: "Admin access required" },
{ status: 403 }
);
}
return NextResponse.json(
{ success: false, error: "Failed to fetch user" },
{ status: 500 }
);
}
}Repobility (the analyzer behind this table) · https://repobility.com
PATCH function · typescript · L52-L113 (62 LOC)app/api/admin/users/[id]/route.ts
export async function PATCH(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
await requireAdmin();
await dbConnect();
const { id } = await params;
const body = await request.json();
const validation = UpdateUserSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const updates: Record<string, unknown> = {};
const data = validation.data;
if (data.name) updates.name = data.name;
if (data.role) updates.role = data.role;
if (data.plan) updates.plan = data.plan;
if (data.coins !== undefined) updates.coins = data.coins;
if (data.subscriptionStatus) {
updates["subscription.status"] = data.subscriptionStatus;
}
const user = await User.findByIdAndUpdate(
id,
{ $set: updates },
{ new: true }
).lean();
if (!user) {
retuDELETE function · typescript · L115-L150 (36 LOC)app/api/admin/users/[id]/route.ts
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
await requireAdmin();
await dbConnect();
const { id } = await params;
const user = await User.findByIdAndDelete(id);
if (!user) {
return NextResponse.json(
{ success: false, error: "User not found" },
{ status: 404 }
);
}
return NextResponse.json({
success: true,
message: "User deleted successfully",
});
} catch (error) {
console.error("Admin delete user error:", error);
if ((error as Error).message === "Forbidden") {
return NextResponse.json(
{ success: false, error: "Admin access required" },
{ status: 403 }
);
}
return NextResponse.json(
{ success: false, error: "Failed to delete user" },
{ status: 500 }
);
}
}GET function · typescript · L6-L79 (74 LOC)app/api/admin/users/route.ts
export async function GET(request: NextRequest) {
try {
await requireAdmin();
await dbConnect();
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get("page") || "1");
const limit = parseInt(searchParams.get("limit") || "20");
const search = searchParams.get("search") || "";
const plan = searchParams.get("plan") || "";
const role = searchParams.get("role") || "";
const skip = (page - 1) * limit;
// Build query
const query: Record<string, unknown> = {};
if (search) {
query.$or = [
{ email: { $regex: search, $options: "i" } },
{ name: { $regex: search, $options: "i" } },
];
}
if (plan) {
query.plan = plan;
}
if (role) {
query.role = role;
}
// Get users
const [users, total] = await Promise.all([
User.find(query)
.sort({ createdAt: -1 })
.skip(skip)
.limit(limit)
.lean(),
User.countDocumentsGET function · typescript · L7-L55 (49 LOC)app/api/auth/me/route.ts
export async function GET() {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Not authenticated" },
{ status: 401 }
);
}
await dbConnect();
const user = await User.findById(session.user.id).lean<IUser>();
if (!user) {
return NextResponse.json(
{ success: false, error: "User not found" },
{ status: 404 }
);
}
// Return user data directly (no save needed here)
const publicUser = {
id: user._id.toString(),
email: user.email,
name: user.name,
image: user.image,
role: user.role,
plan: user.plan,
coins: user.coins,
subscription: user.subscription,
usage: user.usage,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
};
return NextResponse.json({
success: true,
data: { user: publicUser },
});
} catch (error) {
console.error("Get me POST function · typescript · L14-L86 (73 LOC)app/api/auth/register/route.ts
export async function POST(request: NextRequest) {
try {
// Rate limiting for auth endpoints (prevent brute force)
const clientIp = getClientIp(request.headers);
const rateLimit = withRateLimit(clientIp, "auth", RATE_LIMIT_CONFIGS.auth);
if (!rateLimit.allowed) {
return NextResponse.json(
{
success: false,
error: `Too many attempts. Please try again in ${Math.ceil((rateLimit.retryAfter || 0) / 60)} minutes.`,
code: "RATE_LIMITED"
},
{
status: 429,
headers: rateLimit.headers
}
);
}
await dbConnect();
const body = await request.json();
const validation = RegisterSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const { email, password, name } = validation.data;
// Check if user exists
const existingUPOST function · typescript · L12-L127 (116 LOC)app/api/codes/redeem/route.ts
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const body = await request.json();
const validation = RedeemSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const { code } = validation.data;
// Find code
const accessCode = await AccessCode.findOne({
code: code.toUpperCase().trim(),
});
if (!accessCode) {
return NextResponse.json(
{ success: false, error: "Invalid code" },
{ status: 404 }
);
}
// Check if code is valid
const validity = accessCode.isValid(session.user.id);
if (!validity.valid) {
return NextResponse.json(
GET function · typescript · L15-L65 (51 LOC)app/api/collections/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const collection = await Collection.findOne({
_id: id,
userId: session.user.id,
});
if (!collection) {
return NextResponse.json(
{ success: false, error: "Collection not found" },
{ status: 404 }
);
}
// Get favorite count
const favoriteCount = await Favorite.countDocuments({
userId: session.user.id,
collectionId: id,
});
return NextResponse.json({
success: true,
data: {
collection: {
...collection.toObject(),
favoriteCount,
},
},
});
} catch (error) {
console.error("Get collPATCH function · typescript · L68-L143 (76 LOC)app/api/collections/[id]/route.ts
export async function PATCH(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const body = await request.json();
const validation = UpdateCollectionSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const collection = await Collection.findOne({
_id: id,
userId: session.user.id,
});
if (!collection) {
return NextResponse.json(
{ success: false, error: "Collection not found" },
{ status: 404 }
);
}
const { name, description, color, icon } = validation.data;
// Check for duplicate nAll rows above produced by Repobility · https://repobility.com
DELETE function · typescript · L146-L191 (46 LOC)app/api/collections/[id]/route.ts
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const collection = await Collection.findOneAndDelete({
_id: id,
userId: session.user.id,
});
if (!collection) {
return NextResponse.json(
{ success: false, error: "Collection not found" },
{ status: 404 }
);
}
// Move favorites from this collection to uncategorized
await Favorite.updateMany(
{ userId: session.user.id, collectionId: id },
{ collectionId: null }
);
return NextResponse.json({
success: true,
message: "Collection deleted",
});
} catch (error) {
console.error("Delete collection error:", error);
retuGET function · typescript · L16-L76 (61 LOC)app/api/collections/route.ts
export async function GET(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const collections = await Collection.find({ userId: session.user.id })
.sort({ name: 1 })
.lean();
// Get favorite counts for each collection
const collectionIds = collections.map(c => c._id.toString());
const favoriteCounts = await Favorite.aggregate([
{
$match: {
userId: session.user.id,
collectionId: { $in: collectionIds },
},
},
{
$group: {
_id: "$collectionId",
count: { $sum: 1 },
},
},
]);
const countMap = new Map(favoriteCounts.map(c => [c._id, c.count]));
// Get uncategorized count
const uncategorizedCount = await Favorite.countDocuments({
userId: session.POST function · typescript · L79-L139 (61 LOC)app/api/collections/route.ts
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const body = await request.json();
const validation = CreateCollectionSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const { name, description, color, icon } = validation.data;
// Check for duplicate name
const existing = await Collection.findOne({
userId: session.user.id,
name: { $regex: new RegExp(`^${name}$`, "i") },
});
if (existing) {
return NextResponse.json(
{ success: false, error: "Collection with this name already exists" },
{ status: 400 }
);
}
const collection = await CoPATCH function · typescript · L14-L72 (59 LOC)app/api/favorites/[id]/route.ts
export async function PATCH(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const body = await request.json();
const validation = UpdateFavoriteSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const favorite = await Favorite.findOne({
_id: id,
userId: session.user.id,
});
if (!favorite) {
return NextResponse.json(
{ success: false, error: "Favorite not found" },
{ status: 404 }
);
}
const { collectionId, notes, tags } = validation.data;
if (collectionId !== undefined) favoritDELETE function · typescript · L75-L114 (40 LOC)app/api/favorites/[id]/route.ts
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const favorite = await Favorite.findOneAndDelete({
_id: id,
userId: session.user.id,
});
if (!favorite) {
return NextResponse.json(
{ success: false, error: "Favorite not found" },
{ status: 404 }
);
}
return NextResponse.json({
success: true,
message: "Removed from favorites",
});
} catch (error) {
console.error("Delete favorite error:", error);
return NextResponse.json(
{ success: false, error: "Failed to remove from favorites" },
{ status: 500 }
);
}
}GET function · typescript · L16-L78 (63 LOC)app/api/favorites/route.ts
export async function GET(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { searchParams } = new URL(request.url);
const collectionId = searchParams.get("collectionId");
const tag = searchParams.get("tag");
// Build query
const query: Record<string, unknown> = { userId: session.user.id };
if (collectionId) {
query.collectionId = collectionId === "uncategorized" ? null : collectionId;
}
if (tag) {
query.tags = tag;
}
const favorites = await Favorite.find(query)
.sort({ createdAt: -1 })
.limit(100)
.lean();
// Get generation details for each favorite
// Convert string IDs to ObjectIds for the query
const generationIds = favorites
.map(f => f.generationId)
.filter(id => mongoose.TypPOST function · typescript · L81-L151 (71 LOC)app/api/favorites/route.ts
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const body = await request.json();
const validation = CreateFavoriteSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const { generationId, collectionId, notes, tags } = validation.data;
// Verify generation exists and belongs to user
const generation = await Generation.findOne({
_id: generationId,
userId: session.user.id,
});
if (!generation) {
return NextResponse.json(
{ success: false, error: "Generation not found" },
{ status: 404 }
);
}
// Check if already favorited
const exisPOST function · typescript · L23-L271 (249 LOC)app/api/generate/route.ts
export async function POST(request: NextRequest) {
try {
// Rate limiting check
const clientIp = getClientIp(request.headers);
const rateLimit = withRateLimit(clientIp, "generate", RATE_LIMIT_CONFIGS.generation);
if (!rateLimit.allowed) {
return NextResponse.json(
{
success: false,
error: `Too many requests. Please try again in ${rateLimit.retryAfter} seconds.`,
code: "RATE_LIMITED"
},
{
status: 429,
headers: rateLimit.headers
}
);
}
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const body = await request.json();
const validation = GenerateSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].meRepobility · code-quality intelligence platform · https://repobility.com
POST function · typescript · L13-L56 (44 LOC)app/api/generate/variations/route.ts
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
const body = await request.json();
const validation = VariationsSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const { transcript, originalHook, count } = validation.data;
// Generate A/B variations
const result = await generateABHookVariations(transcript, originalHook, count);
// Check for A/B tester achievement
await checkAndUnlockAchievement(session.user.id, "ab_tester");
return NextResponse.json({
success: true,
data: {
variations: result.variations,
tokens: result.tokens,
},
});
} catch (error) {
conPOST function · typescript · L7-L78 (72 LOC)app/api/scheduler/[id]/publish/route.ts
export async function POST(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const post = await ScheduledPost.findOne({
_id: id,
userId: session.user.id,
});
if (!post) {
return NextResponse.json(
{ success: false, error: "Scheduled post not found" },
{ status: 404 }
);
}
if (post.status === "published") {
return NextResponse.json(
{ success: false, error: "Post has already been published" },
{ status: 400 }
);
}
// Mark as published
// Note: Actual publishing to platforms would require platform API integrations
post.status = "published";
post.publishedAt = new Date();
await post.save(GET function · typescript · L18-L57 (40 LOC)app/api/scheduler/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const post = await ScheduledPost.findOne({
_id: id,
userId: session.user.id,
});
if (!post) {
return NextResponse.json(
{ success: false, error: "Scheduled post not found" },
{ status: 404 }
);
}
return NextResponse.json({
success: true,
data: { post },
});
} catch (error) {
console.error("Get scheduled post error:", error);
return NextResponse.json(
{ success: false, error: "Failed to fetch scheduled post" },
{ status: 500 }
);
}
}PATCH function · typescript · L60-L134 (75 LOC)app/api/scheduler/[id]/route.ts
export async function PATCH(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const body = await request.json();
const validation = UpdateScheduledPostSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const post = await ScheduledPost.findOne({
_id: id,
userId: session.user.id,
});
if (!post) {
return NextResponse.json(
{ success: false, error: "Scheduled post not found" },
{ status: 404 }
);
}
// Only allow updates to pending posts
if (post.status !== "pending") {
return NeDELETE function · typescript · L137-L176 (40 LOC)app/api/scheduler/[id]/route.ts
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const post = await ScheduledPost.findOneAndDelete({
_id: id,
userId: session.user.id,
});
if (!post) {
return NextResponse.json(
{ success: false, error: "Scheduled post not found" },
{ status: 404 }
);
}
return NextResponse.json({
success: true,
message: "Scheduled post deleted",
});
} catch (error) {
console.error("Delete scheduled post error:", error);
return NextResponse.json(
{ success: false, error: "Failed to delete scheduled post" },
{ status: 500 }
);
}
}GET function · typescript · L19-L69 (51 LOC)app/api/scheduler/route.ts
export async function GET(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { searchParams } = new URL(request.url);
const status = searchParams.get("status");
const startDate = searchParams.get("startDate");
const endDate = searchParams.get("endDate");
// Build query
const query: Record<string, unknown> = { userId: session.user.id };
if (status) {
query.status = status;
}
if (startDate || endDate) {
query.scheduledAt = {};
if (startDate) {
(query.scheduledAt as Record<string, Date>).$gte = new Date(startDate);
}
if (endDate) {
(query.scheduledAt as Record<string, Date>).$lte = new Date(endDate);
}
}
const posts = await ScheduledPost.find(query)
.sort({ scheduledAt: 1 })
POST function · typescript · L72-L127 (56 LOC)app/api/scheduler/route.ts
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const body = await request.json();
const validation = CreateScheduledPostSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const { content, scheduledAt, recurrence } = validation.data;
// Validate scheduled time is in the future
if (scheduledAt <= new Date()) {
return NextResponse.json(
{ success: false, error: "Scheduled time must be in the future" },
{ status: 400 }
);
}
const post = await ScheduledPost.create({
userId: session.user.id,
content,
scheduledAt,
recurrence,
statGET function · typescript · L6-L46 (41 LOC)app/api/share/[id]/image/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params;
await dbConnect();
const sharedCard = await SharedCard.findOne({ uniqueId: id }).select("imageData");
if (!sharedCard || !sharedCard.imageData) {
return NextResponse.json(
{ success: false, error: "Image not found" },
{ status: 404 }
);
}
// Extract base64 data (remove data:image/png;base64, prefix)
const base64Data = sharedCard.imageData.replace(/^data:image\/\w+;base64,/, "");
const imageBuffer = Buffer.from(base64Data, "base64");
// Determine content type from the data URL
const contentType = sharedCard.imageData.startsWith("data:image/jpeg")
? "image/jpeg"
: "image/png";
return new NextResponse(imageBuffer, {
headers: {
"Content-Type": contentType,
"Cache-Control": "public, max-age=31536000, immutable",
},
});
} catch (eRepobility · open methodology · https://repobility.com/research/
GET function · typescript · L16-L62 (47 LOC)app/api/share/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params;
await dbConnect();
const sharedCard = await SharedCard.findOne({ uniqueId: id });
if (!sharedCard) {
return NextResponse.json(
{ success: false, error: "Shared card not found" },
{ status: 404 }
);
}
// Increment view count
await SharedCard.updateOne(
{ uniqueId: id },
{ $inc: { views: 1 } }
);
return NextResponse.json({
success: true,
data: {
card: {
uniqueId: sharedCard.uniqueId,
imageData: sharedCard.imageData,
title: sharedCard.title,
description: sharedCard.description,
threadBody: sharedCard.threadBody || "",
templateName: sharedCard.templateName,
views: sharedCard.views + 1,
createdAt: sharedCard.createdAt,
},
},
});
} catch (error) {
conPUT function · typescript · L65-L131 (67 LOC)app/api/share/[id]/route.ts
export async function PUT(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
const { id } = await params;
await dbConnect();
// Find the shared card
const sharedCard = await SharedCard.findOne({ uniqueId: id });
if (!sharedCard) {
return NextResponse.json(
{ success: false, error: "Shared card not found" },
{ status: 404 }
);
}
// Check if user owns this share (if they were logged in when creating)
if (sharedCard.userId && session?.user?.id !== sharedCard.userId) {
return NextResponse.json(
{ success: false, error: "You don't have permission to update this share" },
{ status: 403 }
);
}
const body = await request.json();
const validation = UpdateShareSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
POST function · typescript · L17-L75 (59 LOC)app/api/share/route.ts
export async function POST(request: NextRequest) {
try {
const session = await auth();
// Allow sharing without login, but track userId if logged in
const userId = session?.user?.id || null;
await dbConnect();
const body = await request.json();
const validation = CreateShareSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const { imageData, title, description, threadBody, templateName } = validation.data;
// Generate unique ID for the share link
const uniqueId = nanoid(10);
const sharedCard = await SharedCard.create({
uniqueId,
userId,
imageData,
title,
description,
threadBody,
templateName,
views: 0,
});
const shareUrl = `${process.env.NEXT_PUBLIC_APP_URL || "https://threadn.launchory.org"}/share/${uniqueId}`;
return NextResponse.jGET function · typescript · L78-L124 (47 LOC)app/api/share/route.ts
export async function GET(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to view your shared cards" },
{ status: 401 }
);
}
await dbConnect();
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get("page") || "1");
const limit = parseInt(searchParams.get("limit") || "10");
const skip = (page - 1) * limit;
const [sharedCards, total] = await Promise.all([
SharedCard.find({ userId: session.user.id })
.select("-imageData") // Don't send large image data in list
.sort({ createdAt: -1 })
.skip(skip)
.limit(limit)
.lean(),
SharedCard.countDocuments({ userId: session.user.id }),
]);
return NextResponse.json({
success: true,
data: {
sharedCards,
pagination: {
page,
limit,
totalGET function · typescript · L7-L67 (61 LOC)app/api/streak/route.ts
export async function GET(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
let streak = await UserStreak.findOne({ userId: session.user.id });
// Create streak record if doesn't exist
if (!streak) {
streak = await UserStreak.create({
userId: session.user.id,
currentStreak: 0,
longestStreak: 0,
lastActivityDate: null,
totalDaysActive: 0,
});
}
// Check if streak is broken (more than 24 hours since last activity)
let isActive = false;
if (streak.lastActivityDate) {
const now = new Date();
const lastActivity = new Date(streak.lastActivityDate);
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const lastActivityDay = new Date(lastActivity.getFullYear(), lastAGET function · typescript · L24-L66 (43 LOC)app/api/templates/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const template = await Template.findOne({
_id: id,
$or: [
{ userId: session.user.id },
{ isPublic: true },
],
});
if (!template) {
return NextResponse.json(
{ success: false, error: "Template not found" },
{ status: 404 }
);
}
return NextResponse.json({
success: true,
data: { template },
});
} catch (error) {
console.error("Get template error:", error);
return NextResponse.json(
{ success: false, error: "Failed to fetch template" },
{ status: 500 }
);
}
}PATCH function · typescript · L69-L134 (66 LOC)app/api/templates/[id]/route.ts
export async function PATCH(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const body = await request.json();
const validation = UpdateTemplateSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
// Only owner can update
const template = await Template.findOne({
_id: id,
userId: session.user.id,
});
if (!template) {
return NextResponse.json(
{ success: false, error: "Template not found or you don't have permission to edit it" },
{ status: 404 }
);
}
const { name, description, catDELETE function · typescript · L137-L177 (41 LOC)app/api/templates/[id]/route.ts
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
// Only owner can delete
const template = await Template.findOneAndDelete({
_id: id,
userId: session.user.id,
});
if (!template) {
return NextResponse.json(
{ success: false, error: "Template not found or you don't have permission to delete it" },
{ status: 404 }
);
}
return NextResponse.json({
success: true,
message: "Template deleted",
});
} catch (error) {
console.error("Delete template error:", error);
return NextResponse.json(
{ success: false, error: "Failed to delete template" },
{ status: 500 }
);
}
}Repobility (the analyzer behind this table) · https://repobility.com
POST function · typescript · L13-L79 (67 LOC)app/api/templates/[id]/use/route.ts
export async function POST(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { id } = await params;
const body = await request.json();
const validation = UseTemplateSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const { variables } = validation.data;
// Find template (user's own or public)
const template = await Template.findOne({
_id: id,
$or: [
{ userId: session.user.id },
{ isPublic: true },
],
});
if (!template) {
return NextResponse.json(
{ success: false, error: "Template not found" },
GET function · typescript · L25-L76 (52 LOC)app/api/templates/route.ts
export async function GET(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const { searchParams } = new URL(request.url);
const category = searchParams.get("category");
const type = searchParams.get("type"); // "my" | "public" | "all"
// Build query for user's templates and public templates
let query: Record<string, unknown> = {};
if (type === "my") {
query.userId = session.user.id;
} else if (type === "public") {
query.isPublic = true;
} else {
// Default: user's templates + public templates
query.$or = [
{ userId: session.user.id },
{ isPublic: true },
];
}
if (category) {
query.category = category;
}
const templates = await Template.find(query)
.sort({ usageCount: -1, creaPOST function · typescript · L79-L141 (63 LOC)app/api/templates/route.ts
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: "Please login to continue" },
{ status: 401 }
);
}
await dbConnect();
const body = await request.json();
const validation = CreateTemplateSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
{ success: false, error: validation.error.errors[0].message },
{ status: 400 }
);
}
const { name, description, category, content, isPublic } = validation.data;
// Check for duplicate name for this user
const existing = await Template.findOne({
userId: session.user.id,
name: { $regex: new RegExp(`^${name}$`, "i") },
});
if (existing) {
return NextResponse.json(
{ success: false, error: "You already have a template with this name" },
{ status: 400 }
);
}
page 1 / 3next ›