refacto: types big review
This commit is contained in:
@@ -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[];
|
||||
|
||||
@@ -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<AuthConfig> {
|
||||
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<T>,
|
||||
type: CacheType = "DEFAULT"
|
||||
): Promise<T> {
|
||||
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<T> {
|
||||
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);
|
||||
|
||||
@@ -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<KomgaBookWithPages> {
|
||||
try {
|
||||
return this.fetchWithCache<{ book: KomgaBook; pages: number[] }>(
|
||||
return this.fetchWithCache<KomgaBookWithPages>(
|
||||
`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<Response> {
|
||||
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, {
|
||||
|
||||
@@ -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<KomgaConfig> {
|
||||
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<KomgaConfig | null> {
|
||||
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<TTLConfig | null> {
|
||||
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<TTLConfig> {
|
||||
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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<Library[]> {
|
||||
static async getLibraries(): Promise<KomgaLibrary[]> {
|
||||
try {
|
||||
return this.fetchWithCache<Library[]>(
|
||||
return this.fetchWithCache<KomgaLibrary[]>(
|
||||
"libraries",
|
||||
async () => this.fetchFromApi<Library[]>({ path: "libraries" }),
|
||||
async () => this.fetchFromApi<KomgaLibrary[]>({ path: "libraries" }),
|
||||
"LIBRARIES"
|
||||
);
|
||||
} catch (error) {
|
||||
@@ -18,7 +19,7 @@ export class LibraryService extends BaseApiService {
|
||||
}
|
||||
}
|
||||
|
||||
static async getLibrary(libraryId: string): Promise<Library> {
|
||||
static async getLibrary(libraryId: string): Promise<KomgaLibrary> {
|
||||
try {
|
||||
const libraries = await this.getLibraries();
|
||||
const library = libraries.find((library) => library.id === libraryId);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<KomgaSeries> {
|
||||
@@ -84,19 +86,19 @@ export class SeriesService extends BaseApiService {
|
||||
): Promise<LibraryResponse<KomgaBook>> {
|
||||
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<void> {
|
||||
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<string>(
|
||||
`series-first-book-${seriesId}`,
|
||||
async () => {
|
||||
const data = await this.fetchFromApi<LibraryResponse<KomgaBook>>({
|
||||
const data: LibraryResponse<KomgaBook> = await this.fetchFromApi<
|
||||
LibraryResponse<KomgaBook>
|
||||
>({
|
||||
path: `series/${seriesId}/books`,
|
||||
params: { page: "0", size: "1" },
|
||||
});
|
||||
@@ -170,11 +174,11 @@ export class SeriesService extends BaseApiService {
|
||||
static async getCover(seriesId: string): Promise<Response> {
|
||||
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<KomgaSeries[]> {
|
||||
try {
|
||||
const seriesPromises = seriesIds.map((id) => this.getSeries(id));
|
||||
const series = await Promise.all(seriesPromises);
|
||||
const seriesPromises: Promise<KomgaSeries>[] = 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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[] }> {
|
||||
|
||||
Reference in New Issue
Block a user