/**
* Zod validation schemas for HackerNews MCP Server
*/
import { z } from "zod";
/**
* Schema for HackerNews post/item
*/
export const HackerNewsPostSchema: z.ZodType<any> = z.object({
objectID: z.string().min(1),
created_at: z.string().datetime(),
created_at_i: z.number().int().positive(),
title: z.string().nullable(),
url: z.string().url().nullable().or(z.literal(null)),
author: z.string().min(1),
points: z.number().int().nonnegative().nullable(),
story_id: z.number().int().positive().nullable(),
parent_id: z.number().int().positive().nullable(),
comment_text: z.string().nullable(),
story_text: z.string().nullable(),
num_comments: z.number().int().nonnegative().nullable(),
_tags: z.array(z.string()),
children: z
.array(z.lazy((): z.ZodType<any> => HackerNewsPostSchema))
.optional()
.default([]),
});
export type HackerNewsPost = z.infer<typeof HackerNewsPostSchema>;
/**
* Schema for HackerNews user profile
*/
export const HackerNewsUserSchema = z.object({
username: z.string().min(1).max(15),
created_at: z.string().datetime(),
created_at_i: z.number().int().positive(),
karma: z.number().int().nonnegative(),
about: z.string().nullable(),
});
export type HackerNewsUser = z.infer<typeof HackerNewsUserSchema>;
/**
* Schema for search query parameters
*/
export const SearchQuerySchema = z.object({
query: z.string().max(1000).optional().default(""),
tags: z.array(z.string()).optional().default([]),
numericFilters: z.array(z.string()).optional().default([]),
page: z.number().int().nonnegative().max(999).optional().default(0),
hitsPerPage: z.number().int().min(1).max(1000).optional().default(20),
});
export type SearchQuery = z.infer<typeof SearchQuerySchema>;
/**
* Schema for paginated search results
*/
export const SearchResultSchema = z.object({
hits: z.array(HackerNewsPostSchema),
nbHits: z.number().int().nonnegative(),
page: z.number().int().nonnegative(),
nbPages: z.number().int().nonnegative(),
hitsPerPage: z.number().int().positive(),
processingTimeMS: z.number().nonnegative(),
});
export type SearchResult = z.infer<typeof SearchResultSchema>;
/**
* Schema for search_posts tool input
*/
export const SearchPostsInputSchema = z.object({
query: z.string().max(1000).optional(),
tags: z
.array(z.enum(["story", "comment", "poll", "pollopt", "show_hn", "ask_hn", "front_page"]))
.optional(),
author: z.string().min(1).max(15).optional(),
storyId: z.number().int().positive().optional(),
minPoints: z.number().int().nonnegative().optional(),
maxPoints: z.number().int().nonnegative().optional(),
minComments: z.number().int().nonnegative().optional(),
maxComments: z.number().int().nonnegative().optional(),
dateAfter: z.string().datetime().optional(),
dateBefore: z.string().datetime().optional(),
sortByDate: z.boolean().optional().default(false),
page: z.number().int().nonnegative().max(999).optional().default(0),
hitsPerPage: z.number().int().min(1).max(100).optional().default(20),
});
export type SearchPostsInput = z.infer<typeof SearchPostsInputSchema>;
/**
* Schema for get_front_page tool input
*/
export const GetFrontPageInputSchema = z.object({
page: z.number().int().nonnegative().optional().default(0),
hitsPerPage: z.number().int().min(1).max(30).optional().default(30),
});
export type GetFrontPageInput = z.infer<typeof GetFrontPageInputSchema>;
/**
* Schema for get_post tool input
*/
export const GetPostInputSchema = z.object({
postId: z.string().regex(/^\d+$/, "Post ID must be a numeric string"),
});
export type GetPostInput = z.infer<typeof GetPostInputSchema>;
/**
* Schema for get_user tool input
*/
export const GetUserInputSchema = z.object({
username: z.string().min(1).max(15),
});
export type GetUserInput = z.infer<typeof GetUserInputSchema>;