From 63fe7eb717dc90655f1d2de26d6faa883a812fa5 Mon Sep 17 00:00:00 2001 From: ssbg04 Date: Sun, 18 Oct 2026 20:24:13 +0800 Subject: [PATCH] fix(geo): import env from cloudflare:workers for KV binding and add storage telemetry indicator --- src/pages/api/geo.ts | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/pages/api/geo.ts b/src/pages/api/geo.ts index bbd3ad0..3200658 100644 --- a/src/pages/api/geo.ts +++ b/src/pages/api/geo.ts @@ -36,6 +36,9 @@ export const COUNTRY_COORDS: Record = {}; +// @ts-ignore +import { env as cfEnv } from 'cloudflare:workers'; + // Rate limiter / dedup per IP to avoid spamming the counter (3 min cooldown per IP) const recentIps = new Map(); @@ -52,13 +55,14 @@ export const GET: APIRoute = async ({ request, locals }) => { request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || '127.0.0.1'; - // 2. Safely resolve persistent Cloudflare KV + // 2. Resolve persistent Cloudflare KV using modern cloudflare:workers env let kv: any = null; try { - if ((locals as any)?.env?.GEO_KV || (locals as any)?.env?.GEO_ANALYTICS) { + if (typeof cfEnv !== 'undefined' && cfEnv) { + kv = (cfEnv as any).GEO_KV || (cfEnv as any).GEO_ANALYTICS; + } + if (!kv && (locals as any)?.env) { kv = (locals as any).env.GEO_KV || (locals as any).env.GEO_ANALYTICS; - } else if ((locals as any)?.runtime?.env?.GEO_KV || (locals as any)?.runtime?.env?.GEO_ANALYTICS) { - kv = (locals as any).runtime.env.GEO_KV || (locals as any).runtime.env.GEO_ANALYTICS; } } catch { // ignore - fall back to edge memory @@ -66,6 +70,7 @@ export const GET: APIRoute = async ({ request, locals }) => { let activeCounts: Record = { ...visitorCounts }; + let kvStoredFound = false; if (kv) { try { const stored = await kv.get('geo_visitor_counts'); @@ -77,6 +82,7 @@ export const GET: APIRoute = async ({ request, locals }) => { await kv.put('geo_visitor_counts', JSON.stringify({})); } else { activeCounts = parsed; + kvStoredFound = true; } } } catch (kvErr) { @@ -87,7 +93,9 @@ export const GET: APIRoute = async ({ request, locals }) => { // 3. Increment visitor count for the detected country (deduped per IP for 3 minutes) const now = Date.now(); const lastSeen = recentIps.get(cfIp) || 0; - if (now - lastSeen > 3 * 60 * 1000) { + const shouldIncrement = !kvStoredFound || (now - lastSeen > 3 * 60 * 1000); + + if (shouldIncrement) { recentIps.set(cfIp, now); // Clean old IPs if map grows large if (recentIps.size > 2000) { @@ -110,6 +118,11 @@ export const GET: APIRoute = async ({ request, locals }) => { if (!activeCounts[cfCountry]) { activeCounts[cfCountry] = 1; visitorCounts[cfCountry] = 1; + if (kv) { + try { + await kv.put('geo_visitor_counts', JSON.stringify(activeCounts)); + } catch {} + } } } @@ -153,6 +166,7 @@ export const GET: APIRoute = async ({ request, locals }) => { totalCountries: activeVisitedCountries.length > 0 ? activeVisitedCountries.length : 1, topCountries, allCountries: countries, + storage: kv ? 'cloudflare_kv' : 'edge_memory', }, }), {