Compare commits

..

7 Commits

Author SHA1 Message Date
7542f42568 perf: eliminate global JS bloat and defer autoPlay video
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🧪 QA (push) Successful in 1m29s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
- Dynamically imported ToolCoordinator dependencies
- Removes ~400KB from global layout (html2canvas, framer-motion)
- Implemented IntersectionObserver in VideoSection
- Prevents 1.8MB .webm autoPlay blocking initial network
- Restored SSR hydration visibility for LCP elements in Hero
2026-02-20 00:34:08 +01:00
474fa4f3df perf: optimize PageSpeed Insights performance
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 7s
Build & Deploy / 🧪 QA (push) Successful in 1m26s
Build & Deploy / 🏗️ Build (push) Successful in 4m17s
Build & Deploy / 🚀 Deploy (push) Successful in 26s
Build & Deploy / 🧪 Smoke Test (push) Successful in 52s
Build & Deploy / ⚡ Lighthouse (push) Successful in 3m41s
Build & Deploy / 🔔 Notify (push) Successful in 2s
- Suppress browser source map references to fix 404/SyntaxErrors
- Reduce legacy JS polyfills via browserslist config
- Optimize LCP by refining Hero animations and image sizes
- Implement video lazy loading and reduce SVG animation complexity
- Add preconnect hints for critical origins
2026-02-19 23:21:01 +01:00
f1d49416d1 fix(navigation): Corrected incorrect 'Home' label in both languages
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 17s
Build & Deploy / 🧪 QA (push) Successful in 4m11s
Build & Deploy / 🏗️ Build (push) Successful in 8m43s
Build & Deploy / 🚀 Deploy (push) Successful in 25s
Build & Deploy / 🧪 Smoke Test (push) Successful in 47s
Build & Deploy / ⚡ Lighthouse (push) Successful in 3m57s
Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-02-19 21:40:20 +01:00
e3e0a7670c fix(staging): completely resolve phantom 403 imgproxy caching loops via base64, traefik routing precedence, and variable mapping
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 12s
Build & Deploy / 🧪 QA (push) Successful in 1m54s
Build & Deploy / 🏗️ Build (push) Successful in 7m44s
Build & Deploy / 🚀 Deploy (push) Successful in 30s
Build & Deploy / 🧪 Smoke Test (push) Successful in 1m2s
Build & Deploy / ⚡ Lighthouse (push) Successful in 3m17s
Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-02-19 20:06:55 +01:00
8a87318b12 fix(imgproxy): fallback to smart gravity (sm) instead of face detection (fv)
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 12s
Build & Deploy / 🧪 QA (push) Successful in 1m27s
Build & Deploy / 🏗️ Build (push) Successful in 2m56s
Build & Deploy / 🚀 Deploy (push) Successful in 29s
Build & Deploy / 🧪 Smoke Test (push) Successful in 51s
Build & Deploy / ⚡ Lighthouse (push) Successful in 4m33s
Build & Deploy / 🔔 Notify (push) Successful in 3s
- 'fv' requires ML modules not present in standard imgproxy image
- 'sm' is robust and supported everywhere
- Fixes broken images on staging using Next.js Image loader
2026-02-19 18:05:29 +01:00
93cb12d7d9 fix(imgproxy): URL-encode plain source URLs
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 13s
Build & Deploy / 🧪 QA (push) Successful in 1m49s
Build & Deploy / 🏗️ Build (push) Successful in 2m57s
Build & Deploy / 🚀 Deploy (push) Successful in 26s
Build & Deploy / 🧪 Smoke Test (push) Successful in 49s
Build & Deploy / ⚡ Lighthouse (push) Successful in 4m23s
Build & Deploy / 🔔 Notify (push) Successful in 1s
- Use encodeURIComponent for source URLs in plain/ format
- Prevents 308 redirect loops caused by double-slash normalization
- Prevents invalid URL structures for imgproxy
2026-02-19 17:15:58 +01:00
44f0c430a9 fix(infra): whitelist video files and source maps
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 7s
Build & Deploy / 🧪 QA (push) Successful in 1m28s
Build & Deploy / 🏗️ Build (push) Successful in 7m31s
Build & Deploy / 🚀 Deploy (push) Successful in 26s
Build & Deploy / 🧪 Smoke Test (push) Successful in 1m4s
Build & Deploy / ⚡ Lighthouse (push) Successful in 3m17s
Build & Deploy / 🔔 Notify (push) Successful in 2s
- Added webm, mp4, map to Traefik whitelist to bypass Gatekeeper
- Added webm, mp4, map to middleware exclusion to prevent locale redirects
- This fixes 404 errors for background videos and source maps on protected environments
2026-02-19 16:04:58 +01:00
15 changed files with 218 additions and 46 deletions

