Files
ReadaBook/packages/shared/src/index.ts

225 lines
8.0 KiB
TypeScript

import { z } from "zod";
export const RoleSchema = z.enum(["admin", "user"]);
export type Role = z.infer<typeof RoleSchema>;
export const UserSchema = z.object({
id: z.number().int().positive(),
email: z.string().email(),
name: z.string().nullable(),
role: RoleSchema,
createdAt: z.string()
});
export type UserDto = z.infer<typeof UserSchema>;
export const BootstrapAdminSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
name: z.string().min(1).max(120).optional()
});
export type BootstrapAdminDto = z.infer<typeof BootstrapAdminSchema>;
export const LoginSchema = z.object({
email: z.string().email(),
password: z.string().min(1)
});
export type LoginDto = z.infer<typeof LoginSchema>;
export const AuthStatusSchema = z.object({
hasUsers: z.boolean(),
initialAdminEmail: z.string().email(),
initialAdminPasswordIsDefault: z.boolean()
});
export type AuthStatusDto = z.infer<typeof AuthStatusSchema>;
export const UpdateAccountSchema = z
.object({
email: z.string().email().optional(),
name: z.string().min(1).max(120).nullable().optional(),
currentPassword: z.string().min(1),
newPassword: z.string().min(8).optional()
})
.refine((value) => value.email !== undefined || value.name !== undefined || value.newPassword !== undefined, {
message: "At least one account field must be changed"
});
export type UpdateAccountDto = z.infer<typeof UpdateAccountSchema>;
export const CreateUserSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
name: z.string().min(1).max(120).optional(),
role: RoleSchema.default("user")
});
export type CreateUserDto = z.infer<typeof CreateUserSchema>;
export const UpdateUserSchema = z.object({
email: z.string().email().optional(),
password: z.string().min(8).optional(),
name: z.string().min(1).max(120).nullable().optional(),
role: RoleSchema.optional()
});
export type UpdateUserDto = z.infer<typeof UpdateUserSchema>;
export const LibrarySchema = z.object({
id: z.number().int().positive(),
name: z.string(),
path: z.string(),
enabled: z.boolean(),
createdAt: z.string(),
updatedAt: z.string()
});
export type LibraryDto = z.infer<typeof LibrarySchema>;
export const CreateLibrarySchema = z.object({
name: z.string().min(1).max(160),
path: z.string().min(1),
enabled: z.boolean().default(true)
});
export type CreateLibraryDto = z.infer<typeof CreateLibrarySchema>;
export const UpdateLibrarySchema = z.object({
name: z.string().min(1).max(160).optional(),
path: z.string().min(1).optional(),
enabled: z.boolean().optional()
});
export type UpdateLibraryDto = z.infer<typeof UpdateLibrarySchema>;
export const SeriesSchema = z.object({
id: z.number().int().positive(),
title: z.string(),
normalizedTitle: z.string(),
description: z.string().nullable(),
publisher: z.string().nullable(),
createdAt: z.string(),
updatedAt: z.string()
});
export type SeriesDto = z.infer<typeof SeriesSchema>;
export const BookSchema = z.object({
id: z.number().int().positive(),
libraryId: z.number().int().positive(),
seriesId: z.number().int().positive().nullable().optional(),
title: z.string(),
author: z.string().nullable(),
description: z.string().nullable(),
isbn: z.string().nullable(),
isbn13: z.string().nullable(),
language: z.string().nullable(),
publisher: z.string().nullable(),
publishedDate: z.string().nullable(),
volumeNumber: z.number().int().nullable().optional(),
volumeLabel: z.string().nullable().optional(),
format: z.enum(["epub", "pdf", "cbz", "cbr"]),
filePath: z.string(),
coverPath: z.string().nullable(),
metadataStatus: z.enum(["enriched", "partial", "none"]).default("none"),
metadataProvenance: z.record(z.string(), z.string()).default({}),
series: SeriesSchema.nullable().optional(),
scanStatus: z.enum(["idle", "running", "succeeded", "failed"]).default("idle"),
enrichmentStatus: z.enum(["idle", "running", "succeeded", "failed"]).default("idle"),
fileSize: z.number().int().nonnegative(),
fileMtime: z.string(),
createdAt: z.string(),
updatedAt: z.string()
});
export type BookDto = z.infer<typeof BookSchema>;
export const BookQuerySchema = z.object({
q: z.string().optional(),
format: z.enum(["epub", "pdf", "cbz", "cbr"]).optional(),
libraryId: z.coerce.number().int().positive().optional(),
limit: z.coerce.number().int().min(1).max(100).optional(),
offset: z.coerce.number().int().min(0).default(0)
});
export type BookQueryDto = z.infer<typeof BookQuerySchema>;
export const ProgressSchema = z.object({
bookId: z.number().int().positive(),
locator: z.string().min(1),
percent: z.number().min(0).max(100),
updatedAt: z.string()
});
export type ProgressDto = z.infer<typeof ProgressSchema>;
export const UpdateProgressSchema = z.object({
locator: z.string().min(1),
percent: z.number().min(0).max(100)
});
export type UpdateProgressDto = z.infer<typeof UpdateProgressSchema>;
export const ReaderPreferencesSchema = z.object({
mode: z.enum(["paged", "scrolled", "horizontal", "vertical"]).default("paged"),
fit: z.enum(["page", "width", "height", "auto"]).nullable().default(null),
updatedAt: z.string().optional()
});
export type ReaderPreferencesDto = z.infer<typeof ReaderPreferencesSchema>;
export const UpdateReaderPreferencesSchema = z.object({
mode: z.enum(["paged", "scrolled", "horizontal", "vertical"]).optional(),
fit: z.enum(["page", "width", "height", "auto"]).nullable().optional()
});
export type UpdateReaderPreferencesDto = z.infer<typeof UpdateReaderPreferencesSchema>;
export const JobSchema = z.object({
id: z.number().int().positive(),
type: z.string(),
status: z.enum(["queued", "running", "succeeded", "failed"]),
detail: z.string().nullable(),
error: z.string().nullable(),
createdAt: z.string(),
updatedAt: z.string()
});
export type JobDto = z.infer<typeof JobSchema>;
export const MetadataProviderIdSchema = z.enum(["local", "openlibrary", "googlebooks", "bnf", "mangadex", "comicvine"]);
export type MetadataProviderId = z.infer<typeof MetadataProviderIdSchema>;
export const MetadataSourceConfigSchema = z.object({
provider: MetadataProviderIdSchema,
enabled: z.boolean(),
priority: z.number().int().min(0),
hasApiKey: z.boolean().default(false)
});
export type MetadataSourceConfigDto = z.infer<typeof MetadataSourceConfigSchema>;
export const MetadataSourcesConfigSchema = z.object({
isbnPriorityEnabled: z.boolean(),
sources: z.array(MetadataSourceConfigSchema)
});
export type MetadataSourcesConfigDto = z.infer<typeof MetadataSourcesConfigSchema>;
export const UpdateMetadataSourceConfigSchema = z.object({
provider: MetadataProviderIdSchema.exclude(["local"]),
enabled: z.boolean(),
priority: z.number().int().min(1).max(100),
apiKey: z.string().min(1).nullable().optional()
});
export type UpdateMetadataSourceConfigDto = z.infer<typeof UpdateMetadataSourceConfigSchema>;
export const UpdateMetadataSourcesConfigSchema = z.object({
isbnPriorityEnabled: z.boolean().optional(),
sources: z.array(UpdateMetadataSourceConfigSchema).optional()
});
export type UpdateMetadataSourcesConfigDto = z.infer<typeof UpdateMetadataSourcesConfigSchema>;
export const AutomationFrequencySchema = z.enum(["disabled", "daily", "weekly"]);
export type AutomationFrequency = z.infer<typeof AutomationFrequencySchema>;
export const AutomationScheduleSchema = z.object({
frequency: AutomationFrequencySchema,
time: z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/).default("03:00"),
dayOfWeek: z.number().int().min(0).max(6).default(1)
});
export type AutomationScheduleDto = z.infer<typeof AutomationScheduleSchema>;
export const AutomationSettingsSchema = z.object({
watchLibraries: z.boolean(),
autoEnrichNewBooks: z.boolean(),
scanSchedule: AutomationScheduleSchema,
enrichSchedule: AutomationScheduleSchema
});
export type AutomationSettingsDto = z.infer<typeof AutomationSettingsSchema>;
export const UpdateAutomationSettingsSchema = AutomationSettingsSchema.partial();
export type UpdateAutomationSettingsDto = z.infer<typeof UpdateAutomationSettingsSchema>;