From 3c46afb294ad2f5bd8c9ae2f39ba9de36c22a304 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Thu, 27 Feb 2025 08:29:08 +0100 Subject: [PATCH] refacto: types big review --- docs/services.md | 2 +- src/app/api/auth/login/route.ts | 3 +- src/app/api/auth/register/route.ts | 4 +- src/app/api/debug/route.ts | 6 +- .../[bookId]/pages/[pageNumber]/route.ts | 2 +- src/app/api/komga/books/[bookId]/route.ts | 4 +- src/app/api/komga/cache/clear/route.ts | 4 +- src/app/api/komga/cache/mode/route.ts | 12 ++-- src/app/api/komga/config/route.ts | 27 +++----- src/app/api/komga/favorites/route.ts | 6 +- .../pages/[pageNumber]/thumbnail/route.ts | 2 +- src/app/api/komga/libraries/route.ts | 4 +- src/app/api/komga/series/[seriesId]/route.ts | 3 +- src/app/api/komga/test/route.ts | 3 +- src/app/api/komga/ttl-config/route.ts | 6 +- src/app/api/preferences/route.ts | 9 ++- src/app/books/[bookId]/page.tsx | 3 +- src/app/libraries/[libraryId]/page.tsx | 18 +++--- src/app/series/[seriesId]/page.tsx | 17 +++-- src/app/settings/page.tsx | 8 ++- src/components/layout/Sidebar.tsx | 13 +++- src/components/library/LibraryGrid.tsx | 2 +- src/components/series/SeriesHeader.tsx | 11 +++- src/components/settings/ClientSettings.tsx | 18 +----- src/lib/services/auth-server.service.ts | 2 +- src/lib/services/base-api.service.ts | 15 +++-- src/lib/services/book.service.ts | 14 ++-- src/lib/services/config-db.service.ts | 64 ++++++++----------- src/lib/services/debug.service.ts | 2 +- src/lib/services/favorite.service.ts | 6 +- src/lib/services/image.service.ts | 2 +- src/lib/services/library.service.ts | 11 ++-- src/lib/services/preferences.service.ts | 6 +- src/lib/services/series.service.ts | 26 +++++--- src/lib/services/server-cache.service.ts | 2 +- src/lib/services/test.service.ts | 2 +- src/middleware.ts | 3 +- src/types/komga.ts | 36 +++++++++++ src/types/library.ts | 9 --- 39 files changed, 209 insertions(+), 178 deletions(-) diff --git a/docs/services.md b/docs/services.md index 726f744..624ae64 100644 --- a/docs/services.md +++ b/docs/services.md @@ -166,7 +166,7 @@ Service de test de connexion ### Méthodes -- `testConnection(config: AuthConfig): Promise<{ libraries: Library[] }>` +- `testConnection(config: AuthConfig): Promise<{ libraries: KomgaLibrary[] }>` - Teste la connexion au serveur Komga - Retourne les bibliothèques si succès diff --git a/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts index 3000df2..b95c9cf 100644 --- a/src/app/api/auth/login/route.ts +++ b/src/app/api/auth/login/route.ts @@ -3,13 +3,14 @@ import { AuthServerService } from "@/lib/services/auth-server.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; import { AppError } from "@/utils/errors"; +import { UserData } from "@/lib/services/auth-server.service"; export async function POST(request: Request) { try { const { email, password } = await request.json(); try { - const userData = await AuthServerService.loginUser(email, password); + const userData: UserData = await AuthServerService.loginUser(email, password); AuthServerService.setUserCookie(userData); return NextResponse.json({ diff --git a/src/app/api/auth/register/route.ts b/src/app/api/auth/register/route.ts index 52ae88e..59ae447 100644 --- a/src/app/api/auth/register/route.ts +++ b/src/app/api/auth/register/route.ts @@ -1,5 +1,5 @@ import { NextResponse } from "next/server"; -import { AuthServerService } from "@/lib/services/auth-server.service"; +import { AuthServerService, UserData } from "@/lib/services/auth-server.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; import { AppError } from "@/utils/errors"; @@ -9,7 +9,7 @@ export async function POST(request: Request) { const { email, password } = await request.json(); try { - const userData = await AuthServerService.createUser(email, password); + const userData: UserData = await AuthServerService.createUser(email, password); AuthServerService.setUserCookie(userData); return NextResponse.json({ diff --git a/src/app/api/debug/route.ts b/src/app/api/debug/route.ts index e4055e0..feb431f 100644 --- a/src/app/api/debug/route.ts +++ b/src/app/api/debug/route.ts @@ -1,12 +1,12 @@ import { NextRequest, NextResponse } from "next/server"; -import { DebugService } from "@/lib/services/debug.service"; +import { DebugService, RequestTiming } from "@/lib/services/debug.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; import { AppError } from "@/utils/errors"; export async function GET() { try { - const logs = await DebugService.getRequestLogs(); + const logs: RequestTiming[] = await DebugService.getRequestLogs(); return NextResponse.json(logs); } catch (error) { console.error("Erreur lors de la récupération des logs:", error); @@ -35,7 +35,7 @@ export async function GET() { export async function POST(request: NextRequest) { try { - const timing = await request.json(); + const timing: RequestTiming = await request.json(); await DebugService.logRequest(timing); return NextResponse.json({ message: "✅ Log enregistré avec succès", diff --git a/src/app/api/komga/books/[bookId]/pages/[pageNumber]/route.ts b/src/app/api/komga/books/[bookId]/pages/[pageNumber]/route.ts index 1dfa66b..ec8c3ce 100644 --- a/src/app/api/komga/books/[bookId]/pages/[pageNumber]/route.ts +++ b/src/app/api/komga/books/[bookId]/pages/[pageNumber]/route.ts @@ -11,7 +11,7 @@ export async function GET( { params }: { params: { bookId: string; pageNumber: string } } ) { try { - const pageNumber = parseInt(params.pageNumber); + const pageNumber: number = parseInt(params.pageNumber); if (isNaN(pageNumber) || pageNumber < 0) { return NextResponse.json( { diff --git a/src/app/api/komga/books/[bookId]/route.ts b/src/app/api/komga/books/[bookId]/route.ts index 0e4a6a0..ae4276a 100644 --- a/src/app/api/komga/books/[bookId]/route.ts +++ b/src/app/api/komga/books/[bookId]/route.ts @@ -3,10 +3,10 @@ import { BookService } from "@/lib/services/book.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; import { AppError } from "@/utils/errors"; - +import { KomgaBookWithPages } from "@/types/komga"; export async function GET(request: Request, { params }: { params: { bookId: string } }) { try { - const data = await BookService.getBook(params.bookId); + const data: KomgaBookWithPages = await BookService.getBook(params.bookId); return NextResponse.json(data); } catch (error) { console.error("API Books - Erreur:", error); diff --git a/src/app/api/komga/cache/clear/route.ts b/src/app/api/komga/cache/clear/route.ts index f58c9b1..fa62b09 100644 --- a/src/app/api/komga/cache/clear/route.ts +++ b/src/app/api/komga/cache/clear/route.ts @@ -1,11 +1,11 @@ import { NextResponse } from "next/server"; -import { getServerCacheService } from "@/lib/services/server-cache.service"; +import { getServerCacheService, ServerCacheService } from "@/lib/services/server-cache.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; export async function POST() { try { - const cacheService = await getServerCacheService(); + const cacheService: ServerCacheService = await getServerCacheService(); cacheService.clear(); return NextResponse.json({ message: "🧹 Cache vidé avec succès" }); } catch (error) { diff --git a/src/app/api/komga/cache/mode/route.ts b/src/app/api/komga/cache/mode/route.ts index 3738e50..e92375b 100644 --- a/src/app/api/komga/cache/mode/route.ts +++ b/src/app/api/komga/cache/mode/route.ts @@ -1,11 +1,15 @@ import { NextResponse } from "next/server"; -import { getServerCacheService } from "@/lib/services/server-cache.service"; +import { + CacheMode, + getServerCacheService, + ServerCacheService, +} from "@/lib/services/server-cache.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; export async function GET() { try { - const cacheService = await getServerCacheService(); + const cacheService: ServerCacheService = await getServerCacheService(); return NextResponse.json({ mode: cacheService.getCacheMode() }); } catch (error) { console.error("Erreur lors de la récupération du mode de cache:", error); @@ -23,7 +27,7 @@ export async function GET() { export async function POST(request: Request) { try { - const { mode } = await request.json(); + const { mode }: { mode: CacheMode } = await request.json(); if (mode !== "file" && mode !== "memory") { return NextResponse.json( { @@ -36,7 +40,7 @@ export async function POST(request: Request) { ); } - const cacheService = await getServerCacheService(); + const cacheService: ServerCacheService = await getServerCacheService(); cacheService.setCacheMode(mode); return NextResponse.json({ mode: cacheService.getCacheMode() }); } catch (error) { diff --git a/src/app/api/komga/config/route.ts b/src/app/api/komga/config/route.ts index 826eb54..28f54aa 100644 --- a/src/app/api/komga/config/route.ts +++ b/src/app/api/komga/config/route.ts @@ -2,22 +2,17 @@ import { NextResponse } from "next/server"; import { ConfigDBService } from "@/lib/services/config-db.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; +import { KomgaConfig, KomgaConfigData } from "@/types/komga"; export const dynamic = "force-dynamic"; export async function POST(request: Request) { try { - const data = await request.json(); - const mongoConfig = await ConfigDBService.saveConfig(data); - // Convertir le document Mongoose en objet simple - const config = { - url: mongoConfig.url, - username: mongoConfig.username, - password: mongoConfig.password, - userId: mongoConfig.userId, - }; + const data: KomgaConfigData = await request.json(); + const mongoConfig: KomgaConfig = await ConfigDBService.saveConfig(data); + return NextResponse.json( - { message: "⚙️ Configuration sauvegardée avec succès", config }, + { message: "⚙️ Configuration sauvegardée avec succès", mongoConfig }, { status: 200 } ); } catch (error) { @@ -47,15 +42,9 @@ export async function POST(request: Request) { export async function GET() { try { - const mongoConfig = await ConfigDBService.getConfig(); - // Convertir le document Mongoose en objet simple - const config = { - url: mongoConfig.url, - username: mongoConfig.username, - password: mongoConfig.password, - userId: mongoConfig.userId, - }; - return NextResponse.json(config, { status: 200 }); + const mongoConfig: KomgaConfig | null = await ConfigDBService.getConfig(); + + return NextResponse.json(mongoConfig, { status: 200 }); } catch (error) { console.error("Erreur lors de la récupération de la configuration:", error); if (error instanceof Error) { diff --git a/src/app/api/komga/favorites/route.ts b/src/app/api/komga/favorites/route.ts index 40e8dab..a91e8cc 100644 --- a/src/app/api/komga/favorites/route.ts +++ b/src/app/api/komga/favorites/route.ts @@ -6,7 +6,7 @@ import { AppError } from "@/utils/errors"; export async function GET() { try { - const favoriteIds = await FavoriteService.getAllFavoriteIds(); + const favoriteIds: string[] = await FavoriteService.getAllFavoriteIds(); return NextResponse.json(favoriteIds); } catch (error) { console.error("Erreur lors de la récupération des favoris:", error); @@ -35,7 +35,7 @@ export async function GET() { export async function POST(request: Request) { try { - const { seriesId } = await request.json(); + const { seriesId }: { seriesId: string } = await request.json(); await FavoriteService.addToFavorites(seriesId); return NextResponse.json({ message: "⭐️ Série ajoutée aux favoris" }); } catch (error) { @@ -65,7 +65,7 @@ export async function POST(request: Request) { export async function DELETE(request: Request) { try { - const { seriesId } = await request.json(); + const { seriesId }: { seriesId: string } = await request.json(); await FavoriteService.removeFromFavorites(seriesId); return NextResponse.json({ message: "💔 Série retirée des favoris" }); } catch (error) { diff --git a/src/app/api/komga/images/books/[bookId]/pages/[pageNumber]/thumbnail/route.ts b/src/app/api/komga/images/books/[bookId]/pages/[pageNumber]/thumbnail/route.ts index 9616e42..2634874 100644 --- a/src/app/api/komga/images/books/[bookId]/pages/[pageNumber]/thumbnail/route.ts +++ b/src/app/api/komga/images/books/[bookId]/pages/[pageNumber]/thumbnail/route.ts @@ -12,7 +12,7 @@ export async function GET( ) { try { // Convertir le numéro de page en nombre - const pageNumber = parseInt(params.pageNumber); + const pageNumber: number = parseInt(params.pageNumber); if (isNaN(pageNumber) || pageNumber < 0) { return NextResponse.json( { diff --git a/src/app/api/komga/libraries/route.ts b/src/app/api/komga/libraries/route.ts index 8a6422f..4fb93cf 100644 --- a/src/app/api/komga/libraries/route.ts +++ b/src/app/api/komga/libraries/route.ts @@ -3,12 +3,12 @@ import { LibraryService } from "@/lib/services/library.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; import { AppError } from "@/utils/errors"; - +import { KomgaLibrary } from "@/types/komga"; export const dynamic = "force-dynamic"; export async function GET() { try { - const libraries = await LibraryService.getLibraries(); + const libraries: KomgaLibrary[] = await LibraryService.getLibraries(); return NextResponse.json(libraries); } catch (error) { console.error("API Libraries - Erreur:", error); diff --git a/src/app/api/komga/series/[seriesId]/route.ts b/src/app/api/komga/series/[seriesId]/route.ts index 34815ae..99d3948 100644 --- a/src/app/api/komga/series/[seriesId]/route.ts +++ b/src/app/api/komga/series/[seriesId]/route.ts @@ -3,12 +3,13 @@ import { SeriesService } from "@/lib/services/series.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; import { AppError } from "@/utils/errors"; +import { KomgaSeries } from "@/types/komga"; export const dynamic = "force-dynamic"; export async function GET(request: Request, { params }: { params: { seriesId: string } }) { try { - const series = await SeriesService.getSeries(params.seriesId); + const series: KomgaSeries = await SeriesService.getSeries(params.seriesId); return NextResponse.json(series); } catch (error) { console.error("API Series - Erreur:", error); diff --git a/src/app/api/komga/test/route.ts b/src/app/api/komga/test/route.ts index 595e1f5..aaa3ecb 100644 --- a/src/app/api/komga/test/route.ts +++ b/src/app/api/komga/test/route.ts @@ -2,13 +2,14 @@ import { NextResponse } from "next/server"; import { TestService } from "@/lib/services/test.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; +import { KomgaLibrary } from "@/types/komga"; export async function POST(request: Request) { try { const { serverUrl, username, password } = await request.json(); const authHeader = Buffer.from(`${username}:${password}`).toString("base64"); - const { libraries } = await TestService.testConnection({ + const { libraries }: { libraries: KomgaLibrary[] } = await TestService.testConnection({ serverUrl, authHeader, }); diff --git a/src/app/api/komga/ttl-config/route.ts b/src/app/api/komga/ttl-config/route.ts index 57a2bf9..f41c87f 100644 --- a/src/app/api/komga/ttl-config/route.ts +++ b/src/app/api/komga/ttl-config/route.ts @@ -2,10 +2,11 @@ import { NextResponse } from "next/server"; import { ConfigDBService } from "@/lib/services/config-db.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; +import { TTLConfig } from "@/types/komga"; export async function GET() { try { - const config = await ConfigDBService.getTTLConfig(); + const config: TTLConfig | null = await ConfigDBService.getTTLConfig(); return NextResponse.json(config); } catch (error) { console.error("Erreur lors de la récupération de la configuration TTL:", error); @@ -37,7 +38,8 @@ export async function GET() { export async function POST(request: Request) { try { const data = await request.json(); - const config = await ConfigDBService.saveTTLConfig(data); + const config: TTLConfig = await ConfigDBService.saveTTLConfig(data); + return NextResponse.json({ message: "⏱️ Configuration TTL sauvegardée avec succès", config: { diff --git a/src/app/api/preferences/route.ts b/src/app/api/preferences/route.ts index fafebc1..0ca05fd 100644 --- a/src/app/api/preferences/route.ts +++ b/src/app/api/preferences/route.ts @@ -3,10 +3,11 @@ import { PreferencesService } from "@/lib/services/preferences.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_MESSAGES } from "@/constants/errorMessages"; import { AppError } from "@/utils/errors"; +import { UserPreferences } from "@/types/preferences"; export async function GET() { try { - const preferences = await PreferencesService.getPreferences(); + const preferences: UserPreferences = await PreferencesService.getPreferences(); return NextResponse.json(preferences); } catch (error) { console.error("Erreur lors de la récupération des préférences:", error); @@ -35,8 +36,10 @@ export async function GET() { export async function PUT(request: NextRequest) { try { - const preferences = await request.json(); - const updatedPreferences = await PreferencesService.updatePreferences(preferences); + const preferences: UserPreferences = await request.json(); + const updatedPreferences: UserPreferences = await PreferencesService.updatePreferences( + preferences + ); return NextResponse.json(updatedPreferences); } catch (error) { console.error("Erreur lors de la mise à jour des préférences:", error); diff --git a/src/app/books/[bookId]/page.tsx b/src/app/books/[bookId]/page.tsx index 0e20446..ca99378 100644 --- a/src/app/books/[bookId]/page.tsx +++ b/src/app/books/[bookId]/page.tsx @@ -4,10 +4,11 @@ import { BookSkeleton } from "@/components/skeletons/BookSkeleton"; import { BookService } from "@/lib/services/book.service"; import { notFound } from "next/navigation"; import { withPageTiming } from "@/lib/hoc/withPageTiming"; +import { KomgaBookWithPages } from "@/types/komga"; async function BookPage({ params }: { params: { bookId: string } }) { try { - const data = await BookService.getBook(params.bookId); + const data: KomgaBookWithPages = await BookService.getBook(params.bookId); return ( }> diff --git a/src/app/libraries/[libraryId]/page.tsx b/src/app/libraries/[libraryId]/page.tsx index 7f5ce2c..ba2bd51 100644 --- a/src/app/libraries/[libraryId]/page.tsx +++ b/src/app/libraries/[libraryId]/page.tsx @@ -5,7 +5,9 @@ import { revalidatePath } from "next/cache"; import { RefreshButton } from "@/components/library/RefreshButton"; import { withPageTiming } from "@/lib/hoc/withPageTiming"; import { ErrorMessage } from "@/components/ui/ErrorMessage"; - +import { LibraryResponse } from "@/types/library"; +import { KomgaSeries, KomgaLibrary } from "@/types/komga"; +import { UserPreferences } from "@/types/preferences"; interface PageProps { params: { libraryId: string }; searchParams: { page?: string; unread?: string; search?: string }; @@ -36,14 +38,14 @@ async function getLibrarySeries( try { const pageIndex = page - 1; - const series = await LibraryService.getLibrarySeries( + const series: LibraryResponse = await LibraryService.getLibrarySeries( libraryId, pageIndex, PAGE_SIZE, unreadOnly, search ); - const library = await LibraryService.getLibrary(libraryId); + const library: KomgaLibrary = await LibraryService.getLibrary(libraryId); return { data: series, library }; } catch (error) { @@ -53,19 +55,15 @@ async function getLibrarySeries( async function LibraryPage({ params, searchParams }: PageProps) { const currentPage = searchParams.page ? parseInt(searchParams.page) : 1; - const preferences = await PreferencesService.getPreferences(); + const preferences: UserPreferences = await PreferencesService.getPreferences(); // Utiliser le paramètre d'URL s'il existe, sinon utiliser la préférence utilisateur const unreadOnly = searchParams.unread !== undefined ? searchParams.unread === "true" : preferences.showOnlyUnread; try { - const { data: series, library } = await getLibrarySeries( - params.libraryId, - currentPage, - unreadOnly, - searchParams.search - ); + const { data: series, library }: { data: LibraryResponse; library: KomgaLibrary } = + await getLibrarySeries(params.libraryId, currentPage, unreadOnly, searchParams.search); return (
diff --git a/src/app/series/[seriesId]/page.tsx b/src/app/series/[seriesId]/page.tsx index a7677d1..7269545 100644 --- a/src/app/series/[seriesId]/page.tsx +++ b/src/app/series/[seriesId]/page.tsx @@ -5,6 +5,9 @@ import { PreferencesService } from "@/lib/services/preferences.service"; import { revalidatePath } from "next/cache"; import { withPageTiming } from "@/lib/hoc/withPageTiming"; import { ErrorMessage } from "@/components/ui/ErrorMessage"; +import { LibraryResponse } from "@/types/library"; +import { KomgaBook, KomgaSeries } from "@/types/komga"; +import { UserPreferences } from "@/types/preferences"; interface PageProps { params: { seriesId: string }; @@ -17,8 +20,13 @@ async function getSeriesBooks(seriesId: string, page: number = 1, unreadOnly: bo try { const pageIndex = page - 1; - const books = await SeriesService.getSeriesBooks(seriesId, pageIndex, PAGE_SIZE, unreadOnly); - const series = await SeriesService.getSeries(seriesId); + const books: LibraryResponse = await SeriesService.getSeriesBooks( + seriesId, + pageIndex, + PAGE_SIZE, + unreadOnly + ); + const series: KomgaSeries = await SeriesService.getSeries(seriesId); return { data: books, series }; } catch (error) { @@ -42,14 +50,15 @@ async function refreshSeries(seriesId: string) { async function SeriesPage({ params, searchParams }: PageProps) { const currentPage = searchParams.page ? parseInt(searchParams.page) : 1; - const preferences = await PreferencesService.getPreferences(); + const preferences: UserPreferences = await PreferencesService.getPreferences(); // Utiliser le paramètre d'URL s'il existe, sinon utiliser la préférence utilisateur const unreadOnly = searchParams.unread !== undefined ? searchParams.unread === "true" : preferences.showOnlyUnread; try { - const { data: books, series } = await getSeriesBooks(params.seriesId, currentPage, unreadOnly); + const { data: books, series }: { data: LibraryResponse; series: KomgaSeries } = + await getSeriesBooks(params.seriesId, currentPage, unreadOnly); return (
diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx index cd52a1d..21230a0 100644 --- a/src/app/settings/page.tsx +++ b/src/app/settings/page.tsx @@ -1,6 +1,7 @@ import { ConfigDBService } from "@/lib/services/config-db.service"; import { ClientSettings } from "@/components/settings/ClientSettings"; import { Metadata } from "next"; +import { KomgaConfig, TTLConfig } from "@/types/komga"; export const metadata: Metadata = { title: "Préférences", @@ -8,18 +9,19 @@ export const metadata: Metadata = { }; export default async function SettingsPage() { - let config = null; - let ttlConfig = null; + let config: KomgaConfig | null = null; + let ttlConfig: TTLConfig | null = null; try { // Récupérer la configuration Komga - const mongoConfig = await ConfigDBService.getConfig(); + const mongoConfig: KomgaConfig | null = await ConfigDBService.getConfig(); if (mongoConfig) { config = { url: mongoConfig.url, username: mongoConfig.username, userId: mongoConfig.userId, authHeader: mongoConfig.authHeader, + password: null, }; } diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 1b29141..03830ea 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -42,7 +42,10 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { console.error("Erreur de chargement des bibliothèques:", error); toast({ title: "Erreur", - description: error instanceof AppError ? error.message : ERROR_MESSAGES[ERROR_CODES.LIBRARY.FETCH_ERROR], + description: + error instanceof AppError + ? error.message + : ERROR_MESSAGES[ERROR_CODES.LIBRARY.FETCH_ERROR], variant: "destructive", }); setLibraries([]); @@ -80,7 +83,10 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { console.error("Erreur de chargement des favoris:", error); toast({ title: "Erreur", - description: error instanceof AppError ? error.message : ERROR_MESSAGES[ERROR_CODES.FAVORITE.FETCH_ERROR], + description: + error instanceof AppError + ? error.message + : ERROR_MESSAGES[ERROR_CODES.FAVORITE.FETCH_ERROR], variant: "destructive", }); setFavorites([]); @@ -130,7 +136,8 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { console.error("Erreur lors de la déconnexion:", error); toast({ title: "Erreur", - description: error instanceof AppError ? error.message : ERROR_MESSAGES[ERROR_CODES.AUTH.LOGOUT_ERROR], + description: + error instanceof AppError ? error.message : ERROR_MESSAGES[ERROR_CODES.AUTH.LOGOUT_ERROR], variant: "destructive", }); } diff --git a/src/components/library/LibraryGrid.tsx b/src/components/library/LibraryGrid.tsx index 3c5b7d4..c00856f 100644 --- a/src/components/library/LibraryGrid.tsx +++ b/src/components/library/LibraryGrid.tsx @@ -1,6 +1,6 @@ -import { KomgaLibrary } from "@/types/komga"; import { Book } from "lucide-react"; import { Cover } from "@/components/ui/cover"; +import { KomgaLibrary } from "@/types/komga"; interface LibraryGridProps { libraries: KomgaLibrary[]; diff --git a/src/components/series/SeriesHeader.tsx b/src/components/series/SeriesHeader.tsx index 8e34019..a77ef9b 100644 --- a/src/components/series/SeriesHeader.tsx +++ b/src/components/series/SeriesHeader.tsx @@ -9,6 +9,7 @@ import { Cover } from "@/components/ui/cover"; import { RefreshButton } from "@/components/library/RefreshButton"; import { AppError } from "@/utils/errors"; import { ERROR_CODES } from "@/constants/errorCodes"; +import { ERROR_MESSAGES } from "@/constants/errorMessages"; interface SeriesHeaderProps { series: KomgaSeries; @@ -32,7 +33,10 @@ export const SeriesHeader = ({ series, refreshSeries }: SeriesHeaderProps) => { console.error("Erreur lors de la vérification des favoris:", error); toast({ title: "Erreur", - description: error instanceof AppError ? error.message : ERROR_MESSAGES[ERROR_CODES.FAVORITE.NETWORK_ERROR], + description: + error instanceof AppError + ? error.message + : ERROR_MESSAGES[ERROR_CODES.FAVORITE.NETWORK_ERROR], variant: "destructive", }); } @@ -71,7 +75,10 @@ export const SeriesHeader = ({ series, refreshSeries }: SeriesHeaderProps) => { console.error("Erreur lors de la modification des favoris:", error); toast({ title: "Erreur", - description: error instanceof AppError ? error.message : ERROR_MESSAGES[ERROR_CODES.FAVORITE.NETWORK_ERROR], + description: + error instanceof AppError + ? error.message + : ERROR_MESSAGES[ERROR_CODES.FAVORITE.NETWORK_ERROR], variant: "destructive", }); } diff --git a/src/components/settings/ClientSettings.tsx b/src/components/settings/ClientSettings.tsx index 8a4a38c..28ba2fc 100644 --- a/src/components/settings/ClientSettings.tsx +++ b/src/components/settings/ClientSettings.tsx @@ -9,23 +9,7 @@ import { usePreferences } from "@/contexts/PreferencesContext"; import { Switch } from "@/components/ui/switch"; import { Label } from "@/components/ui/label"; import { CacheModeSwitch } from "@/components/settings/CacheModeSwitch"; - -interface KomgaConfig { - url: string; - username: string; - userId: string; - password?: string; - authHeader: string; -} - -interface TTLConfigData { - defaultTTL: number; - homeTTL: number; - librariesTTL: number; - seriesTTL: number; - booksTTL: number; - imagesTTL: number; -} +import { KomgaConfig, TTLConfigData } from "@/types/komga"; interface ClientSettingsProps { initialConfig: KomgaConfig | null; diff --git a/src/lib/services/auth-server.service.ts b/src/lib/services/auth-server.service.ts index e143805..595ece4 100644 --- a/src/lib/services/auth-server.service.ts +++ b/src/lib/services/auth-server.service.ts @@ -5,7 +5,7 @@ import bcrypt from "bcrypt"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; -interface UserData { +export interface UserData { id: string; email: string; roles: string[]; diff --git a/src/lib/services/base-api.service.ts b/src/lib/services/base-api.service.ts index 75e50ec..e62ea6c 100644 --- a/src/lib/services/base-api.service.ts +++ b/src/lib/services/base-api.service.ts @@ -4,7 +4,8 @@ import { ConfigDBService } from "./config-db.service"; import { DebugService } from "./debug.service"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; - +import { KomgaConfig } from "@/types/komga"; +import { ServerCacheService } from "./server-cache.service"; // Types de cache disponibles export type CacheType = "DEFAULT" | "HOME" | "LIBRARIES" | "SERIES" | "BOOKS" | "IMAGES"; @@ -20,7 +21,11 @@ interface KomgaUrlBuilder { export abstract class BaseApiService { protected static async getKomgaConfig(): Promise { try { - const config = await ConfigDBService.getConfig(); + const config: KomgaConfig | null = await ConfigDBService.getConfig(); + if (!config) { + throw new AppError(ERROR_CODES.KOMGA.MISSING_CONFIG); + } + return { serverUrl: config.url, authHeader: config.authHeader, @@ -47,7 +52,7 @@ export abstract class BaseApiService { fetcher: () => Promise, type: CacheType = "DEFAULT" ): Promise { - const cacheService = await getServerCacheService(); + const cacheService: ServerCacheService = await getServerCacheService(); try { const result = await cacheService.getOrSet(key, fetcher, type); @@ -82,11 +87,11 @@ export abstract class BaseApiService { options: KomgaRequestInit = {} ): Promise { const startTime = performance.now(); - const config = await this.getKomgaConfig(); + const config: AuthConfig = await this.getKomgaConfig(); const { path, params } = urlBuilder; const url = this.buildUrl(config, path, params); - const headers = this.getAuthHeaders(config); + const headers: Headers = this.getAuthHeaders(config); if (headersOptions) { for (const [key, value] of Object.entries(headersOptions)) { headers.set(key as string, value as string); diff --git a/src/lib/services/book.service.ts b/src/lib/services/book.service.ts index f1d2591..20e8b6f 100644 --- a/src/lib/services/book.service.ts +++ b/src/lib/services/book.service.ts @@ -1,14 +1,14 @@ import { BaseApiService } from "./base-api.service"; -import { KomgaBook } from "@/types/komga"; -import { ImageService } from "./image.service"; +import { KomgaBook, KomgaBookWithPages } from "@/types/komga"; +import { ImageService, ImageResponse } from "./image.service"; import { PreferencesService } from "./preferences.service"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; export class BookService extends BaseApiService { - static async getBook(bookId: string): Promise<{ book: KomgaBook; pages: number[] }> { + static async getBook(bookId: string): Promise { try { - return this.fetchWithCache<{ book: KomgaBook; pages: number[] }>( + return this.fetchWithCache( `book-${bookId}`, async () => { // Récupération des détails du tome @@ -86,7 +86,7 @@ export class BookService extends BaseApiService { try { // Ajuster le numéro de page pour l'API Komga (zero-based) const adjustedPageNumber = pageNumber - 1; - const response = await ImageService.getImage( + const response: ImageResponse = await ImageService.getImage( `books/${bookId}/pages/${adjustedPageNumber}?zero_based=true` ); return new Response(response.buffer, { @@ -107,7 +107,7 @@ export class BookService extends BaseApiService { // Si l'utilisateur préfère les vignettes, utiliser la miniature if (preferences.showThumbnails) { - const response = await ImageService.getImage(`books/${bookId}/thumbnail`); + const response: ImageResponse = await ImageService.getImage(`books/${bookId}/thumbnail`); return new Response(response.buffer, { headers: { "Content-Type": response.contentType || "image/jpeg", @@ -133,7 +133,7 @@ export class BookService extends BaseApiService { static async getPageThumbnail(bookId: string, pageNumber: number): Promise { try { - const response = await ImageService.getImage( + const response: ImageResponse = await ImageService.getImage( `books/${bookId}/pages/${pageNumber}/thumbnail?zero_based=true` ); return new Response(response.buffer, { diff --git a/src/lib/services/config-db.service.ts b/src/lib/services/config-db.service.ts index e60488b..eb21eab 100644 --- a/src/lib/services/config-db.service.ts +++ b/src/lib/services/config-db.service.ts @@ -1,49 +1,31 @@ import connectDB from "@/lib/mongodb"; -import { KomgaConfig } from "@/lib/models/config.model"; -import { TTLConfig } from "@/lib/models/ttl-config.model"; +import { KomgaConfig as KomgaConfigModel } from "@/lib/models/config.model"; +import { TTLConfig as TTLConfigModel } from "@/lib/models/ttl-config.model"; import { DebugService } from "./debug.service"; import { AuthServerService } from "./auth-server.service"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; - -interface User { - id: string; - email: string; -} - -interface KomgaConfigData { - url: string; - username: string; - password: string; - authHeader: string; -} - -interface TTLConfigData { - defaultTTL: number; - homeTTL: number; - librariesTTL: number; - seriesTTL: number; - booksTTL: number; - imagesTTL: number; -} +import { User, KomgaConfigData, TTLConfigData, KomgaConfig, TTLConfig } from "@/types/komga"; export class ConfigDBService { private static getCurrentUser(): User { - const user = AuthServerService.getCurrentUser(); + const user: User | null = AuthServerService.getCurrentUser(); if (!user) { throw new AppError(ERROR_CODES.AUTH.UNAUTHENTICATED); } return user; } - static async saveConfig(data: KomgaConfigData) { + static async saveConfig(data: KomgaConfigData): Promise { try { - const user = this.getCurrentUser(); + const user: User | null = this.getCurrentUser(); await connectDB(); - const authHeader = Buffer.from(`${data.username}:${data.password}`).toString("base64"); + const authHeader: string = Buffer.from(`${data.username}:${data.password}`).toString( + "base64" + ); - const config = await KomgaConfig.findOneAndUpdate( + const config: KomgaConfig | null = await KomgaConfigModel.findOneAndUpdate( { userId: user.id }, { userId: user.id, @@ -54,6 +36,9 @@ export class ConfigDBService { }, { upsert: true, new: true } ); + if (!config) { + throw new AppError(ERROR_CODES.CONFIG.SAVE_ERROR); + } return config; } catch (error) { @@ -64,13 +49,13 @@ export class ConfigDBService { } } - static async getConfig() { + static async getConfig(): Promise { try { - const user = this.getCurrentUser(); + const user: User | null = this.getCurrentUser(); await connectDB(); return DebugService.measureMongoOperation("getConfig", async () => { - const config = await KomgaConfig.findOne({ userId: user.id }); + const config: KomgaConfig | null = await KomgaConfigModel.findOne({ userId: user.id }); return config; }); } catch (error) { @@ -81,13 +66,13 @@ export class ConfigDBService { } } - static async getTTLConfig() { + static async getTTLConfig(): Promise { try { - const user = this.getCurrentUser(); + const user: User | null = this.getCurrentUser(); await connectDB(); return DebugService.measureMongoOperation("getTTLConfig", async () => { - const config = await TTLConfig.findOne({ userId: user.id }); + const config: TTLConfig | null = await TTLConfigModel.findOne({ userId: user.id }); return config; }); } catch (error) { @@ -98,13 +83,13 @@ export class ConfigDBService { } } - static async saveTTLConfig(data: TTLConfigData) { + static async saveTTLConfig(data: TTLConfigData): Promise { try { - const user = this.getCurrentUser(); + const user: User | null = this.getCurrentUser(); await connectDB(); return DebugService.measureMongoOperation("saveTTLConfig", async () => { - const config = await TTLConfig.findOneAndUpdate( + const config: TTLConfig | null = await TTLConfigModel.findOneAndUpdate( { userId: user.id }, { userId: user.id, @@ -112,6 +97,11 @@ export class ConfigDBService { }, { upsert: true, new: true } ); + + if (!config) { + throw new AppError(ERROR_CODES.CONFIG.TTL_SAVE_ERROR); + } + return config; }); } catch (error) { diff --git a/src/lib/services/debug.service.ts b/src/lib/services/debug.service.ts index 4d3afc2..f2affb1 100644 --- a/src/lib/services/debug.service.ts +++ b/src/lib/services/debug.service.ts @@ -6,7 +6,7 @@ import { PreferencesService } from "./preferences.service"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; -interface RequestTiming { +export interface RequestTiming { url: string; startTime: number; endTime: number; diff --git a/src/lib/services/favorite.service.ts b/src/lib/services/favorite.service.ts index 114115b..d213540 100644 --- a/src/lib/services/favorite.service.ts +++ b/src/lib/services/favorite.service.ts @@ -4,11 +4,7 @@ import { DebugService } from "./debug.service"; import { AuthServerService } from "./auth-server.service"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; - -interface User { - id: string; - email: string; -} +import { User } from "@/types/komga"; export class FavoriteService { private static readonly FAVORITES_CHANGE_EVENT = "favoritesChanged"; diff --git a/src/lib/services/image.service.ts b/src/lib/services/image.service.ts index 89146fc..41153d4 100644 --- a/src/lib/services/image.service.ts +++ b/src/lib/services/image.service.ts @@ -2,7 +2,7 @@ import { BaseApiService } from "./base-api.service"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; -interface ImageResponse { +export interface ImageResponse { buffer: Buffer; contentType: string | null; } diff --git a/src/lib/services/library.service.ts b/src/lib/services/library.service.ts index 7fac1e0..a7f724f 100644 --- a/src/lib/services/library.service.ts +++ b/src/lib/services/library.service.ts @@ -1,16 +1,17 @@ import { BaseApiService } from "./base-api.service"; -import { Library, LibraryResponse } from "@/types/library"; +import { LibraryResponse } from "@/types/library"; import { Series } from "@/types/series"; import { getServerCacheService } from "./server-cache.service"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; +import { KomgaLibrary } from "@/types/komga"; export class LibraryService extends BaseApiService { - static async getLibraries(): Promise { + static async getLibraries(): Promise { try { - return this.fetchWithCache( + return this.fetchWithCache( "libraries", - async () => this.fetchFromApi({ path: "libraries" }), + async () => this.fetchFromApi({ path: "libraries" }), "LIBRARIES" ); } catch (error) { @@ -18,7 +19,7 @@ export class LibraryService extends BaseApiService { } } - static async getLibrary(libraryId: string): Promise { + static async getLibrary(libraryId: string): Promise { try { const libraries = await this.getLibraries(); const library = libraries.find((library) => library.id === libraryId); diff --git a/src/lib/services/preferences.service.ts b/src/lib/services/preferences.service.ts index e690508..7adb299 100644 --- a/src/lib/services/preferences.service.ts +++ b/src/lib/services/preferences.service.ts @@ -3,11 +3,7 @@ import { AuthServerService } from "./auth-server.service"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; import { UserPreferences, defaultPreferences } from "@/types/preferences"; - -interface User { - id: string; - email: string; -} +import { User } from "@/types/komga"; export class PreferencesService { static getCurrentUser(): User { diff --git a/src/lib/services/series.service.ts b/src/lib/services/series.service.ts index 2077a3b..15cb608 100644 --- a/src/lib/services/series.service.ts +++ b/src/lib/services/series.service.ts @@ -2,11 +2,13 @@ import { BaseApiService } from "./base-api.service"; import { LibraryResponse } from "@/types/library"; import { KomgaBook, KomgaSeries } from "@/types/komga"; import { BookService } from "./book.service"; -import { ImageService } from "./image.service"; +import { ImageService, ImageResponse } from "./image.service"; import { PreferencesService } from "./preferences.service"; import { getServerCacheService } from "./server-cache.service"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; +import { UserPreferences } from "@/types/preferences"; +import { ServerCacheService } from "./server-cache.service"; export class SeriesService extends BaseApiService { static async getSeries(seriesId: string): Promise { @@ -84,19 +86,19 @@ export class SeriesService extends BaseApiService { ): Promise> { try { // Récupérer tous les livres depuis le cache - const allBooks = await this.getAllSeriesBooks(seriesId); + const allBooks: KomgaBook[] = await this.getAllSeriesBooks(seriesId); // Filtrer les livres let filteredBooks = allBooks; if (unreadOnly) { filteredBooks = filteredBooks.filter( - (book) => !book.readProgress || !book.readProgress.completed + (book: KomgaBook) => !book.readProgress || !book.readProgress.completed ); } // Trier les livres par numéro - filteredBooks.sort((a, b) => a.number - b.number); + filteredBooks.sort((a: KomgaBook, b: KomgaBook) => a.number - b.number); // Calculer la pagination const totalElements = filteredBooks.length; @@ -140,7 +142,7 @@ export class SeriesService extends BaseApiService { } static async invalidateSeriesBooksCache(seriesId: string): Promise { - const cacheService = await getServerCacheService(); + const cacheService: ServerCacheService = await getServerCacheService(); await cacheService.delete(`series-${seriesId}-all-books`); } @@ -149,7 +151,9 @@ export class SeriesService extends BaseApiService { return this.fetchWithCache( `series-first-book-${seriesId}`, async () => { - const data = await this.fetchFromApi>({ + const data: LibraryResponse = await this.fetchFromApi< + LibraryResponse + >({ path: `series/${seriesId}/books`, params: { page: "0", size: "1" }, }); @@ -170,11 +174,11 @@ export class SeriesService extends BaseApiService { static async getCover(seriesId: string): Promise { try { // Récupérer les préférences de l'utilisateur - const preferences = await PreferencesService.getPreferences(); + const preferences: UserPreferences = await PreferencesService.getPreferences(); // Si l'utilisateur préfère les vignettes, utiliser la miniature if (preferences.showThumbnails) { - const response = await ImageService.getImage(`series/${seriesId}/thumbnail`); + const response: ImageResponse = await ImageService.getImage(`series/${seriesId}/thumbnail`); return new Response(response.buffer, { headers: { "Content-Type": response.contentType || "image/jpeg", @@ -198,8 +202,10 @@ export class SeriesService extends BaseApiService { static async getMultipleSeries(seriesIds: string[]): Promise { try { - const seriesPromises = seriesIds.map((id) => this.getSeries(id)); - const series = await Promise.all(seriesPromises); + const seriesPromises: Promise[] = seriesIds.map((id: string) => + this.getSeries(id) + ); + const series: KomgaSeries[] = await Promise.all(seriesPromises); return series.filter(Boolean); } catch (error) { throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error); diff --git a/src/lib/services/server-cache.service.ts b/src/lib/services/server-cache.service.ts index f997df4..fbd5d76 100644 --- a/src/lib/services/server-cache.service.ts +++ b/src/lib/services/server-cache.service.ts @@ -4,7 +4,7 @@ import { PreferencesService } from "./preferences.service"; import { DebugService } from "./debug.service"; import { AuthServerService } from "./auth-server.service"; -type CacheMode = "file" | "memory"; +export type CacheMode = "file" | "memory"; interface CacheConfig { mode: CacheMode; diff --git a/src/lib/services/test.service.ts b/src/lib/services/test.service.ts index 5e4dcbf..eefd483 100644 --- a/src/lib/services/test.service.ts +++ b/src/lib/services/test.service.ts @@ -1,8 +1,8 @@ import { BaseApiService } from "./base-api.service"; import { AuthConfig } from "@/types/auth"; -import { KomgaLibrary } from "@/types/komga"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; +import { KomgaLibrary } from "@/types/komga"; export class TestService extends BaseApiService { static async testConnection(config: AuthConfig): Promise<{ libraries: KomgaLibrary[] }> { diff --git a/src/middleware.ts b/src/middleware.ts index 9a4029f..e0a922d 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -2,6 +2,7 @@ import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; import { ERROR_CODES } from "./constants/errorCodes"; import { ERROR_MESSAGES } from "./constants/errorMessages"; +import { UserData } from "./lib/services/auth-server.service"; // Routes qui ne nécessitent pas d'authentification const publicRoutes = ["/login", "/register", "/images"]; @@ -43,7 +44,7 @@ export function middleware(request: NextRequest) { } try { - const userData = JSON.parse(atob(user.value)); + const userData: UserData = JSON.parse(atob(user.value)); if (!userData || !userData.authenticated || !userData.id || !userData.email) { throw new Error(ERROR_MESSAGES[ERROR_CODES.MIDDLEWARE.INVALID_SESSION]); } diff --git a/src/types/komga.ts b/src/types/komga.ts index 0cc751d..2897f97 100644 --- a/src/types/komga.ts +++ b/src/types/komga.ts @@ -1,3 +1,34 @@ +// Types liés à la configuration +export interface User { + id: string; + email: string; +} + +export interface KomgaConfigData { + url: string; + username: string; + password?: string | null; + authHeader: string; +} + +export interface KomgaConfig extends KomgaConfigData { + userId: string; +} + +export interface TTLConfigData { + defaultTTL: number; + homeTTL: number; + librariesTTL: number; + seriesTTL: number; + booksTTL: number; + imagesTTL: number; +} + +export interface TTLConfig extends TTLConfigData { + userId: string; +} + +// Types liés à l'API Komga export interface KomgaUser { id: string; email: string; @@ -107,3 +138,8 @@ export interface BookMetadata { releaseDate: string; isbn: string; } + +export interface KomgaBookWithPages { + book: KomgaBook; + pages: number[]; +} diff --git a/src/types/library.ts b/src/types/library.ts index e9cdcf6..23a03a5 100644 --- a/src/types/library.ts +++ b/src/types/library.ts @@ -1,12 +1,3 @@ -export interface Library { - id: string; - name: string; - root: string; - importLastModified: string; - lastModified: string; - unavailable: boolean; -} - export interface LibraryResponse { content: T[]; empty: boolean;