View File

@@ -112,7 +112,11 @@ export default async function Layout(props: {
return (
<html lang={safeLocale} className={`scroll-smooth overflow-x-hidden ${inter.variable}`}>
<head></head>
<head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
<link rel="preconnect" href="https://img.infra.mintel.me" />
</head>
<body className="flex flex-col min-h-screen font-sans selection:bg-accent selection:text-primary-dark antialiased overflow-x-hidden">
<NextIntlClientProvider messages={messages} locale={safeLocale}>
<RecordModeProvider isEnabled={recordModeEnabled}>

View File

@@ -137,12 +137,12 @@ const containerVariants = {
} as const;
const headingVariants = {
hidden: { opacity: 1, y: 30, scale: 0.95 },
hidden: { opacity: 1, y: 10, scale: 0.98 },
visible: {
opacity: 1,
y: 0,
scale: 1,
transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] },
transition: { duration: 0.4, ease: [0.25, 0.46, 0.45, 0.94] },
},
} as const;
@@ -167,17 +167,17 @@ const scribbleVariants = {
} as const;
const subtitleVariants = {
hidden: { opacity: 0, y: 40, scale: 0.95 },
hidden: { opacity: 1, y: 20, scale: 0.98 },
visible: {
opacity: 1,
y: 0,
scale: 1,
transition: { duration: 1, ease: [0.25, 0.46, 0.45, 0.94] },
transition: { duration: 0.6, ease: [0.25, 0.46, 0.45, 0.94], delay: 0.1 },
},
} as const;
const buttonContainerVariants = {
hidden: { opacity: 0 },
hidden: { opacity: 1 },
visible: {
opacity: 1,
transition: {
@@ -188,7 +188,7 @@ const buttonContainerVariants = {
} as const;
const buttonVariants = {
hidden: { opacity: 0, y: 30, scale: 0.9 },
hidden: { opacity: 1, y: 30, scale: 0.9 },
visible: {
opacity: 1,
y: 0,

View File

@@ -154,15 +154,15 @@ export default function HeroIllustration() {
<stop offset="70%" stopColor="white" stopOpacity="0.4" />
<stop offset="100%" stopColor="white" stopOpacity="0" />
</linearGradient>
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="3" result="blur" />
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="1.5" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<filter id="soft-glow" x="-100%" y="-100%" width="300%" height="300%">
<feGaussianBlur stdDeviation="2" result="blur" />
<filter id="soft-glow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="1" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
@@ -215,10 +215,10 @@ export default function HeroIllustration() {
</g>
{/* ANIMATED ENERGY FLOW */}
<g filter="url(#glow)">
<g>
{POWER_LINES.map((line, i) => {
// Only animate a subset of lines to reduce main-thread work
if (i % 2 !== 0) return null;
// Only animate a small subset of lines to reduce main-thread work significantly
if (i % 5 !== 0) return null;
const from = gridToScreen(line.from.col, line.from.row);
const to = gridToScreen(line.to.col, line.to.row);
const length = Math.sqrt(Math.pow(to.x - from.x, 2) + Math.pow(to.y - from.y, 2));

View File

@@ -56,7 +56,7 @@ export default function ProductCategories() {
alt={category.title}
fill
className="object-cover transition-transform duration-1000 group-hover:scale-110"
sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 25vw"
sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 24vw"
/>
<div className="absolute inset-0 bg-primary-dark/40 group-hover:bg-primary-dark/60 transition-all duration-500" />
<div className="absolute inset-0 p-8 md:p-10 flex flex-col justify-end text-white">

View File

@@ -1,30 +1,55 @@
'use client';
import React, { useState, useEffect, useRef } from 'react';
import Scribble from '@/components/Scribble';
import { useTranslations } from 'next-intl';
export default function VideoSection() {
const t = useTranslations('Home.video');
const [isVisible, setIsVisible] = useState(false);
const sectionRef = useRef<HTMLElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.disconnect();
}
},
{ rootMargin: '200px' },
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
return (
<section className="relative h-[70vh] overflow-hidden bg-primary">
<video
className="w-full h-full object-cover opacity-60"
autoPlay
muted
loop
playsInline
>
<source src="/uploads/2024/12/making-of-metal-cable-on-factory-2023-11-27-04-55-16-utc-2.webm" type="video/mp4" />
</video>
<div className="absolute inset-0 bg-gradient-to-b from-primary/60 via-transparent to-primary/60 flex items-center justify-center">
<div className="max-w-5xl px-6 text-center animate-slide-up">
<section ref={sectionRef} className="relative h-[70vh] overflow-hidden bg-primary">
{isVisible && (
<video className="w-full h-full object-cover opacity-60" autoPlay muted loop playsInline>
<source
src="/uploads/2024/12/making-of-metal-cable-on-factory-2023-11-27-04-55-16-utc-2.webm"
type="video/webm"
/>
</video>
)}
<div className="absolute inset-0 bg-gradient-to-b from-primary/60 via-transparent to-primary/60 flex items-center justify-center pointer-events-none">
<div className="max-w-5xl px-6 text-center animate-slide-up pointer-events-auto">
<h2 className="text-3xl md:text-4xl lg:text-5xl font-extrabold text-white leading-[1.1]">
{t.rich('title', {
future: (chunks) => (
<span className="relative inline-block mx-2">
<span className="relative z-10 italic text-accent">{chunks}</span>
<Scribble variant="underline" className="w-full h-4 -bottom-2 left-0 text-accent/40" />
<Scribble
variant="underline"
className="w-full h-4 -bottom-2 left-0 text-accent/40"
/>
</span>
)
),
})}
</h2>
</div>

View File

@@ -2,8 +2,17 @@
import React, { useState, useEffect } from 'react';
import { useRecordMode } from './RecordModeContext';
import { FeedbackOverlay } from '@mintel/next-feedback/FeedbackOverlay';
import { RecordModeOverlay } from './RecordModeOverlay';
import dynamic from 'next/dynamic';
const FeedbackOverlay = dynamic(
() => import('@mintel/next-feedback/FeedbackOverlay').then((mod) => mod.FeedbackOverlay),
{ ssr: false },
);
const RecordModeOverlay = dynamic(
() => import('./RecordModeOverlay').then((mod) => mod.RecordModeOverlay),
{ ssr: false },
);
import { PickingHelper } from './PickingHelper';
interface ToolCoordinatorProps {

View File

@@ -5,7 +5,7 @@ services:
dockerfile: Dockerfile
args:
NEXT_PUBLIC_BASE_URL: ${NEXT_PUBLIC_BASE_URL}
DIRECTUS_URL: ${DIRECTUS_URL}
DIRECTUS_URL: "${DIRECTUS_URL}"
image: registry.infra.mintel.me/mintel/klz-cables.com:${IMAGE_TAG:-latest}
restart: unless-stopped
networks:
@@ -32,7 +32,7 @@ services:
- "traefik.http.routers.${PROJECT_NAME:-klz}.middlewares=${AUTH_MIDDLEWARE:-klz-ratelimit,klz-forward,klz-compress}"
# Public Router (Whitelist for OG Images, Sitemaps, Health)
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.rule=(${TRAEFIK_HOST_RULE:-Host(`${TRAEFIK_HOST:-klz-cables.com}`)}) && (PathPrefix(`/health`) || PathPrefix(`/sitemap.xml`) || PathPrefix(`/robots.txt`) || PathPrefix(`/manifest.webmanifest`) || PathPrefix(`/_img`) || PathPrefix(`/api/og`) || PathPrefix(`/de/api/og`) || PathPrefix(`/en/api/og`) || PathPrefix(`/logo-white.svg`) || PathPrefix(`/icon-white.svg`) || PathPrefix(`/opengraph-image`) || PathPrefix(`/de/opengraph-image`) || PathPrefix(`/en/opengraph-image`) || PathPrefix(`/blog/opengraph-image`) || PathPrefix(`/de/blog/opengraph-image`) || PathPrefix(`/en/blog/opengraph-image`) || PathRegexp(`^/sitemap(-[0-9]+)?\\.xml$`) || PathRegexp(`.*\\.(svg|png|jpg|jpeg|gif|webp|ico)$`))"
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.rule=(${TRAEFIK_HOST_RULE:-Host(`${TRAEFIK_HOST:-klz-cables.com}`)}) && (PathPrefix(`/health`) || PathPrefix(`/sitemap.xml`) || PathPrefix(`/robots.txt`) || PathPrefix(`/manifest.webmanifest`) || PathPrefix(`/api/og`) || PathPrefix(`/de/api/og`) || PathPrefix(`/en/api/og`) || PathPrefix(`/logo-white.svg`) || PathPrefix(`/icon-white.svg`) || PathPrefix(`/opengraph-image`) || PathPrefix(`/de/opengraph-image`) || PathPrefix(`/en/opengraph-image`) || PathPrefix(`/blog/opengraph-image`) || PathPrefix(`/de/blog/opengraph-image`) || PathPrefix(`/en/blog/opengraph-image`) || PathRegexp(`^/sitemap(-[0-9]+)?\\.xml$`) || PathRegexp(`.*\\.(svg|png|jpg|jpeg|gif|webp|ico|webm|mp4|map)$`))"
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.entrypoints=${TRAEFIK_ENTRYPOINT:-web}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls=${TRAEFIK_TLS:-false}"
@@ -165,17 +165,31 @@ services:
- "cms.klz.localhost:host-gateway"
- "host.docker.internal:host-gateway"
environment:
IMGPROXY_URL_MAPPING: "${IMGPROXY_URL_MAPPING:-http://klz.localhost/:http://klz-app:3000/,http://cms.klz.localhost/:http://klz-cms:8055/}"
IMGPROXY_URL_MAPPING: "${NEXT_PUBLIC_BASE_URL}:http://klz-app:3000,${DIRECTUS_URL}:http://klz-cms:8055"
IMGPROXY_USE_ETAG: "true"
IMGPROXY_MAX_SRC_RESOLUTION: 20
IMGPROXY_IGNORE_SSL_ERRORS: "true"
IMGPROXY_DEBUG: "true"
IMGPROXY_LOG_LEVEL: debug
IMGPROXY_ALLOW_LOCAL_NETWORKS: "true"
labels:
- "traefik.enable=true"
# HTTP router (local dev)
# Existing Local HTTP Router
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy.rule=Host(`img.${TRAEFIK_HOST:-klz.localhost}`)"
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy.entrypoints=web"
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy.service=${PROJECT_NAME:-klz}-imgproxy-svc"
# NEW: Direct Public Staging Router for /_img (Bypasses Next.js rewrites)
# This fixes the Next.js URL-decoding bug on dynamic image proxy paths
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.rule=(Host(`${TRAEFIK_HOST:-klz.localhost}`) || Host(`staging.klz-cables.com`) || Host(`testing.klz-cables.com`)) && PathPrefix(`/_img`)"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.priority=99999"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.entrypoints=websecure"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.tls=true"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-le}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.service=${PROJECT_NAME:-klz}-imgproxy-svc"
- "traefik.http.services.${PROJECT_NAME:-klz}-imgproxy-svc.loadbalancer.server.port=8080"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.middlewares=${PROJECT_NAME:-klz}-img-strip"
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-img-strip.stripprefix.prefixes=/_img"
# HTTPS router (staging/prod)
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy-secure.rule=Host(`img.${TRAEFIK_HOST:-klz.localhost}`)"
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy-secure.entrypoints=${TRAEFIK_ENTRYPOINT:-web}"

View File

@@ -28,6 +28,6 @@ export default function imgproxyLoader({
return getImgproxyUrl(src, {
width,
resizing_type: 'fit',
gravity: 'fv', // Use face-aware focusing (face detection)
gravity: 'sm', // Use smart gravity (content-aware) instead of face detection (requires ML)
});
}

View File

@@ -55,10 +55,18 @@ export function getImgproxyUrl(src: string, options: ImgproxyOptions = {}): stri
`g:${gravity}`,
].join('/');
// Using /unsafe/ with plain/ source URL format
// plain/ format works reliably with imgproxy URL mapping
// Format: <base_url>/unsafe/<options>/plain/<source_url>[@<extension>]
const suffix = extension ? `@${extension}` : '';
// Using Base64 encoding for the source URL.
// This completely eliminates any risk of intermediate proxies (Traefik/Next.js)
// URL-decoding the path, which corrupts the double-slash (// to /) and causes 403 errors.
// Imgproxy expects URL-safe Base64 (RFC 4648) without padding.
const b64 =
typeof window === 'undefined'
? Buffer.from(absoluteSrc).toString('base64')
: btoa(unescape(encodeURIComponent(absoluteSrc)));
return `${baseUrl}/unsafe/${processingOptions}/plain/${absoluteSrc}${suffix}`;
const urlSafeB64 = b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
const suffix = extension ? `.${extension}` : '';
return `${baseUrl}/unsafe/${processingOptions}/${urlSafeB64}${suffix}`;
}

View File

@@ -59,7 +59,7 @@
},
"Navigation": {
"menu": "Menü",
"home": "KLZ Cables Startseite",
"home": "Startseite",
"team": "Team",
"products": "Produkte",
"blog": "Blog",

View File

@@ -59,7 +59,7 @@
},
"Navigation": {
"menu": "Menu",
"home": "KLZ Cables Home",
"home": "Home",
"team": "Team",
"products": "Products",
"blog": "Blog",

View File

@@ -95,7 +95,7 @@ export default function middleware(request: NextRequest) {
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|_img|favicon.ico|manifest.webmanifest|.*\\.(?:svg|png|jpg|jpeg|gif|webp|pdf|txt|vcf|xml)$).*)',
'/((?!api|_next/static|_next/image|_img|favicon.ico|manifest.webmanifest|.*\\.(?:svg|png|jpg|jpeg|gif|webp|pdf|txt|vcf|xml|webm|mp4|map)$).*)',
'/(de|en)/:path*',
'/(de|en)/:path*',
],

View File

@@ -1,4 +1,6 @@
import withMintelConfig from '@mintel/next-config';
import withBundleAnalyzer from '@next/bundle-analyzer';
import { withSentryConfig } from '@sentry/nextjs';
console.log('🚀 NEXT CONFIG LOADED FROM:', process.cwd());
@@ -8,6 +10,7 @@ const nextConfig = {
// Make sure entries are not disposed too quickly
maxInactiveAge: 60 * 1000,
},
productionBrowserSourceMaps: false,
logging: {
fetches: {
fullUrl: true,
@@ -353,4 +356,10 @@ const nextConfig = {
},
};
export default withMintelConfig(nextConfig);
const withAnalyzer = withBundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
});
export default withAnalyzer(withMintelConfig(nextConfig, {
hideSourceMaps: true,
}));

View File

@@ -49,6 +49,7 @@
"@lhci/cli": "^0.15.1",
"@mintel/eslint-config": "1.8.3",
"@mintel/tsconfig": "1.8.3",
"@next/bundle-analyzer": "^16.1.6",
"@remotion/cli": "^4.0.421",
"@remotion/google-fonts": "^4.0.421",
"@remotion/player": "^4.0.421",
@@ -129,6 +130,11 @@
"next": "16.1.6"
}
},
"browserslist": [
"last 3 versions",
"not dead",
"not ie 11"
],
"peerDependencies": {
"@remotion/cli": "^4.0.421",
"@remotion/google-fonts": "^4.0.421",

97
pnpm-lock.yaml generated
View File

@@ -144,6 +144,9 @@ importers:
'@mintel/tsconfig':
specifier: 1.8.3
version: 1.8.3
'@next/bundle-analyzer':
specifier: ^16.1.6
version: 16.1.6
'@remotion/cli':
specifier: ^4.0.421
version: 4.0.421(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
@@ -464,6 +467,10 @@ packages:
resolution: {integrity: sha512-Ig8zZAQDbc7QMIM54N+x71C04lni9MN9yalNAezjDjFdNknTJzupDY7V5cb+kOJL8GsqDE9Bg8xq8xCmkDVs5A==}
engines: {node: '>=22'}
'@discoveryjs/json-ext@0.5.7':
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
engines: {node: '>=10.0.0'}
'@emnapi/core@1.8.1':
resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==}
@@ -1269,6 +1276,9 @@ packages:
'@napi-rs/wasm-runtime@0.2.12':
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
'@next/bundle-analyzer@16.1.6':
resolution: {integrity: sha512-ee2kagdTaeEWPlotgdTOqFHYcD3e2m2bbE3I9Rq2i6ABYi5OgopmtEUe8NM23viaYxLV2tDH/2nd5+qKoEr6cw==}
'@next/env@16.1.6':
resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==}
@@ -3038,6 +3048,10 @@ packages:
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
acorn-walk@8.3.5:
resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==}
engines: {node: '>=0.4.0'}
acorn@8.15.0:
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
engines: {node: '>=0.4.0'}
@@ -3581,6 +3595,10 @@ packages:
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
commander@7.2.0:
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
engines: {node: '>= 10'}
commondir@1.0.1:
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
@@ -3800,6 +3818,9 @@ packages:
resolution: {integrity: sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ==}
engines: {node: '>=18'}
debounce@1.2.1:
resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==}
debounce@2.2.0:
resolution: {integrity: sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw==}
engines: {node: '>=18'}
@@ -4588,6 +4609,10 @@ packages:
resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
engines: {node: '>=6.0'}
gzip-size@6.0.0:
resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==}
engines: {node: '>=10'}
happy-dom@20.6.1:
resolution: {integrity: sha512-+0vhESXXhFwkdjZnJ5DlmJIfUYGgIEEjzIjB+aKJbFuqlvvKyOi+XkI1fYbgYR9QCxG5T08koxsQ6HrQfa5gCQ==}
engines: {node: '>=20.0.0'}
@@ -4658,6 +4683,9 @@ packages:
resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
html-parse-stringify@3.0.1:
resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
@@ -4943,6 +4971,10 @@ packages:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
is-plain-object@5.0.0:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'}
is-potential-custom-element-name@1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
@@ -5870,6 +5902,10 @@ packages:
resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
engines: {node: '>=12'}
opener@1.5.2:
resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==}
hasBin: true
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
@@ -6618,6 +6654,10 @@ packages:
simple-swizzle@0.2.4:
resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==}
sirv@2.0.4:
resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==}
engines: {node: '>= 10'}
sirv@3.0.2:
resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==}
engines: {node: '>=18'}
@@ -7332,6 +7372,11 @@ packages:
resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
engines: {node: '>=20'}
webpack-bundle-analyzer@4.10.1:
resolution: {integrity: sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==}
engines: {node: '>= 10.13.0'}
hasBin: true
webpack-sources@3.3.3:
resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==}
engines: {node: '>=10.13.0'}
@@ -7867,6 +7912,8 @@ snapshots:
'@directus/sdk@21.1.0': {}
'@discoveryjs/json-ext@0.5.7': {}
'@emnapi/core@1.8.1':
dependencies:
'@emnapi/wasi-threads': 1.1.0
@@ -8557,6 +8604,13 @@ snapshots:
'@tybys/wasm-util': 0.10.1
optional: true
'@next/bundle-analyzer@16.1.6':
dependencies:
webpack-bundle-analyzer: 4.10.1
transitivePeerDependencies:
- bufferutil
- utf-8-validate
'@next/env@16.1.6': {}
'@next/eslint-plugin-next@16.1.6':
@@ -10508,6 +10562,10 @@ snapshots:
dependencies:
acorn: 8.15.0
acorn-walk@8.3.5:
dependencies:
acorn: 8.15.0
acorn@8.15.0: {}
adler-32@1.3.1: {}
@@ -11072,6 +11130,8 @@ snapshots:
commander@2.20.3: {}
commander@7.2.0: {}
commondir@1.0.1: {}
compare-func@2.0.0:
@@ -11305,6 +11365,8 @@ snapshots:
dependencies:
mimic-function: 5.0.1
debounce@1.2.1: {}
debounce@2.2.0: {}
debug@2.6.9:
@@ -12350,6 +12412,10 @@ snapshots:
section-matter: 1.0.0
strip-bom-string: 1.0.0
gzip-size@6.0.0:
dependencies:
duplexer: 0.1.2
happy-dom@20.6.1:
dependencies:
'@types/node': 22.19.10
@@ -12457,6 +12523,8 @@ snapshots:
transitivePeerDependencies:
- '@noble/hashes'
html-escaper@2.0.2: {}
html-parse-stringify@3.0.1:
dependencies:
void-elements: 3.1.0
@@ -12758,6 +12826,8 @@ snapshots:
is-plain-obj@4.1.0: {}
is-plain-object@5.0.0: {}
is-potential-custom-element-name@1.0.1: {}
is-reference@1.2.1:
@@ -13859,6 +13929,8 @@ snapshots:
is-docker: 2.2.1
is-wsl: 2.2.0
opener@1.5.2: {}
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@@ -14853,6 +14925,12 @@ snapshots:
dependencies:
is-arrayish: 0.3.4
sirv@2.0.4:
dependencies:
'@polka/url': 1.0.0-next.29
mrmime: 2.0.1
totalist: 3.0.1
sirv@3.0.2:
dependencies:
'@polka/url': 1.0.0-next.29
@@ -15666,6 +15744,25 @@ snapshots:
webidl-conversions@8.0.1: {}
webpack-bundle-analyzer@4.10.1:
dependencies:
'@discoveryjs/json-ext': 0.5.7
acorn: 8.15.0
acorn-walk: 8.3.5
commander: 7.2.0
debounce: 1.2.1
escape-string-regexp: 4.0.0
gzip-size: 6.0.0
html-escaper: 2.0.2
is-plain-object: 5.0.0
opener: 1.5.2
picocolors: 1.1.1
sirv: 2.0.4
ws: 7.5.10
transitivePeerDependencies:
- bufferutil
- utf-8-validate
webpack-sources@3.3.3: {}
webpack-virtual-modules@0.5.0: {}