Files
ReadaBook/packages/shared/src/index.ts
Git Agent 8f7555cfe4 feat(api,web): auth et first-run — bootstrap admin, login, session, gardes
- api: auth controller/service, config env
- web: App/LoginPage/ProfilePage, garde d'auth, client API, styles
- shared: types/contrats auth
- compose: variables d'environnement first-run

Refs: #14
2026-08-23 11:01:00 +02:00

140 lines
4.3 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 BookSchema = z.object({
id: z.number().int().positive(),
libraryId: z.number().int().positive(),
title: z.string(),
author: z.string().nullable(),
description: z.string().nullable(),
isbn: z.string().nullable(),
language: z.string().nullable(),
publisher: z.string().nullable(),
publishedDate: z.string().nullable(),
format: z.enum(["epub", "pdf"]),
filePath: z.string(),
coverPath: z.string().nullable(),
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"]).optional(),
libraryId: z.coerce.number().int().positive().optional(),
limit: z.coerce.number().int().min(1).max(100).default(50),
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 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>;