chore: remediate pygienium audit findings
Dead code: 77 verified-unused exports, files (BackArrow, MenuBars, cookies.ts, db/create.ts, schemas/comment.ts, security-headers.ts) and 12 unused dependencies removed Comments: ~370 RESTATE comments stripped across 53 files; 2 verbose blocks tightened; dead commented-out config removed Complexity: bulkUpsert extracted into 11 per-entity helpers (CCN 156->~10); login formHandler split into 3 submitters (CCN 63->~5); account page render split into 8 section components (CCN 40); updatePost SQL builder rebuilt; assert*Owned consolidated behind generic assertOwnedBy Defensive guards: 4 redundant rethrow/nullish guards removed
This commit is contained in:
@@ -6,105 +6,6 @@ import { z } from "zod";
|
||||
* Schemas for post creation, updating, querying, and interactions
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// Post Category and Status
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Post category enum (deprecated but kept for backward compatibility)
|
||||
*/
|
||||
export const postCategorySchema = z.enum(["blog", "project"]);
|
||||
|
||||
// ============================================================================
|
||||
// Post Creation and Updates
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Create new post schema
|
||||
*/
|
||||
export const createPostSchema = z.object({
|
||||
title: z
|
||||
.string()
|
||||
.min(1, "Title is required")
|
||||
.max(200, "Title must be under 200 characters"),
|
||||
subtitle: z
|
||||
.string()
|
||||
.max(300, "Subtitle must be under 300 characters")
|
||||
.optional(),
|
||||
body: z.string().min(1, "Post body is required"),
|
||||
banner_photo: z.string().url("Must be a valid URL").optional(),
|
||||
published: z.boolean().default(false),
|
||||
category: postCategorySchema.default("blog"),
|
||||
attachments: z.string().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* Update post schema (partial updates)
|
||||
*/
|
||||
export const updatePostSchema = z.object({
|
||||
postId: z.number(),
|
||||
title: z.string().min(1).max(200).optional(),
|
||||
subtitle: z.string().max(300).optional(),
|
||||
body: z.string().min(1).optional(),
|
||||
banner_photo: z.string().url().optional(),
|
||||
published: z.boolean().optional(),
|
||||
attachments: z.string().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* Delete post schema
|
||||
*/
|
||||
export const deletePostSchema = z.object({
|
||||
postId: z.number()
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Post Queries and Filtering
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Post sort mode enum
|
||||
* Defines available sorting options for blog posts
|
||||
*/
|
||||
export const postSortModeSchema = z.enum([
|
||||
"newest",
|
||||
"oldest",
|
||||
"most_liked",
|
||||
"most_read",
|
||||
"most_comments"
|
||||
]);
|
||||
|
||||
/**
|
||||
* Post query input schema
|
||||
* Accepts optional filters (pipe-separated tags) and sort mode
|
||||
*/
|
||||
export const postQueryInputSchema = z.object({
|
||||
/**
|
||||
* Pipe-separated list of tags to filter by
|
||||
* e.g., "tech|design|javascript"
|
||||
* Empty string or undefined means no filter
|
||||
*/
|
||||
filters: z.string().optional(),
|
||||
|
||||
/**
|
||||
* Sort mode for posts
|
||||
* Defaults to "newest" if not specified
|
||||
*/
|
||||
sortBy: postSortModeSchema.default("newest")
|
||||
});
|
||||
|
||||
/**
|
||||
* Get single post by ID or slug
|
||||
*/
|
||||
export const getPostSchema = z
|
||||
.object({
|
||||
postId: z.number().optional(),
|
||||
slug: z.string().optional()
|
||||
})
|
||||
.refine((data) => data.postId || data.slug, {
|
||||
message: "Either postId or slug must be provided"
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Post Interactions
|
||||
// ============================================================================
|
||||
@@ -116,55 +17,8 @@ export const incrementPostReadSchema = z.object({
|
||||
postId: z.number()
|
||||
});
|
||||
|
||||
/**
|
||||
* Like/unlike post
|
||||
*/
|
||||
export const togglePostLikeSchema = z.object({
|
||||
postId: z.number()
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Tag Management
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Add tags to post
|
||||
*/
|
||||
export const addTagsToPostSchema = z.object({
|
||||
postId: z.number(),
|
||||
tags: z
|
||||
.array(z.string().min(1).max(50))
|
||||
.min(1, "At least one tag is required")
|
||||
});
|
||||
|
||||
/**
|
||||
* Remove tag from post
|
||||
*/
|
||||
export const removeTagFromPostSchema = z.object({
|
||||
tagId: z.number()
|
||||
});
|
||||
|
||||
/**
|
||||
* Update post tags (replaces all tags)
|
||||
*/
|
||||
export const updatePostTagsSchema = z.object({
|
||||
postId: z.number(),
|
||||
tags: z.array(z.string().min(1).max(50))
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Type Exports
|
||||
// ============================================================================
|
||||
|
||||
export type PostCategory = z.infer<typeof postCategorySchema>;
|
||||
export type CreatePostInput = z.infer<typeof createPostSchema>;
|
||||
export type UpdatePostInput = z.infer<typeof updatePostSchema>;
|
||||
export type DeletePostInput = z.infer<typeof deletePostSchema>;
|
||||
export type PostSortMode = z.infer<typeof postSortModeSchema>;
|
||||
export type PostQueryInput = z.infer<typeof postQueryInputSchema>;
|
||||
export type GetPostInput = z.infer<typeof getPostSchema>;
|
||||
export type IncrementPostReadInput = z.infer<typeof incrementPostReadSchema>;
|
||||
export type TogglePostLikeInput = z.infer<typeof togglePostLikeSchema>;
|
||||
export type AddTagsToPostInput = z.infer<typeof addTagsToPostSchema>;
|
||||
export type RemoveTagFromPostInput = z.infer<typeof removeTagFromPostSchema>;
|
||||
export type UpdatePostTagsInput = z.infer<typeof updatePostTagsSchema>;
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
/**
|
||||
* Comment API Validation Schemas
|
||||
*
|
||||
* Zod schemas for comment-related tRPC procedures:
|
||||
* - Comment creation, updating, deletion
|
||||
* - Comment reactions
|
||||
* - Comment sorting and filtering
|
||||
*/
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
// ============================================================================
|
||||
// Comment CRUD Operations
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Create new comment schema
|
||||
*/
|
||||
export const createCommentSchema = z.object({
|
||||
body: z
|
||||
.string()
|
||||
.min(1, "Comment cannot be empty")
|
||||
.max(5000, "Comment too long"),
|
||||
post_id: z.number(),
|
||||
parent_comment_id: z.number().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* Update comment schema
|
||||
*/
|
||||
export const updateCommentSchema = z.object({
|
||||
commentId: z.number(),
|
||||
body: z
|
||||
.string()
|
||||
.min(1, "Comment cannot be empty")
|
||||
.max(5000, "Comment too long")
|
||||
});
|
||||
|
||||
/**
|
||||
* Delete comment schema
|
||||
*/
|
||||
export const deleteCommentSchema = z.object({
|
||||
commentId: z.number(),
|
||||
deletionType: z.enum(["user", "admin", "database"]).optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* Get comments for post schema
|
||||
*/
|
||||
export const getCommentsSchema = z.object({
|
||||
postId: z.number(),
|
||||
sortBy: z.enum(["newest", "oldest", "highest_rated", "hot"]).default("newest")
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Comment Reactions
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Valid reaction types
|
||||
*/
|
||||
export const reactionTypeSchema = z.enum([
|
||||
"tears",
|
||||
"blank",
|
||||
"tongue",
|
||||
"cry",
|
||||
"heartEye",
|
||||
"angry",
|
||||
"moneyEye",
|
||||
"sick",
|
||||
"upsideDown",
|
||||
"worried"
|
||||
]);
|
||||
|
||||
/**
|
||||
* Add/remove reaction to comment
|
||||
*/
|
||||
export const toggleCommentReactionSchema = z.object({
|
||||
commentId: z.number(),
|
||||
reactionType: reactionTypeSchema
|
||||
});
|
||||
|
||||
/**
|
||||
* Get reactions for comment
|
||||
*/
|
||||
export const getCommentReactionsSchema = z.object({
|
||||
commentId: z.number()
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Comment Sorting
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Valid comment sorting modes
|
||||
*/
|
||||
export const commentSortSchema = z
|
||||
.enum(["newest", "oldest", "highest_rated", "hot"])
|
||||
.default("newest");
|
||||
|
||||
// ============================================================================
|
||||
// Type Exports
|
||||
// ============================================================================
|
||||
|
||||
export type CommentSortMode = z.infer<typeof commentSortSchema>;
|
||||
export type ReactionType = z.infer<typeof reactionTypeSchema>;
|
||||
export type CreateCommentInput = z.infer<typeof createCommentSchema>;
|
||||
export type UpdateCommentInput = z.infer<typeof updateCommentSchema>;
|
||||
export type DeleteCommentInput = z.infer<typeof deleteCommentSchema>;
|
||||
export type GetCommentsInput = z.infer<typeof getCommentsSchema>;
|
||||
export type ToggleCommentReactionInput = z.infer<
|
||||
typeof toggleCommentReactionSchema
|
||||
>;
|
||||
export type GetCommentReactionsInput = z.infer<
|
||||
typeof getCommentReactionsSchema
|
||||
>;
|
||||
@@ -7,71 +7,10 @@ import { z } from "zod";
|
||||
* Use these schemas for validating database inputs and outputs in tRPC procedures
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// User Schemas
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Full User schema matching database structure
|
||||
*/
|
||||
export const userSchema = z.object({
|
||||
id: z.string(),
|
||||
email: z.string().email().nullable().optional(),
|
||||
email_verified: z.number(),
|
||||
password_hash: z.string().nullable().optional(),
|
||||
display_name: z.string().nullable().optional(),
|
||||
provider: z.enum(["email", "google", "github"]).nullable().optional(),
|
||||
image: z.string().url().nullable().optional(),
|
||||
apple_user_string: z.string().nullable().optional(),
|
||||
database_name: z.string().nullable().optional(),
|
||||
database_token: z.string().nullable().optional(),
|
||||
database_url: z.string().nullable().optional(),
|
||||
db_destroy_date: z.string().nullable().optional(),
|
||||
created_at: z.string(),
|
||||
updated_at: z.string()
|
||||
});
|
||||
|
||||
/**
|
||||
* User creation input (for registration)
|
||||
*/
|
||||
export const createUserSchema = z.object({
|
||||
email: z.string().email().optional(),
|
||||
password: z.string().min(8).optional(),
|
||||
display_name: z.string().min(1).max(50).optional(),
|
||||
provider: z.enum(["email", "google", "github"]).optional(),
|
||||
image: z.string().url().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* User update input (partial updates)
|
||||
*/
|
||||
export const updateUserSchema = z.object({
|
||||
email: z.string().email().optional(),
|
||||
display_name: z.string().min(1).max(50).optional(),
|
||||
image: z.string().url().optional()
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Post Schemas
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Full Post schema matching database structure
|
||||
*/
|
||||
export const postSchema = z.object({
|
||||
id: z.number(),
|
||||
category: z.enum(["blog", "project"]),
|
||||
title: z.string(),
|
||||
subtitle: z.string().optional(),
|
||||
body: z.string(),
|
||||
banner_photo: z.string().optional(),
|
||||
date: z.string(),
|
||||
published: z.boolean(),
|
||||
author_id: z.string(),
|
||||
reads: z.number(),
|
||||
attachments: z.string().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* Post creation input
|
||||
*/
|
||||
@@ -97,47 +36,6 @@ export const updatePostSchema = z.object({
|
||||
attachments: z.string().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* Post with aggregated data
|
||||
*/
|
||||
export const postWithCommentsAndLikesSchema = postSchema.extend({
|
||||
total_likes: z.number(),
|
||||
total_comments: z.number()
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Comment Schemas
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Full Comment schema matching database structure
|
||||
*/
|
||||
export const commentSchema = z.object({
|
||||
id: z.number(),
|
||||
body: z.string(),
|
||||
post_id: z.number(),
|
||||
parent_comment_id: z.number().optional(),
|
||||
date: z.string(),
|
||||
edited: z.boolean(),
|
||||
commenter_id: z.string()
|
||||
});
|
||||
|
||||
/**
|
||||
* Comment creation input
|
||||
*/
|
||||
export const createCommentSchema = z.object({
|
||||
body: z.string().min(1).max(5000),
|
||||
post_id: z.number(),
|
||||
parent_comment_id: z.number().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* Comment update input
|
||||
*/
|
||||
export const updateCommentSchema = z.object({
|
||||
body: z.string().min(1).max(5000)
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// CommentReaction Schemas
|
||||
// ============================================================================
|
||||
@@ -160,94 +58,6 @@ export const reactionTypeSchema = z.enum([
|
||||
"downVote"
|
||||
]);
|
||||
|
||||
/**
|
||||
* Full CommentReaction schema matching database structure
|
||||
*/
|
||||
export const commentReactionSchema = z.object({
|
||||
id: z.number(),
|
||||
type: reactionTypeSchema,
|
||||
comment_id: z.number(),
|
||||
user_id: z.string()
|
||||
});
|
||||
|
||||
/**
|
||||
* Comment reaction creation input
|
||||
*/
|
||||
export const createCommentReactionSchema = z.object({
|
||||
type: reactionTypeSchema,
|
||||
comment_id: z.number()
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// PostLike Schemas
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Full PostLike schema matching database structure
|
||||
*/
|
||||
export const postLikeSchema = z.object({
|
||||
id: z.number(),
|
||||
user_id: z.string(),
|
||||
post_id: z.number()
|
||||
});
|
||||
|
||||
/**
|
||||
* PostLike creation input
|
||||
*/
|
||||
export const createPostLikeSchema = z.object({
|
||||
post_id: z.number()
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Tag Schemas
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Full Tag schema matching database structure
|
||||
*/
|
||||
export const tagSchema = z.object({
|
||||
id: z.number(),
|
||||
value: z.string(),
|
||||
post_id: z.number()
|
||||
});
|
||||
|
||||
/**
|
||||
* Tag creation input
|
||||
*/
|
||||
export const createTagSchema = z.object({
|
||||
value: z.string().min(1).max(50),
|
||||
post_id: z.number()
|
||||
});
|
||||
|
||||
/**
|
||||
* PostWithTags schema
|
||||
*/
|
||||
export const postWithTagsSchema = postSchema.extend({
|
||||
tags: z.array(tagSchema)
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Connection Schemas
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Full Connection schema matching database structure
|
||||
*/
|
||||
export const connectionSchema = z.object({
|
||||
id: z.number(),
|
||||
user_id: z.string(),
|
||||
connection_id: z.string(),
|
||||
post_id: z.number().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* Connection creation input
|
||||
*/
|
||||
export const createConnectionSchema = z.object({
|
||||
connection_id: z.string(),
|
||||
post_id: z.number().optional()
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Common Query Schemas
|
||||
// ============================================================================
|
||||
@@ -259,26 +69,6 @@ export const idSchema = z.object({
|
||||
id: z.number()
|
||||
});
|
||||
|
||||
export const userIdSchema = z.object({
|
||||
userId: z.string()
|
||||
});
|
||||
|
||||
export const postIdSchema = z.object({
|
||||
postId: z.number()
|
||||
});
|
||||
|
||||
export const commentIdSchema = z.object({
|
||||
commentId: z.number()
|
||||
});
|
||||
|
||||
/**
|
||||
* Pagination schema
|
||||
*/
|
||||
export const paginationSchema = z.object({
|
||||
limit: z.number().min(1).max(100).default(10),
|
||||
offset: z.number().min(0).default(0)
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Additional Database Router Schemas
|
||||
// ============================================================================
|
||||
@@ -343,10 +133,6 @@ export const getUserByIdSchema = z.object({
|
||||
id: z.string()
|
||||
});
|
||||
|
||||
export const getUserPublicDataSchema = z.object({
|
||||
id: z.string()
|
||||
});
|
||||
|
||||
export const updateUserImageSchema = z.object({
|
||||
id: z.string(),
|
||||
imageURL: z.string()
|
||||
@@ -365,15 +151,6 @@ export const updateUserEmailSchema = z.object({
|
||||
export type ReactionType = z.infer<typeof reactionTypeSchema>;
|
||||
export type CreatePostInput = z.infer<typeof createPostSchema>;
|
||||
export type UpdatePostInput = z.infer<typeof updatePostSchema>;
|
||||
export type CreateCommentInput = z.infer<typeof createCommentSchema>;
|
||||
export type UpdateCommentInput = z.infer<typeof updateCommentSchema>;
|
||||
export type CreateCommentReactionInput = z.infer<
|
||||
typeof createCommentReactionSchema
|
||||
>;
|
||||
export type CreatePostLikeInput = z.infer<typeof createPostLikeSchema>;
|
||||
export type CreateTagInput = z.infer<typeof createTagSchema>;
|
||||
export type CreateConnectionInput = z.infer<typeof createConnectionSchema>;
|
||||
export type PaginationInput = z.infer<typeof paginationSchema>;
|
||||
export type GetPostByIdInput = z.infer<typeof getPostByIdSchema>;
|
||||
export type GetPostByTitleInput = z.infer<typeof getPostByTitleSchema>;
|
||||
export type GetCommentsByPostIdInput = z.infer<
|
||||
|
||||
@@ -65,11 +65,6 @@ export const loginUserSchema = z.object({
|
||||
rememberMe: z.boolean().optional().default(false)
|
||||
});
|
||||
|
||||
/**
|
||||
* OAuth provider schema
|
||||
*/
|
||||
export const oauthProviderSchema = z.enum(["google", "github"]);
|
||||
|
||||
// ============================================================================
|
||||
// Profile Management Schemas
|
||||
// ============================================================================
|
||||
@@ -168,20 +163,12 @@ export const deleteAccountSchema = z.object({
|
||||
password: z.string().min(1, "Password is required to delete account")
|
||||
});
|
||||
|
||||
/**
|
||||
* Email verification schema
|
||||
*/
|
||||
export const verifyEmailSchema = z.object({
|
||||
token: z.string().min(1)
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Type Exports
|
||||
// ============================================================================
|
||||
|
||||
export type RegisterUserInput = z.infer<typeof registerUserSchema>;
|
||||
export type LoginUserInput = z.infer<typeof loginUserSchema>;
|
||||
export type OAuthProvider = z.infer<typeof oauthProviderSchema>;
|
||||
export type UpdateEmailInput = z.infer<typeof updateEmailSchema>;
|
||||
export type UpdateDisplayNameInput = z.infer<typeof updateDisplayNameSchema>;
|
||||
export type UpdateProfileImageInput = z.infer<typeof updateProfileImageSchema>;
|
||||
@@ -192,4 +179,3 @@ export type RequestPasswordResetInput = z.infer<
|
||||
>;
|
||||
export type ResetPasswordInput = z.infer<typeof resetPasswordSchema>;
|
||||
export type DeleteAccountInput = z.infer<typeof deleteAccountSchema>;
|
||||
export type VerifyEmailInput = z.infer<typeof verifyEmailSchema>;
|
||||
|
||||
Reference in New Issue
Block a user