feat: implement DELETE API endpoint for cache invalidation in HomeService and update ClientHomePage to utilize it
This commit is contained in:
@@ -36,3 +36,34 @@ export async function GET() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function DELETE() {
|
||||||
|
try {
|
||||||
|
await HomeService.invalidateHomeCache();
|
||||||
|
return NextResponse.json({ success: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("API Home - Erreur lors de l'invalidation du cache:", error);
|
||||||
|
if (error instanceof AppError) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
error: {
|
||||||
|
code: error.code,
|
||||||
|
name: "Cache invalidation error",
|
||||||
|
message: getErrorMessage(error.code),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
error: {
|
||||||
|
code: ERROR_CODES.CACHE.DELETE_ERROR,
|
||||||
|
name: "Cache invalidation error",
|
||||||
|
message: getErrorMessage(ERROR_CODES.CACHE.DELETE_ERROR),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { ClientLibraryPage } from "./ClientLibraryPage";
|
|||||||
import type { UserPreferences } from "@/types/preferences";
|
import type { UserPreferences } from "@/types/preferences";
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: { libraryId: string };
|
params: Promise<{ libraryId: string }>;
|
||||||
searchParams: { page?: string; unread?: string; search?: string; size?: string };
|
searchParams: Promise<{ page?: string; unread?: string; search?: string; size?: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function LibraryPage({ params, searchParams }: PageProps) {
|
export default async function LibraryPage({ params, searchParams }: PageProps) {
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import { LoginContent } from "./LoginContent";
|
|||||||
import { withPageTiming } from "@/lib/hoc/withPageTiming";
|
import { withPageTiming } from "@/lib/hoc/withPageTiming";
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
searchParams: {
|
searchParams: Promise<{
|
||||||
from?: string;
|
from?: string;
|
||||||
tab?: string;
|
tab?: string;
|
||||||
};
|
}>;
|
||||||
}
|
}
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Connexion",
|
title: "Connexion",
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { ClientSeriesPage } from "./ClientSeriesPage";
|
|||||||
import type { UserPreferences } from "@/types/preferences";
|
import type { UserPreferences } from "@/types/preferences";
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: { seriesId: string };
|
params: Promise<{ seriesId: string }>;
|
||||||
searchParams: { page?: string; unread?: string; size?: string };
|
searchParams: Promise<{ page?: string; unread?: string; size?: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function SeriesPage({ params, searchParams }: PageProps) {
|
export default async function SeriesPage({ params, searchParams }: PageProps) {
|
||||||
|
|||||||
@@ -14,27 +14,10 @@ import {
|
|||||||
Filter,
|
Filter,
|
||||||
Calendar,
|
Calendar,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import type { CacheType } from "@/lib/services/base-api.service";
|
import type { RequestTiming } from "@/types/debug";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useDebug } from "@/contexts/DebugContext";
|
import { useDebug } from "@/contexts/DebugContext";
|
||||||
|
|
||||||
interface RequestTiming {
|
|
||||||
url: string;
|
|
||||||
startTime: number;
|
|
||||||
endTime: number;
|
|
||||||
duration: number;
|
|
||||||
timestamp: string;
|
|
||||||
fromCache: boolean;
|
|
||||||
cacheType?: CacheType;
|
|
||||||
mongoAccess?: {
|
|
||||||
operation: string;
|
|
||||||
duration: number;
|
|
||||||
};
|
|
||||||
pageRender?: {
|
|
||||||
page: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatTime(timestamp: string) {
|
function formatTime(timestamp: string) {
|
||||||
const date = new Date(timestamp);
|
const date = new Date(timestamp);
|
||||||
return date.toLocaleTimeString("fr-FR", {
|
return date.toLocaleTimeString("fr-FR", {
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { HomeContent } from "./HomeContent";
|
import { HomeContent } from "./HomeContent";
|
||||||
import { HomeService } from "@/lib/services/home.service";
|
|
||||||
import { ErrorMessage } from "@/components/ui/ErrorMessage";
|
import { ErrorMessage } from "@/components/ui/ErrorMessage";
|
||||||
import { HomePageSkeleton } from "@/components/skeletons/OptimizedSkeletons";
|
import { HomePageSkeleton } from "@/components/skeletons/OptimizedSkeletons";
|
||||||
import { ERROR_CODES } from "@/constants/errorCodes";
|
import { ERROR_CODES } from "@/constants/errorCodes";
|
||||||
import type { HomeData } from "@/lib/services/home.service";
|
import type { HomeData } from "@/types/home";
|
||||||
|
|
||||||
export function ClientHomePage() {
|
export function ClientHomePage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -51,8 +50,16 @@ export function ClientHomePage() {
|
|||||||
|
|
||||||
const handleRefresh = async () => {
|
const handleRefresh = async () => {
|
||||||
try {
|
try {
|
||||||
await HomeService.invalidateHomeCache();
|
// Invalider le cache via l'API
|
||||||
|
const deleteResponse = await fetch("/api/komga/home", {
|
||||||
|
method: "DELETE",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!deleteResponse.ok) {
|
||||||
|
throw new Error("Erreur lors de l'invalidation du cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer les nouvelles données
|
||||||
const response = await fetch("/api/komga/home");
|
const response = await fetch("/api/komga/home");
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
import { HeroSection } from "./HeroSection";
|
import { HeroSection } from "./HeroSection";
|
||||||
import { MediaRow } from "./MediaRow";
|
import { MediaRow } from "./MediaRow";
|
||||||
import type { KomgaBook, KomgaSeries } from "@/types/komga";
|
import type { KomgaBook, KomgaSeries } from "@/types/komga";
|
||||||
|
import type { HomeData } from "@/types/home";
|
||||||
import { RefreshButton } from "@/components/library/RefreshButton";
|
import { RefreshButton } from "@/components/library/RefreshButton";
|
||||||
import { History, Sparkles, Clock, LibraryBig, BookOpen } from "lucide-react";
|
import { History, Sparkles, Clock, LibraryBig, BookOpen } from "lucide-react";
|
||||||
import type { HomeData } from "@/lib/services/home.service";
|
|
||||||
import { useTranslate } from "@/hooks/useTranslate";
|
import { useTranslate } from "@/hooks/useTranslate";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { createContext, useContext, useState, useEffect, ReactNode } from "react";
|
import { createContext, useContext, useState, useEffect, ReactNode } from "react";
|
||||||
import type { RequestTiming } from "@/lib/services/debug.service";
|
import type { RequestTiming } from "@/types/debug";
|
||||||
import { usePreferences } from "./PreferencesContext";
|
import { usePreferences } from "./PreferencesContext";
|
||||||
|
|
||||||
interface DebugContextType {
|
interface DebugContextType {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { AuthConfig } from "@/types/auth";
|
import type { AuthConfig } from "@/types/auth";
|
||||||
|
import type { CacheType } from "@/types/cache";
|
||||||
import { getServerCacheService } from "./server-cache.service";
|
import { getServerCacheService } from "./server-cache.service";
|
||||||
import { ConfigDBService } from "./config-db.service";
|
import { ConfigDBService } from "./config-db.service";
|
||||||
import { ERROR_CODES } from "../../constants/errorCodes";
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
@@ -8,8 +9,8 @@ import type { ServerCacheService } from "./server-cache.service";
|
|||||||
import { DebugService } from "./debug.service";
|
import { DebugService } from "./debug.service";
|
||||||
import { RequestMonitorService } from "./request-monitor.service";
|
import { RequestMonitorService } from "./request-monitor.service";
|
||||||
import { RequestQueueService } from "./request-queue.service";
|
import { RequestQueueService } from "./request-queue.service";
|
||||||
// Types de cache disponibles
|
|
||||||
export type CacheType = "DEFAULT" | "HOME" | "LIBRARIES" | "SERIES" | "BOOKS" | "IMAGES";
|
export type { CacheType };
|
||||||
|
|
||||||
interface KomgaRequestInit extends RequestInit {
|
interface KomgaRequestInit extends RequestInit {
|
||||||
isImage?: boolean;
|
isImage?: boolean;
|
||||||
@@ -87,23 +88,9 @@ export abstract class BaseApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static async resolveWithFallback(url: string): Promise<string> {
|
protected static async resolveWithFallback(url: string): Promise<string> {
|
||||||
try {
|
// DNS resolution is only needed server-side and causes build issues
|
||||||
// Essayer de résoudre le DNS d'abord
|
// The fetch API will handle DNS resolution automatically
|
||||||
const urlObj = new URL(url);
|
|
||||||
const hostname = urlObj.hostname;
|
|
||||||
|
|
||||||
// Si c'est un nom de domaine, essayer de le résoudre
|
|
||||||
if (!/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
|
|
||||||
// Vérifier si le domaine peut être résolu
|
|
||||||
const { lookup } = await import('dns').then(dns => dns.promises);
|
|
||||||
await lookup(hostname);
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
} catch (dnsError) {
|
|
||||||
console.warn(`DNS resolution failed for ${url}, using original URL:`, dnsError);
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static async fetchFromApi<T>(
|
protected static async fetchFromApi<T>(
|
||||||
|
|||||||
@@ -1,28 +1,12 @@
|
|||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import type { CacheType } from "./base-api.service";
|
import type { RequestTiming } from "@/types/debug";
|
||||||
import { PreferencesService } from "./preferences.service";
|
import { PreferencesService } from "./preferences.service";
|
||||||
import { getCurrentUser } from "../auth-utils";
|
import { getCurrentUser } from "../auth-utils";
|
||||||
import { ERROR_CODES } from "../../constants/errorCodes";
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
import { AppError } from "../../utils/errors";
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
export interface RequestTiming {
|
export type { RequestTiming };
|
||||||
url: string;
|
|
||||||
startTime: number;
|
|
||||||
endTime: number;
|
|
||||||
duration: number;
|
|
||||||
timestamp: string;
|
|
||||||
fromCache: boolean;
|
|
||||||
cacheType?: CacheType;
|
|
||||||
mongoAccess?: {
|
|
||||||
operation: string;
|
|
||||||
duration: number;
|
|
||||||
};
|
|
||||||
pageRender?: {
|
|
||||||
page: string;
|
|
||||||
duration: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DebugService {
|
export class DebugService {
|
||||||
private static writeQueues = new Map<string, Promise<void>>();
|
private static writeQueues = new Map<string, Promise<void>>();
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
import { BaseApiService } from "./base-api.service";
|
import { BaseApiService } from "./base-api.service";
|
||||||
import type { KomgaBook, KomgaSeries } from "@/types/komga";
|
import type { KomgaBook, KomgaSeries } from "@/types/komga";
|
||||||
import type { LibraryResponse } from "@/types/library";
|
import type { LibraryResponse } from "@/types/library";
|
||||||
|
import type { HomeData } from "@/types/home";
|
||||||
import { getServerCacheService } from "./server-cache.service";
|
import { getServerCacheService } from "./server-cache.service";
|
||||||
import { ERROR_CODES } from "../../constants/errorCodes";
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
import { AppError } from "../../utils/errors";
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
export interface HomeData {
|
export type { HomeData };
|
||||||
ongoing: KomgaSeries[];
|
|
||||||
ongoingBooks: KomgaBook[];
|
|
||||||
recentlyRead: KomgaBook[];
|
|
||||||
onDeck: KomgaBook[];
|
|
||||||
latestSeries: KomgaSeries[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HomeService extends BaseApiService {
|
export class HomeService extends BaseApiService {
|
||||||
static async getHomeData(): Promise<HomeData> {
|
static async getHomeData(): Promise<HomeData> {
|
||||||
|
|||||||
@@ -1,8 +1 @@
|
|||||||
export interface TTLConfig {
|
export type CacheType = "DEFAULT" | "HOME" | "LIBRARIES" | "SERIES" | "BOOKS" | "IMAGES";
|
||||||
defaultTTL: number;
|
|
||||||
homeTTL: number;
|
|
||||||
librariesTTL: number;
|
|
||||||
seriesTTL: number;
|
|
||||||
booksTTL: number;
|
|
||||||
imagesTTL: number;
|
|
||||||
}
|
|
||||||
|
|||||||
20
src/types/debug.ts
Normal file
20
src/types/debug.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import type { CacheType } from "./cache";
|
||||||
|
|
||||||
|
export interface RequestTiming {
|
||||||
|
url: string;
|
||||||
|
startTime: number;
|
||||||
|
endTime: number;
|
||||||
|
duration: number;
|
||||||
|
timestamp: string;
|
||||||
|
fromCache: boolean;
|
||||||
|
cacheType?: CacheType;
|
||||||
|
mongoAccess?: {
|
||||||
|
operation: string;
|
||||||
|
duration: number;
|
||||||
|
};
|
||||||
|
pageRender?: {
|
||||||
|
page: string;
|
||||||
|
duration: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
10
src/types/home.ts
Normal file
10
src/types/home.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import type { KomgaBook, KomgaSeries } from "./komga";
|
||||||
|
|
||||||
|
export interface HomeData {
|
||||||
|
ongoing: KomgaSeries[];
|
||||||
|
ongoingBooks: KomgaBook[];
|
||||||
|
recentlyRead: KomgaBook[];
|
||||||
|
onDeck: KomgaBook[];
|
||||||
|
latestSeries: KomgaSeries[];
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user