import { z } from "zod"; const hexColor = /^#[0-9A-Fa-f]{6}$/; const languageSchema = z.object({ color: z.string().regex(hexColor), percentage: z.number().min(0).max(100), }); const imageUrl = z .string() .refine( (u) => u.startsWith("https://") || u.startsWith("http://") || u.startsWith("data:image/"), "Must be http, https or data URI", ); export const repositoryCardSchema = z.object({ type: z.literal("repository"), repoName: z.string().min(1).max(100), ownerHandle: z.string().min(1).max(100), stars: z.number().int().min(0).max(1000000).default(0), pulls: z.number().int().min(0).max(100000).default(0), issues: z.number().int().min(0).max(100000).default(0), createdAt: z.string().max(100).optional().default(""), avatarUrl: imageUrl.optional(), languages: z.array(languageSchema).max(5).default([]), }); export const issueCardSchema = z.object({ type: z.literal("issue"), repoName: z.string().min(1).max(100), ownerHandle: z.string().min(1).max(100), authorHandle: z.string().min(1).max(100), avatarUrl: imageUrl.optional(), authorAvatarUrl: imageUrl.optional(), title: z.string().min(1).max(500), issueNumber: z.union([z.number().int().positive(), z.string().min(1).max(50)]), status: z.enum(["open", "closed"]), labels: z .array( z.object({ name: z.string().max(50), color: z.string().regex(hexColor), }), ) .max(10) .default([]), commentCount: z.number().int().min(0).default(0), reactionCount: z.number().int().min(0).default(0), createdAt: z.string().optional().default(""), }); export const pullRequestCardSchema = z.object({ type: z.literal("pullRequest"), repoName: z.string().min(1).max(100), ownerHandle: z.string().min(1).max(100), authorHandle: z.string().min(1).max(100), avatarUrl: imageUrl.optional(), authorAvatarUrl: imageUrl.optional(), title: z.string().min(1).max(500), pullRequestNumber: z.union([z.number().int().positive(), z.string().min(1).max(50)]), status: z.enum(["open", "closed", "merged"]), filesChanged: z.number().int().min(0).default(0), additions: z.number().int().min(0).default(0), deletions: z.number().int().min(0).default(0), rounds: z.number().int().min(1).default(1), commentCount: z.number().int().min(0).default(0), reactionCount: z.number().int().min(0).default(0), createdAt: z.string().optional().default(""), }); export const cardPayloadSchema = z.discriminatedUnion("type", [ repositoryCardSchema, issueCardSchema, pullRequestCardSchema, ]); export type Language = z.infer; export type RepositoryCardData = z.infer; export type IssueCardData = z.infer; export type PullRequestCardData = z.infer;