refactor: modify layout to use ClientOnly and BackgroundBlobsClient components fix: correct import statement for ActivityFeed in the main page fix: enhance sitemap fetching logic with error handling and mock support refactor: convert BackgroundBlobs to default export for consistency refactor: simplify ErrorBoundary component and improve error handling UI chore: update framer-motion to version 12.24.10 in package.json and package-lock.json test: add minimal Prisma Client mock for testing purposes feat: create BackgroundBlobsClient for dynamic import of BackgroundBlobs feat: implement ClientOnly component to handle client-side rendering feat: add custom error handling components for better user experience
72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import http from "http";
|
|
import NodeCache from "node-cache";
|
|
|
|
// Use a dynamic import for node-fetch so tests that mock it (via jest.mock) are respected
|
|
async function getFetch() {
|
|
try {
|
|
const mod = await import("node-fetch");
|
|
// support both CJS and ESM interop
|
|
return (mod as any).default ?? mod;
|
|
} catch (err) {
|
|
return (globalThis as any).fetch;
|
|
}
|
|
}
|
|
|
|
export const runtime = "nodejs"; // Force Node runtime
|
|
|
|
const GHOST_API_URL = process.env.GHOST_API_URL;
|
|
const GHOST_API_KEY = process.env.GHOST_API_KEY;
|
|
const cache = new NodeCache({ stdTTL: 300 }); // Cache für 5 Minuten
|
|
|
|
type GhostPost = {
|
|
slug: string;
|
|
id: string;
|
|
title: string;
|
|
feature_image: string;
|
|
visibility: string;
|
|
published_at: string;
|
|
updated_at: string;
|
|
html: string;
|
|
reading_time: number;
|
|
meta_description: string;
|
|
};
|
|
|
|
type GhostPostsResponse = {
|
|
posts: Array<GhostPost>;
|
|
};
|
|
|
|
export async function GET() {
|
|
const cacheKey = "ghostPosts";
|
|
const cachedPosts = cache.get<GhostPostsResponse>(cacheKey);
|
|
|
|
if (cachedPosts) {
|
|
return NextResponse.json(cachedPosts);
|
|
}
|
|
|
|
try {
|
|
const agent = new http.Agent({ keepAlive: true });
|
|
const fetchFn = await getFetch();
|
|
const response = await fetchFn(
|
|
`${GHOST_API_URL}/ghost/api/content/posts/?key=${GHOST_API_KEY}&limit=all`,
|
|
{ agent: agent as unknown as undefined }
|
|
);
|
|
const posts: GhostPostsResponse = await response.json() as GhostPostsResponse;
|
|
|
|
if (!posts || !posts.posts) {
|
|
console.error("Invalid posts data");
|
|
return NextResponse.json([]);
|
|
}
|
|
|
|
cache.set(cacheKey, posts); // Daten im Cache speichern
|
|
|
|
return NextResponse.json(posts);
|
|
} catch (error) {
|
|
console.error("Failed to fetch posts from Ghost:", error);
|
|
return NextResponse.json(
|
|
{ error: "Failed to fetch projects" },
|
|
{ status: 500 },
|
|
);
|
|
}
|
|
}
|