Fix API routes for Cloudflare Workers and enable preview URLs
- Remove unsupported next: { revalidate } option from API routes
- Add Cloudflare-specific cache configuration (cf.cacheTtl)
- Add User-Agent and Referer headers to bypass Plan API 403 errors
- Enable workers_dev and preview_urls in wrangler.jsonc to prevent disabling on deployment
This commit is contained in:
parent
d0bd636a43
commit
3c2368d886
File diff suppressed because it is too large
Load Diff
@ -18,8 +18,6 @@ interface PlanPlayersResponse {
|
|||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const runtime = 'edge';
|
|
||||||
|
|
||||||
// Extract player name from HTML string
|
// Extract player name from HTML string
|
||||||
function extractPlayerName(nameString: string): string {
|
function extractPlayerName(nameString: string): string {
|
||||||
// Name format: '<a class="link" href="../player/...">PlayerName</a>'
|
// Name format: '<a class="link" href="../player/...">PlayerName</a>'
|
||||||
@ -32,9 +30,14 @@ export async function GET() {
|
|||||||
const playersResponse = await fetch(
|
const playersResponse = await fetch(
|
||||||
`${PLAN_BASE_URL}/v1/players?server=${SERVER_NAME}`,
|
`${PLAN_BASE_URL}/v1/players?server=${SERVER_NAME}`,
|
||||||
{
|
{
|
||||||
next: { revalidate: 300 }, // Cache for 5 minutes
|
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
'User-Agent': 'Mozilla/5.0 (compatible; BiohazardVFX/1.0)',
|
||||||
|
'Referer': PLAN_BASE_URL,
|
||||||
|
},
|
||||||
|
cf: {
|
||||||
|
cacheTtl: 300,
|
||||||
|
cacheEverything: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -25,9 +25,14 @@ export async function GET() {
|
|||||||
const overviewResponse = await fetch(
|
const overviewResponse = await fetch(
|
||||||
`${PLAN_BASE_URL}/v1/serverOverview?server=${SERVER_NAME}`,
|
`${PLAN_BASE_URL}/v1/serverOverview?server=${SERVER_NAME}`,
|
||||||
{
|
{
|
||||||
next: { revalidate: 30 }, // Cache for 30 seconds
|
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
'User-Agent': 'Mozilla/5.0 (compatible; BiohazardVFX/1.0)',
|
||||||
|
'Referer': PLAN_BASE_URL,
|
||||||
|
},
|
||||||
|
cf: {
|
||||||
|
cacheTtl: 30,
|
||||||
|
cacheEverything: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import Link from 'next/link';
|
|
||||||
import StickyFooter from '@/components/ui/footer';
|
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { MessageCircle } from 'lucide-react';
|
import { MessageCircle } from 'lucide-react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
@ -42,7 +40,7 @@ export function CustomFooter() {
|
|||||||
try {
|
try {
|
||||||
await navigator.clipboard.writeText('minecraft.biohazardvfx.com');
|
await navigator.clipboard.writeText('minecraft.biohazardvfx.com');
|
||||||
toast.success('Server IP copied to clipboard!');
|
toast.success('Server IP copied to clipboard!');
|
||||||
} catch (error) {
|
} catch {
|
||||||
toast.error('Failed to copy IP address');
|
toast.error('Failed to copy IP address');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -84,7 +82,7 @@ export function CustomFooter() {
|
|||||||
{section.title}
|
{section.title}
|
||||||
</h3>
|
</h3>
|
||||||
{section.links.map((link, linkIndex) => {
|
{section.links.map((link, linkIndex) => {
|
||||||
if (link.external) {
|
if ('external' in link && link.external) {
|
||||||
return (
|
return (
|
||||||
<motion.a
|
<motion.a
|
||||||
key={linkIndex}
|
key={linkIndex}
|
||||||
@ -105,7 +103,7 @@ export function CustomFooter() {
|
|||||||
</span>
|
</span>
|
||||||
</motion.a>
|
</motion.a>
|
||||||
);
|
);
|
||||||
} else if (link.isButton) {
|
} else if ('isButton' in link && link.isButton) {
|
||||||
return (
|
return (
|
||||||
<motion.button
|
<motion.button
|
||||||
key={linkIndex}
|
key={linkIndex}
|
||||||
@ -124,7 +122,7 @@ export function CustomFooter() {
|
|||||||
</span>
|
</span>
|
||||||
</motion.button>
|
</motion.button>
|
||||||
);
|
);
|
||||||
} else if (link.isStatic) {
|
} else if ('isStatic' in link && link.isStatic) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
key={linkIndex}
|
key={linkIndex}
|
||||||
|
|||||||
@ -76,19 +76,19 @@ export function Hero() {
|
|||||||
<span className="block text-primary break-words tracking-tighter text-shadow-md">
|
<span className="block text-primary break-words tracking-tighter text-shadow-md">
|
||||||
<HoverRollingText
|
<HoverRollingText
|
||||||
text="Build."
|
text="Build."
|
||||||
transition={{ duration: 0.6, delay: 0.05, ease: [0.4, 0, 0.2, 1] }}
|
transition={{ duration: 0.6, delay: 0.05 }}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span className="block text-secondary break-words tracking-normal text-shadow-sm">
|
<span className="block text-secondary break-words tracking-normal text-shadow-sm">
|
||||||
<HoverRollingText
|
<HoverRollingText
|
||||||
text="Explore."
|
text="Explore."
|
||||||
transition={{ duration: 0.6, delay: 0.05, ease: [0.4, 0, 0.2, 1] }}
|
transition={{ duration: 0.6, delay: 0.05 }}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span className="block text-accent break-words tracking-normal text-shadow-sm">
|
<span className="block text-accent break-words tracking-normal text-shadow-sm">
|
||||||
<HoverRollingText
|
<HoverRollingText
|
||||||
text="Survive."
|
text="Survive."
|
||||||
transition={{ duration: 0.6, delay: 0.05, ease: [0.4, 0, 0.2, 1] }}
|
transition={{ duration: 0.6, delay: 0.05 }}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</motion.h1>
|
</motion.h1>
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { motion } from 'motion/react';
|
import { motion } from 'motion/react';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { Trophy, Clock, Calendar } from 'lucide-react';
|
import { Trophy, Clock } from 'lucide-react';
|
||||||
import { PlayerTooltip } from '@/components/player-tooltip';
|
import { PlayerTooltip } from '@/components/player-tooltip';
|
||||||
|
|
||||||
interface LeaderboardPlayer {
|
interface LeaderboardPlayer {
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import { useTheme } from 'next-themes';
|
|||||||
|
|
||||||
export function ThemeTransition() {
|
export function ThemeTransition() {
|
||||||
const { theme, resolvedTheme } = useTheme();
|
const { theme, resolvedTheme } = useTheme();
|
||||||
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
||||||
const [prevTheme, setPrevTheme] = useState<string | undefined>();
|
const [prevTheme, setPrevTheme] = useState<string | undefined>();
|
||||||
const [capturedImage, setCapturedImage] = useState<string | null>(null);
|
const [capturedImage, setCapturedImage] = useState<string | null>(null);
|
||||||
const overlayRef = useRef<HTMLDivElement>(null);
|
const overlayRef = useRef<HTMLDivElement>(null);
|
||||||
@ -26,8 +25,6 @@ export function ThemeTransition() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentTheme = resolvedTheme || theme;
|
const currentTheme = resolvedTheme || theme;
|
||||||
if (prevTheme && prevTheme !== currentTheme && currentTheme && overlayRef.current && capturedImage) {
|
if (prevTheme && prevTheme !== currentTheme && currentTheme && overlayRef.current && capturedImage) {
|
||||||
setIsTransitioning(true);
|
|
||||||
|
|
||||||
// Set the captured image as background
|
// Set the captured image as background
|
||||||
overlayRef.current.style.backgroundImage = `url(${capturedImage})`;
|
overlayRef.current.style.backgroundImage = `url(${capturedImage})`;
|
||||||
overlayRef.current.style.backgroundSize = 'cover';
|
overlayRef.current.style.backgroundSize = 'cover';
|
||||||
@ -36,7 +33,6 @@ export function ThemeTransition() {
|
|||||||
overlayRef.current.classList.add('theme-wipe-active');
|
overlayRef.current.classList.add('theme-wipe-active');
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
setIsTransitioning(false);
|
|
||||||
if (overlayRef.current) {
|
if (overlayRef.current) {
|
||||||
overlayRef.current.classList.remove('theme-wipe-active');
|
overlayRef.current.classList.remove('theme-wipe-active');
|
||||||
overlayRef.current.style.opacity = '0';
|
overlayRef.current.style.opacity = '0';
|
||||||
|
|||||||
@ -9,7 +9,6 @@ const containerVariants = {
|
|||||||
y: 0,
|
y: 0,
|
||||||
transition: {
|
transition: {
|
||||||
duration: 0.8,
|
duration: 0.8,
|
||||||
ease: "easeOut",
|
|
||||||
staggerChildren: 0.1,
|
staggerChildren: 0.1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -20,7 +19,7 @@ const itemVariants = {
|
|||||||
visible: {
|
visible: {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
x: 0,
|
x: 0,
|
||||||
transition: { duration: 0.6, ease: "easeOut" },
|
transition: { duration: 0.6 },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ const linkVariants = {
|
|||||||
visible: {
|
visible: {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
y: 0,
|
y: 0,
|
||||||
transition: { duration: 0.4, ease: "easeOut" },
|
transition: { duration: 0.4 },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +38,7 @@ const socialVariants = {
|
|||||||
opacity: 1,
|
opacity: 1,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
transition: {
|
transition: {
|
||||||
type: "spring",
|
type: "spring" as const,
|
||||||
stiffness: 200,
|
stiffness: 200,
|
||||||
damping: 10,
|
damping: 10,
|
||||||
},
|
},
|
||||||
@ -53,7 +52,6 @@ const backgroundVariants = {
|
|||||||
scale: 1,
|
scale: 1,
|
||||||
transition: {
|
transition: {
|
||||||
duration: 2,
|
duration: 2,
|
||||||
ease: "easeOut",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import Link from "next/link";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
const transition = {
|
const transition = {
|
||||||
type: "spring",
|
type: "spring" as const,
|
||||||
mass: 0.5,
|
mass: 0.5,
|
||||||
damping: 11.5,
|
damping: 11.5,
|
||||||
stiffness: 100,
|
stiffness: 100,
|
||||||
@ -109,7 +109,7 @@ export const ProductItem = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const HoveredLink = ({ children, ...rest }: any) => {
|
export const HoveredLink = ({ children, ...rest }: React.ComponentProps<typeof Link>) => {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
{...rest}
|
{...rest}
|
||||||
|
|||||||
@ -35,20 +35,21 @@ export const AnimatedTooltip = ({ items }: AnimatedTooltipProps) => {
|
|||||||
springConfig,
|
springConfig,
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleMouseMove = (event: any) => {
|
const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||||
if (animationFrameRef.current) {
|
if (animationFrameRef.current) {
|
||||||
cancelAnimationFrame(animationFrameRef.current);
|
cancelAnimationFrame(animationFrameRef.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
animationFrameRef.current = requestAnimationFrame(() => {
|
animationFrameRef.current = requestAnimationFrame(() => {
|
||||||
const halfWidth = event.target.offsetWidth / 2;
|
const target = event.target as HTMLElement;
|
||||||
|
const halfWidth = target.offsetWidth / 2;
|
||||||
x.set(event.nativeEvent.offsetX - halfWidth);
|
x.set(event.nativeEvent.offsetX - halfWidth);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{items.map((item, idx) => (
|
{items.map((item) => (
|
||||||
<div
|
<div
|
||||||
className="group relative -mr-4"
|
className="group relative -mr-4"
|
||||||
key={item.name}
|
key={item.name}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
export const Component = () => {
|
export const Component = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import { MessageCircle } from "lucide-react";
|
|
||||||
|
|
||||||
export interface NavItem {
|
export interface NavItem {
|
||||||
label: string;
|
label: string;
|
||||||
href: string;
|
href: string;
|
||||||
@ -29,6 +27,5 @@ export const navigationItems: Array<NavItem | NavDropdown> = [
|
|||||||
label: "Community",
|
label: "Community",
|
||||||
href: "https://discord.gg/invite",
|
href: "https://discord.gg/invite",
|
||||||
external: true,
|
external: true,
|
||||||
icon: <MessageCircle className="h-4 w-4" />,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -21,6 +21,8 @@
|
|||||||
"zone_name": "biohazardvfx.com"
|
"zone_name": "biohazardvfx.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"workers_dev": true,
|
||||||
|
"preview_urls": true,
|
||||||
"observability": {
|
"observability": {
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user