diff --git a/apps/cms/next.config.mjs b/apps/cms/next.config.mjs index 3317297c82..092c737bfb 100644 --- a/apps/cms/next.config.mjs +++ b/apps/cms/next.config.mjs @@ -47,10 +47,6 @@ const nextConfig = { // We are already running linting via GH action, this will skip linting during production build on Vercel ignoreDuringBuilds: true, }, - experimental: { - // Ensure compatibility with Turbopack and Sharp - serverComponentsExternalPackages: ['sharp'], - }, // Configure Sharp as an external package for server-side rendering serverExternalPackages: ['sharp'], } diff --git a/apps/cms/package.json b/apps/cms/package.json index 13e5841a04..b4d5728204 100644 --- a/apps/cms/package.json +++ b/apps/cms/package.json @@ -15,7 +15,7 @@ "lint": "cross-env NODE_OPTIONS=--no-deprecation next lint", "migrate": "cross-env NODE_OPTIONS=--no-deprecation tsx scripts/migrate.ts", "payload": "cross-env NODE_OPTIONS=--no-deprecation payload", - "start": "cross-env NODE_OPTIONS=--no-deprecation next start --port 3030", + "start": "cross-env NODE_OPTIONS=--no-deprecation next start", "vercel-build": "pnpm migrate && pnpm build", "typecheck_IGNORED": "tsc --noEmit" }, diff --git a/apps/cms/src/app/(payload)/api/graphql-playground/route.ts b/apps/cms/src/app/(payload)/api/graphql-playground/route.ts deleted file mode 100644 index 17d2954ca2..0000000000 --- a/apps/cms/src/app/(payload)/api/graphql-playground/route.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ -/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ -import config from '@payload-config' -import '@payloadcms/next/css' -import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes' - -export const GET = GRAPHQL_PLAYGROUND_GET(config) diff --git a/apps/cms/src/app/(payload)/api/graphql/route.ts b/apps/cms/src/app/(payload)/api/graphql/route.ts deleted file mode 100644 index 2069ff86b0..0000000000 --- a/apps/cms/src/app/(payload)/api/graphql/route.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ -/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ -import config from '@payload-config' -import { GRAPHQL_POST, REST_OPTIONS } from '@payloadcms/next/routes' - -export const POST = GRAPHQL_POST(config) - -export const OPTIONS = REST_OPTIONS(config) diff --git a/apps/cms/src/payload.config.ts b/apps/cms/src/payload.config.ts index 8858ce58a5..8e7a31c40d 100644 --- a/apps/cms/src/payload.config.ts +++ b/apps/cms/src/payload.config.ts @@ -102,7 +102,7 @@ export default buildConfig({ // Global configuration for better performance globals: [], graphQL: { - disable: process.env.NODE_ENV !== 'development', // Disable GraphQL in production for better performance + disable: true, }, // Reduce payload init overhead telemetry: false, diff --git a/apps/www/app/api-v2/cms-posts/route.ts b/apps/www/app/api-v2/cms-posts/route.ts index 2243cab04d..04f64cf768 100644 --- a/apps/www/app/api-v2/cms-posts/route.ts +++ b/apps/www/app/api-v2/cms-posts/route.ts @@ -6,6 +6,12 @@ import { generateReadingTime } from '~/lib/helpers' // Lightweight runtime for better performance export const runtime = 'edge' +// CORS headers for cross-origin requests +const corsHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', +} + // Lightweight TOC generation for edge runtime type TocItem = { content: string; slug: string; lvl: number } @@ -115,6 +121,14 @@ function convertRichTextToMarkdown(content: any): string { .join('\n\n') } +// Handle preflight requests +export async function OPTIONS() { + return new Response(null, { + status: 200, + headers: corsHeaders, + }) +} + export async function GET(request: NextRequest) { try { const { searchParams } = new URL(request.url) @@ -212,12 +226,15 @@ export async function GET(request: NextRequest) { _status: latestVersion._status, } - return NextResponse.json({ - success: true, - post: processedPost, - mode, - isDraft: shouldFetchDraft, - }) + return NextResponse.json( + { + success: true, + post: processedPost, + mode, + isDraft: shouldFetchDraft, + }, + { headers: corsHeaders } + ) } } } @@ -289,12 +306,15 @@ export async function GET(request: NextRequest) { _status: post._status, } - return NextResponse.json({ - success: true, - post: processedPost, - mode, - isDraft: shouldFetchDraft, - }) + return NextResponse.json( + { + success: true, + post: processedPost, + mode, + isDraft: shouldFetchDraft, + }, + { headers: corsHeaders } + ) } } @@ -364,12 +384,15 @@ export async function GET(request: NextRequest) { _status: post._status, } - return NextResponse.json({ - success: true, - post: processedPost, - mode, - isDraft: shouldFetchDraft, - }) + return NextResponse.json( + { + success: true, + post: processedPost, + mode, + isDraft: shouldFetchDraft, + }, + { headers: corsHeaders } + ) } } } @@ -452,16 +475,21 @@ export async function GET(request: NextRequest) { toc_depth: post.toc_depth || 3, } - return NextResponse.json({ - success: true, - post: processedPost, - mode, - source: 'versions-api', - }) + return NextResponse.json( + { + success: true, + post: processedPost, + mode, + source: 'versions-api', + }, + { headers: corsHeaders } + ) } } } else { - console.log('[cms-posts] Versions API failed, response:', await versionsResponse.text()) + if (process.env.NODE_ENV !== 'production') { + console.log('[cms-posts] Versions API failed, response:', await versionsResponse.text()) + } } // Strategy 2: If versions API didn't work, try finding the parent post first, then get its latest published version @@ -556,12 +584,15 @@ export async function GET(request: NextRequest) { richContent: mode === 'full' ? post.content : undefined, } - return NextResponse.json({ - success: true, - post: processedPost, - mode, - source: 'versions-by-parent-api', - }) + return NextResponse.json( + { + success: true, + post: processedPost, + mode, + source: 'versions-by-parent-api', + }, + { headers: corsHeaders } + ) } } } @@ -590,6 +621,12 @@ export async function GET(request: NextRequest) { // For individual post requests, don't cache to ensure fresh data cache: slug ? 'no-store' : 'default', next: slug ? undefined : { revalidate: 300 }, + // Add SSL configuration for production + ...(process.env.NODE_ENV === 'production' && { + // Allow self-signed certificates in development, but use proper SSL in production + // This helps with Vercel's internal networking + agent: false, + }), }) if (!response.ok) { @@ -600,7 +637,7 @@ export async function GET(request: NextRequest) { error: 'Failed to fetch posts from CMS', status: response.status, }, - { status: response.status } + { status: response.status, headers: corsHeaders } ) } @@ -613,7 +650,7 @@ export async function GET(request: NextRequest) { error: 'CMS returned non-JSON response', contentType, }, - { status: 502 } + { status: 502, headers: corsHeaders } ) } @@ -695,20 +732,26 @@ export async function GET(request: NextRequest) { // For single post requests, return the post directly if (slug && posts.length > 0) { - return NextResponse.json({ - success: true, - post: posts[0], - mode, - }) + return NextResponse.json( + { + success: true, + post: posts[0], + mode, + }, + { headers: corsHeaders } + ) } - return NextResponse.json({ - success: true, - posts, - total: posts.length, - mode, - cached: true, - }) + return NextResponse.json( + { + success: true, + posts, + total: posts.length, + mode, + cached: true, + }, + { headers: corsHeaders } + ) } catch (error) { console.error('[cms-posts] Error:', error) return NextResponse.json( @@ -717,7 +760,7 @@ export async function GET(request: NextRequest) { error: 'Internal server error', message: error instanceof Error ? error.message : 'Unknown error', }, - { status: 500 } + { status: 500, headers: corsHeaders } ) } } diff --git a/apps/www/app/api-v2/cms/revalidate/route.ts b/apps/www/app/api-v2/cms/revalidate/route.ts index b743c4870d..3ff73f9e8d 100644 --- a/apps/www/app/api-v2/cms/revalidate/route.ts +++ b/apps/www/app/api-v2/cms/revalidate/route.ts @@ -1,27 +1,32 @@ -import type { NextApiRequest, NextApiResponse } from 'next' - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - // Check for secret to confirm this is a valid request - if (req.query.secret !== process.env.CMS_PREVIEW_SECRET) { - return res.status(401).json({ message: 'Invalid token' }) - } - - const { path } = req.query - - if (!path) { - return res.status(400).json({ message: 'Missing path parameter' }) - } +import { revalidatePath } from 'next/cache' +import { NextRequest, NextResponse } from 'next/server' +export async function POST(request: NextRequest) { try { - // This will revalidate the specific page - await res.revalidate(String(path)) + const body = await request.json() + const { secret, path } = body - return res.json({ revalidated: true, path }) + // Check for secret to confirm this is a valid request + if (secret !== process.env.CMS_PREVIEW_SECRET) { + return NextResponse.json({ message: 'Invalid token' }, { status: 401 }) + } + + if (!path) { + return NextResponse.json({ message: 'Missing path parameter' }, { status: 400 }) + } + + // This will revalidate the specific page + revalidatePath(path) + + return NextResponse.json({ revalidated: true, path }) } catch (error) { console.error('[Revalidate API] Error during revalidation:', error) - return res.status(500).json({ - message: 'Error revalidating', - error: error instanceof Error ? error.message : 'Unknown error', - }) + return NextResponse.json( + { + message: 'Error revalidating', + error: error instanceof Error ? error.message : 'Unknown error', + }, + { status: 500 } + ) } } diff --git a/apps/www/app/api-v2/ticket-og/route.tsx b/apps/www/app/api-v2/ticket-og/route.tsx index 6c9ba7807a..46b216f66f 100644 --- a/apps/www/app/api-v2/ticket-og/route.tsx +++ b/apps/www/app/api-v2/ticket-og/route.tsx @@ -24,7 +24,7 @@ const FONT_URLS = { const LW_TABLE = 'tickets' const LW_MATERIALIZED_VIEW = 'tickets_view' -export async function GET(req: Request, res: Response) { +export async function GET(req: Request) { const url = new URL(req.url) // Just here to silence snyk false positives diff --git a/apps/www/app/blog/[slug]/page.tsx b/apps/www/app/blog/[slug]/page.tsx index 7f142ae402..dd3ce29f66 100644 --- a/apps/www/app/blog/[slug]/page.tsx +++ b/apps/www/app/blog/[slug]/page.tsx @@ -28,7 +28,7 @@ async function getCMSPostFromAPI( const fetchOptions = isDraft ? { // For draft mode: always fresh data, no caching - cache: 'no-store' as const, + // cache: 'no-store' as const, next: { revalidate: 0 }, } : { diff --git a/apps/www/app/blog/categories/[category]/page.tsx b/apps/www/app/blog/categories/[category]/page.tsx index edafaa817a..b0c8f9ab3b 100644 --- a/apps/www/app/blog/categories/[category]/page.tsx +++ b/apps/www/app/blog/categories/[category]/page.tsx @@ -15,6 +15,7 @@ export async function generateStaticParams() { return categories.map((category: string) => ({ category })) } +export const revalidate = 30 export const dynamic = 'force-static' export async function generateMetadata({ params }: { params: Params }): Promise { diff --git a/apps/www/app/blog/tags/[tag]/page.tsx b/apps/www/app/blog/tags/[tag]/page.tsx index ca270ca9d6..edda447f4a 100644 --- a/apps/www/app/blog/tags/[tag]/page.tsx +++ b/apps/www/app/blog/tags/[tag]/page.tsx @@ -15,6 +15,7 @@ export async function generateStaticParams() { return tags.map((tag: string) => ({ tag })) } +export const revalidate = 30 export const dynamic = 'force-static' export async function generateMetadata({ params }: { params: Params }): Promise { diff --git a/apps/www/components/Nav/ProductDropdown.tsx b/apps/www/components/Nav/ProductDropdown.tsx index 85207759b1..83e0e586a7 100644 --- a/apps/www/components/Nav/ProductDropdown.tsx +++ b/apps/www/components/Nav/ProductDropdown.tsx @@ -14,10 +14,8 @@ import ComparisonsData from 'data/Comparisons' import CustomersData from 'data/CustomerStories' import MainProductsData from 'data/MainProducts' import ProductModulesData from 'data/ProductModules' -import { useRouter } from 'next/router' export const ProductDropdown = () => { - const { basePath } = useRouter() const isTablet = useBreakpoint(1279) return ( diff --git a/apps/www/lib/constants.ts b/apps/www/lib/constants.ts index b77ad67d3e..61a17e59bb 100644 --- a/apps/www/lib/constants.ts +++ b/apps/www/lib/constants.ts @@ -34,8 +34,8 @@ export const SITE_ORIGIN = export const CMS_SITE_ORIGIN = process.env.NEXT_PUBLIC_VERCEL_ENV === 'production' - ? // In production, require env or fall back to localhost to avoid hitting supabase.com - 'http://localhost:3030' + ? // In production, use the actual CMS domain + process.env.CMS_SITE_ORIGIN || 'https://cms.supabase.com' : process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL && typeof process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL === 'string' ? `https://${process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL.replace('zone-www-dot-com-git-', 'cms-git-')}` diff --git a/apps/www/lib/get-cms-posts.tsx b/apps/www/lib/get-cms-posts.tsx index 6507b71dd2..01dd212eeb 100644 --- a/apps/www/lib/get-cms-posts.tsx +++ b/apps/www/lib/get-cms-posts.tsx @@ -288,7 +288,7 @@ export async function getCMSPostBySlug(slug: string, preview = false) { 'Content-Type': 'application/json', ...(CMS_API_KEY && { Authorization: `Bearer ${CMS_API_KEY}` }), }, - cache: 'no-store', + // cache: 'no-store', next: { revalidate: 0 }, }) @@ -300,7 +300,7 @@ export async function getCMSPostBySlug(slug: string, preview = false) { 'Content-Type': 'application/json', ...(CMS_API_KEY && { Authorization: `Bearer ${CMS_API_KEY}` }), }, - cache: 'no-store', + // cache: 'no-store', next: { revalidate: 0 }, }) } @@ -490,8 +490,8 @@ export async function getAllCMSPosts({ 'Content-Type': 'application/json', ...(CMS_API_KEY && { Authorization: `Bearer ${CMS_API_KEY}` }), }, - cache: 'no-store', // Ensure we always get fresh data - next: { revalidate: 0 }, // Disable caching for this fetch + // cache: 'no-store', // Ensure we always get fresh data + next: { revalidate: 30 }, // Disable caching for this fetch } ) diff --git a/apps/www/pages/launch-week/6/index.tsx b/apps/www/pages/launch-week/6/index.tsx index f7a2e94ea4..22989cff44 100644 --- a/apps/www/pages/launch-week/6/index.tsx +++ b/apps/www/pages/launch-week/6/index.tsx @@ -15,7 +15,7 @@ import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { Accordion, Badge } from 'ui' import { SITE_ORIGIN } from '~/lib/constants' -import { WeekDayProps } from './types6' +import type { WeekDayProps } from '~/types/launch-week-6' import styles from './styles/launchWeek6.module.css' import styleUtils from './styles/utils6.module.css' diff --git a/apps/www/pages/launch-week/6/types6.d.ts b/apps/www/types/launch-week-6.ts similarity index 100% rename from apps/www/pages/launch-week/6/types6.d.ts rename to apps/www/types/launch-week-6.ts diff --git a/turbo.json b/turbo.json index b1b8c12160..64a448b08a 100644 --- a/turbo.json +++ b/turbo.json @@ -116,6 +116,7 @@ "ANALYZE", "CMS_API_KEY", "CMS_PREVIEW_SECRET", + "CMS_SITE_ORIGIN", "NEXT_PUBLIC_MISC_USE_URL", "NEXT_PUBLIC_MISC_USE_ANON_KEY", "NEXT_PUBLIC_STUDIO_URL",