From 130d8d45c1b3b5661a940b3ad9a1273899957bf9 Mon Sep 17 00:00:00 2001 From: stephanieoghenemega-eng Date: Wed, 24 Jun 2026 16:18:25 +0100 Subject: [PATCH 1/7] feat(deploy): add wrangler.toml for Cloudflare Pages --- wrangler.toml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 wrangler.toml diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 0000000..f41e626 --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,5 @@ +name = "trustflow-frontend" +compatibility_date = "2024-09-23" +compatibility_flags = ["nodejs_compat"] + +pages_build_output_dir = ".vercel/output/static" From a557d3b84e3ec3e522bc4a9e89957cf48ce23796 Mon Sep 17 00:00:00 2001 From: stephanieoghenemega-eng Date: Wed, 24 Jun 2026 16:18:45 +0100 Subject: [PATCH 2/7] feat(ci): add Cloudflare Pages deploy workflow --- .github/workflows/deploy-cf-pages.yml | 43 +++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/deploy-cf-pages.yml diff --git a/.github/workflows/deploy-cf-pages.yml b/.github/workflows/deploy-cf-pages.yml new file mode 100644 index 0000000..161197e --- /dev/null +++ b/.github/workflows/deploy-cf-pages.yml @@ -0,0 +1,43 @@ +name: Deploy to Cloudflare Pages + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + deploy: + runs-on: ubuntu-latest + permissions: + contents: read + deployments: write + pull-requests: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Build for Cloudflare Pages + run: npx @cloudflare/next-on-pages + env: + NODE_ENV: production + + - name: Publish to Cloudflare Pages + uses: cloudflare/pages-action@v1 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + projectName: trustflow-frontend + directory: .vercel/output/static + gitHubToken: ${{ secrets.GITHUB_TOKEN }} + wranglerVersion: '3' From 2ff507cc87a135cb78ba7769513bfd2e84f6ac48 Mon Sep 17 00:00:00 2001 From: stephanieoghenemega-eng Date: Wed, 24 Jun 2026 16:19:07 +0100 Subject: [PATCH 3/7] feat(deploy): integrate @cloudflare/next-on-pages adapter in next.config.js --- next.config.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/next.config.js b/next.config.js index 54b36ce..5f3f217 100644 --- a/next.config.js +++ b/next.config.js @@ -1,10 +1,20 @@ +const { setupDevPlatform } = process.env.NODE_ENV === 'development' + ? require('@cloudflare/next-on-pages/next-dev') + : { setupDevPlatform: () => {} }; + /** @type {import('next').NextConfig} */ -module.exports = { +const nextConfig = { reactStrictMode: true, - // Built-in locale routing (Pages Router). Prefixes non-default locales, e.g. - // `/es/explore`, and exposes the active locale via `useRouter().locale`. + // Cloudflare Pages runs on the edge runtime which doesn't support the + // Node.js-based i18n middleware Next.js uses internally. We keep the + // locale list here for `useRouter().locale` support in the Pages Router + // and handle locale detection via a Cloudflare Pages _middleware instead. i18n: { locales: ['en', 'es'], defaultLocale: 'en', }, }; + +setupDevPlatform(); + +module.exports = nextConfig; From abdad6f285a06426952df3b72b75a22b380c9bbd Mon Sep 17 00:00:00 2001 From: stephanieoghenemega-eng Date: Wed, 24 Jun 2026 17:38:27 +0100 Subject: [PATCH 4/7] fix(ci): remove NODE_ENV=production to allow devDeps in vercel build --- .github/workflows/deploy-cf-pages.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/deploy-cf-pages.yml b/.github/workflows/deploy-cf-pages.yml index 161197e..7ba5e95 100644 --- a/.github/workflows/deploy-cf-pages.yml +++ b/.github/workflows/deploy-cf-pages.yml @@ -29,8 +29,6 @@ jobs: - name: Build for Cloudflare Pages run: npx @cloudflare/next-on-pages - env: - NODE_ENV: production - name: Publish to Cloudflare Pages uses: cloudflare/pages-action@v1 From a3940adecb4fe89a33b06df3562bf681e49f886f Mon Sep 17 00:00:00 2001 From: stephanieoghenemega-eng Date: Wed, 24 Jun 2026 17:52:43 +0100 Subject: [PATCH 5/7] fix(ci): convert /api/usdc-price to Edge Runtime for Cloudflare Pages --- pages/api/usdc-price.ts | 46 +++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/pages/api/usdc-price.ts b/pages/api/usdc-price.ts index 389e3bc..882298c 100644 --- a/pages/api/usdc-price.ts +++ b/pages/api/usdc-price.ts @@ -1,36 +1,38 @@ -import type { NextApiRequest, NextApiResponse } from 'next' +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; + +export const runtime = 'edge'; export interface USDCPriceResponse { - price: number - currency: string - timestamp: number - source: string + price: number; + currency: string; + timestamp: number; + source: string; } export interface USDCPriceError { - error: string + error: string; } -// Simulate a realistic USDC peg: $1.00 ± 0.05% variance function getMockUSDCPrice(): number { - const variance = (Math.random() - 0.5) * 0.001 - return parseFloat((1.0 + variance).toFixed(4)) + const variance = (Math.random() - 0.5) * 0.001; + return parseFloat((1.0 + variance).toFixed(4)); } -export default function handler( - req: NextApiRequest, - res: NextApiResponse -) { +export default function handler(req: NextRequest): NextResponse { if (req.method !== 'GET') { - return res.status(405).json({ error: 'Method not allowed' }) + return NextResponse.json({ error: 'Method not allowed' }, { status: 405 }); } - res.setHeader('Cache-Control', 's-maxage=30, stale-while-revalidate=60') - - return res.status(200).json({ - price: getMockUSDCPrice(), - currency: 'USD', - timestamp: Date.now(), - source: 'mock', - }) + return NextResponse.json( + { + price: getMockUSDCPrice(), + currency: 'USD', + timestamp: Date.now(), + source: 'mock', + }, + { + headers: { 'Cache-Control': 's-maxage=30, stale-while-revalidate=60' }, + } + ); } From 47c434d5306c8090e82c0e26c6ee77c295843c14 Mon Sep 17 00:00:00 2001 From: Maverick <151352447+meshackyaro@users.noreply.github.com> Date: Mon, 29 Jun 2026 03:20:02 +0100 Subject: [PATCH 6/7] fix: migrate /api/profile to Edge Runtime for Cloudflare Pages compatibility `@cloudflare/next-on-pages` requires all non-static routes to export `runtime = 'edge'`. Converts the handler from NextApiRequest/NextApiResponse to NextRequest/NextResponse, reading query params from URL.searchParams instead of req.query. Co-Authored-By: Claude Sonnet 4.6 --- pages/api/profile.ts | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/pages/api/profile.ts b/pages/api/profile.ts index 6bb7729..89c8b81 100644 --- a/pages/api/profile.ts +++ b/pages/api/profile.ts @@ -1,4 +1,7 @@ -import type { NextApiRequest, NextApiResponse } from 'next' +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +export const runtime = 'edge' export interface ProfileGig { id: string @@ -25,10 +28,6 @@ export interface UserProfileResponse { source: 'backend' | 'mock' } -interface UserProfileError { - error: string -} - interface BackendProfileResponse { walletAddress: string displayName: string @@ -112,24 +111,19 @@ function normalizeBackendResponse(payload: BackendProfileResponse): UserProfileR } } -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { +export default async function handler(req: NextRequest): Promise { if (req.method !== 'GET') { - return res.status(405).json({ error: 'Method not allowed' }) + return NextResponse.json({ error: 'Method not allowed' }, { status: 405 }) } - res.setHeader('Cache-Control', 's-maxage=30, stale-while-revalidate=120') + const { searchParams } = new URL(req.url) + const walletAddress = searchParams.get('walletAddress')?.trim() || 'unknown' - const walletAddress = - typeof req.query.walletAddress === 'string' && req.query.walletAddress.trim().length > 0 - ? req.query.walletAddress - : 'unknown' + const cacheHeaders = { 'Cache-Control': 's-maxage=30, stale-while-revalidate=120' } const backendBaseUrl = process.env.PROFILE_API_BASE_URL if (!backendBaseUrl) { - return res.status(200).json(getMockProfile(walletAddress)) + return NextResponse.json(getMockProfile(walletAddress), { headers: cacheHeaders }) } try { @@ -138,18 +132,16 @@ export default async function handler( const response = await fetch(url.toString(), { method: 'GET', - headers: { - Accept: 'application/json', - }, + headers: { Accept: 'application/json' }, }) if (!response.ok) { - return res.status(200).json(getMockProfile(walletAddress)) + return NextResponse.json(getMockProfile(walletAddress), { headers: cacheHeaders }) } const payload = (await response.json()) as BackendProfileResponse - return res.status(200).json(normalizeBackendResponse(payload)) + return NextResponse.json(normalizeBackendResponse(payload), { headers: cacheHeaders }) } catch { - return res.status(200).json(getMockProfile(walletAddress)) + return NextResponse.json(getMockProfile(walletAddress), { headers: cacheHeaders }) } } \ No newline at end of file From a9bbb534edfa3a408ff433b334fe9d5eb5286261 Mon Sep 17 00:00:00 2001 From: Maverick <151352447+meshackyaro@users.noreply.github.com> Date: Mon, 29 Jun 2026 03:43:21 +0100 Subject: [PATCH 7/7] fix(ci): restrict Cloudflare Pages deploy to push on main only GitHub withholds repo secrets from fork PR workflows (Secret source: None), so the deploy step can never succeed on pull_request events. Restricting to push ensures the workflow only runs post-merge when secrets are available. --- .github/workflows/deploy-cf-pages.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/deploy-cf-pages.yml b/.github/workflows/deploy-cf-pages.yml index 7ba5e95..35ed627 100644 --- a/.github/workflows/deploy-cf-pages.yml +++ b/.github/workflows/deploy-cf-pages.yml @@ -3,8 +3,6 @@ name: Deploy to Cloudflare Pages on: push: branches: [main] - pull_request: - branches: [main] jobs: deploy: