fix(og-image): resolve 404s, migrate middleware to proxy.ts, and fix local port conflict
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 14s
Build & Deploy / 🧪 QA (push) Successful in 1m40s
Build & Deploy / 🏗️ Build (push) Successful in 3m59s
Build & Deploy / 🚀 Deploy (push) Successful in 30s
Build & Deploy / 🧪 Smoke Test (push) Failing after 52s
Build & Deploy / 🔔 Notify (push) Successful in 2s

This commit is contained in:
2026-02-17 01:31:13 +01:00
parent 7e6b4a3ed7
commit 28072908f7
13 changed files with 38 additions and 21 deletions

View File

@@ -3,6 +3,8 @@ import { getPageBySlug } from '@/lib/pages';
import { OGImageTemplate } from '@/components/OGImageTemplate'; import { OGImageTemplate } from '@/components/OGImageTemplate';
import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper'; import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper';
export const size = OG_IMAGE_SIZE;
export const contentType = 'image/png';
export const runtime = 'nodejs'; export const runtime = 'nodejs';
export default async function Image({ export default async function Image({

View File

@@ -4,6 +4,8 @@ import { OGImageTemplate } from '@/components/OGImageTemplate';
import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper'; import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper';
import { SITE_URL } from '@/lib/schema'; import { SITE_URL } from '@/lib/schema';
export const size = OG_IMAGE_SIZE;
export const contentType = 'image/png';
export const runtime = 'nodejs'; export const runtime = 'nodejs';
export default async function Image({ export default async function Image({

View File

@@ -3,6 +3,8 @@ import { getTranslations } from 'next-intl/server';
import { OGImageTemplate } from '@/components/OGImageTemplate'; import { OGImageTemplate } from '@/components/OGImageTemplate';
import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper'; import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper';
export const size = OG_IMAGE_SIZE;
export const contentType = 'image/png';
export const runtime = 'nodejs'; export const runtime = 'nodejs';
export default async function Image({ params }: { params: Promise<{ locale: string }> }) { export default async function Image({ params }: { params: Promise<{ locale: string }> }) {

View File

@@ -3,6 +3,8 @@ import { getTranslations } from 'next-intl/server';
import { OGImageTemplate } from '@/components/OGImageTemplate'; import { OGImageTemplate } from '@/components/OGImageTemplate';
import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper'; import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper';
export const size = OG_IMAGE_SIZE;
export const contentType = 'image/png';
export const runtime = 'nodejs'; export const runtime = 'nodejs';
export default async function Image({ params }: { params: Promise<{ locale: string }> }) { export default async function Image({ params }: { params: Promise<{ locale: string }> }) {

View File

@@ -43,15 +43,13 @@ export const viewport: Viewport = {
themeColor: '#001a4d', themeColor: '#001a4d',
}; };
export default async function LocaleLayout({ export default async function Layout(props: {
children,
params,
}: {
children: React.ReactNode; children: React.ReactNode;
params: Promise<{ locale: string }>; params: Promise<{ locale: string }>;
}) { }) {
const { locale } = await params; const params = await props.params;
const { locale } = params;
const { children } = props;
const supportedLocales = ['en', 'de']; const supportedLocales = ['en', 'de'];
const localeStr = (typeof locale === 'string' ? locale : '').trim(); const localeStr = (typeof locale === 'string' ? locale : '').trim();
const safeLocale = supportedLocales.includes(localeStr) ? localeStr : 'en'; const safeLocale = supportedLocales.includes(localeStr) ? localeStr : 'en';

View File

@@ -3,9 +3,12 @@ import { getTranslations } from 'next-intl/server';
import { OGImageTemplate } from '@/components/OGImageTemplate'; import { OGImageTemplate } from '@/components/OGImageTemplate';
import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper'; import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper';
export const size = OG_IMAGE_SIZE;
export const contentType = 'image/png';
export const runtime = 'nodejs'; export const runtime = 'nodejs';
export default async function Image({ params }: { params: Promise<{ locale: string }> }) { export default async function Image({ params }: { params: Promise<{ locale: string }> }) {
console.log('🖼️ OG Image Handler Called');
const { locale } = await params; const { locale } = await params;
const t = await getTranslations({ locale, namespace: 'Index.meta' }); const t = await getTranslations({ locale, namespace: 'Index.meta' });
const fonts = await getOgFonts(); const fonts = await getOgFonts();

View File

@@ -3,6 +3,8 @@ import { getTranslations } from 'next-intl/server';
import { OGImageTemplate } from '@/components/OGImageTemplate'; import { OGImageTemplate } from '@/components/OGImageTemplate';
import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper'; import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper';
export const size = OG_IMAGE_SIZE;
export const contentType = 'image/png';
export const runtime = 'nodejs'; export const runtime = 'nodejs';
export default async function Image({ params }: { params: Promise<{ locale: string }> }) { export default async function Image({ params }: { params: Promise<{ locale: string }> }) {

View File

@@ -3,6 +3,8 @@ import { getTranslations } from 'next-intl/server';
import { OGImageTemplate } from '@/components/OGImageTemplate'; import { OGImageTemplate } from '@/components/OGImageTemplate';
import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper'; import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper';
export const size = OG_IMAGE_SIZE;
export const contentType = 'image/png';
export const runtime = 'nodejs'; export const runtime = 'nodejs';
export default async function Image({ params }: { params: Promise<{ locale: string }> }) { export default async function Image({ params }: { params: Promise<{ locale: string }> }) {

View File

@@ -9,8 +9,10 @@ services:
image: registry.infra.mintel.me/mintel/klz-cables.com:${IMAGE_TAG:-latest} image: registry.infra.mintel.me/mintel/klz-cables.com:${IMAGE_TAG:-latest}
restart: unless-stopped restart: unless-stopped
networks: networks:
- default default:
- infra infra:
aliases:
- klz.localhost
env_file: env_file:
- ${ENV_FILE:-.env} - ${ENV_FILE:-.env}
labels: labels:

2
next-env.d.ts vendored
View File

@@ -1,6 +1,6 @@
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts"; import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View File

@@ -1,10 +1,18 @@
import createNextIntlPlugin from 'next-intl/plugin';
import withMintelConfig from '@mintel/next-config'; import withMintelConfig from '@mintel/next-config';
const withNextIntl = createNextIntlPlugin(); console.log('🚀 NEXT CONFIG LOADED FROM:', process.cwd());
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
onDemandEntries: {
// Make sure entries are not disposed too quickly
maxInactiveAge: 60 * 1000,
},
logging: {
fetches: {
fullUrl: true,
},
},
output: 'standalone', output: 'standalone',
async redirects() { async redirects() {
return [ return [
@@ -342,6 +350,4 @@ const nextConfig = {
}, },
}; };
const nextIntlConfig = withNextIntl(nextConfig); export default withMintelConfig(nextConfig);
export default withMintelConfig(nextIntlConfig);

View File

@@ -42,11 +42,8 @@ export default function middleware(request: NextRequest) {
// Prioritize x-forwarded-host (passed by Traefik) over the local Host header // Prioritize x-forwarded-host (passed by Traefik) over the local Host header
const hostHeader = const hostHeader =
headers.get('x-forwarded-host') || headers.get('host') || 'testing.klz-cables.com'; headers.get('x-forwarded-host') || headers.get('host') || 'testing.klz-cables.com';
hostHeader.split(':');
urlObj.protocol = proto; urlObj.protocol = proto;
// urlObj.hostname = publicHostname; // Don't rewrite hostname yet as it breaks internal fetches in dev
// urlObj.port = ''; // DON'T clear internal port (3000) anymore
effectiveRequest = new NextRequest(urlObj, { effectiveRequest = new NextRequest(urlObj, {
headers: request.headers, headers: request.headers,
@@ -55,7 +52,7 @@ export default function middleware(request: NextRequest) {
}); });
console.log( console.log(
`🛡️ Middleware: Fixed internal URL leak: ${url} -> ${urlObj.toString()} | Proto: ${proto} | Host: ${hostHeader}`, `🛡️ Proxy: Fixed internal URL leak: ${url} -> ${urlObj.toString()} | Proto: ${proto} | Host: ${hostHeader}`,
); );
} }
@@ -95,6 +92,5 @@ export default function middleware(request: NextRequest) {
} }
export const config = { export const config = {
// Match only internationalized pathnames matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
matcher: ['/((?!api|_next|_vercel|.*\\..*).*)', '/', '/(de|en)/:path*'],
}; };

View File

@@ -22,7 +22,7 @@ async function verifyImage(path: string): Promise<boolean> {
console.log(`Checking ${url}...`); console.log(`Checking ${url}...`);
const body = await response.text(); const body = await response.clone().text();
const contentType = response.headers.get('content-type'); const contentType = response.headers.get('content-type');
if (response.status !== 200) { if (response.status !== 200) {