import { ApolloLink, Observable } from '@apollo/client/core'; import { isCountryBanned, findBannedCountry } from '../../config/bannedCountries'; import { reverseGeocode } from '../../utils/reverseGeocode'; // Chokepoint: intercept every DeviceLocationUpdate mutation, reverse-geocode the // input coords, and refuse to forward if the country is on Feeld's restricted list. // This catches paths that bypass the React-level gates (ApiExplorer raw GraphQL, // scanner loops, anything that calls the mutation directly). export const bannedCountryLink = new ApolloLink((operation, forward) => { if (operation.operationName !== 'DeviceLocationUpdate') { return forward(operation); } const input = (operation.variables as any)?.input ?? {}; const lat = Number(input.latitude); const lng = Number(input.longitude); if (!Number.isFinite(lat) || !Number.isFinite(lng)) { return forward(operation); } return new Observable((observer) => { let cancelled = false; let subscription: { unsubscribe: () => void } | null = null; reverseGeocode(lat, lng) .then((result) => { if (cancelled) return; if (result.resolved && isCountryBanned(result.country, result.countryCode)) { const hit = findBannedCountry(result.country, result.countryCode); const name = hit?.name ?? result.country ?? result.countryCode ?? 'this country'; const msg = `[bannedCountryLink] Refusing DeviceLocationUpdate — Feeld is not available in ${name} (${lat.toFixed(3)}, ${lng.toFixed(3)})`; console.warn(msg); observer.error(new Error(`Feeld is not available in ${name}. Pick a different location.`)); return; } if (!result.resolved) { console.warn( `[bannedCountryLink] Could not resolve country for (${lat.toFixed(3)}, ${lng.toFixed(3)}); forwarding mutation.` ); } subscription = forward(operation).subscribe(observer); }) .catch((err) => { // Reverse-geocode crashed unexpectedly — fail open (forward) to avoid breaking legitimate ops. if (cancelled) return; console.warn('[bannedCountryLink] Reverse-geocode error, forwarding anyway:', err); subscription = forward(operation).subscribe(observer); }); return () => { cancelled = true; subscription?.unsubscribe(); }; }); });