spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1import type { GeoPrecision } from "@dci/core";23/**4 * Curated city → coordinates table for the cloud / hyperscaler connectors.5 *6 * Coordinates are CITY-level markers (town centre, ±a few km), never facility locations. Entries with7 * `precision: "metro"` or `"approximate"` are wider areas (a metro, a county, a state region) that a8 * provider names instead of a city; they are flagged as such so the UI never claims exactness.9 * Providers only ever publish the city/area, so nothing here can be more precise than the city.10 */11export interface CityEntry {12 /** canonical display name */13 city: string;14 iso: string;15 lat: number;16 lng: number;17 /** state / province / region (display) */18 region?: string;19 precision?: GeoPrecision;20 aliases?: string[];21}2223const C = (city: string, iso: string, lat: number, lng: number, region?: string, aliases?: string[], precision?: GeoPrecision): CityEntry => ({ city, iso, lat, lng, region, aliases, precision });2425export const CITIES: CityEntry[] = [26 // ---- North America (US) ----27 C("Ashburn", "US", 39.04, -77.49, "Virginia"),28 C("Northern Virginia", "US", 39.04, -77.49, "Virginia", ["N. Virginia", "Virginia"], "metro"),29 C("Loudoun County", "US", 39.09, -77.64, "Virginia", ["Loundoun County"], "approximate"),30 C("Prince William County", "US", 38.7, -77.48, "Virginia", undefined, "approximate"),31 C("Chesterfield County", "US", 37.38, -77.59, "Virginia", undefined, "approximate"),32 C("Henrico", "US", 37.55, -77.4, "Virginia", ["Henrico County"], "approximate"),33 C("Boydton", "US", 36.67, -78.39, "Virginia"),34 C("Columbus", "US", 39.96, -83.0, "Ohio"),35 C("New Albany", "US", 40.08, -82.81, "Ohio"),36 C("Lancaster", "US", 39.71, -82.6, "Ohio"),37 C("Bowling Green", "US", 41.37, -83.65, "Ohio"),38 C("Chicago", "US", 41.88, -87.63, "Illinois"),39 C("DeKalb", "US", 41.93, -88.75, "Illinois"),40 C("Dallas", "US", 32.78, -96.8, "Texas"),41 C("Fort Worth", "US", 32.75, -97.33, "Texas"),42 C("Houston", "US", 29.76, -95.37, "Texas"),43 C("San Antonio", "US", 29.42, -98.49, "Texas"),44 C("El Paso", "US", 31.76, -106.49, "Texas"),45 C("Temple", "US", 31.1, -97.34, "Texas"),46 C("Midlothian", "US", 32.48, -97.0, "Texas"),47 C("Red Oak", "US", 32.52, -96.8, "Texas"),48 C("Pampa", "US", 35.54, -100.96, "Texas"),49 C("Armstrong County", "US", 34.97, -101.36, "Texas", undefined, "approximate"),50 C("Haskell County", "US", 33.18, -99.73, "Texas", undefined, "approximate"),51 C("Wilbarger County", "US", 34.08, -99.24, "Texas", undefined, "approximate"),52 C("Phoenix", "US", 33.45, -112.07, "Arizona"),53 C("Mesa", "US", 33.42, -111.83, "Arizona"),54 C("Goodyear", "US", 33.44, -112.36, "Arizona"),55 C("Los Angeles", "US", 34.05, -118.24, "California"),56 C("San Jose", "US", 37.34, -121.89, "California"),57 C("Silicon Valley", "US", 37.39, -121.96, "California", undefined, "metro"),58 C("Santa Clara", "US", 37.35, -121.96, "California"),59 C("Las Vegas", "US", 36.17, -115.14, "Nevada"),60 C("Henderson", "US", 36.04, -114.98, "Nevada"),61 C("Storey County", "US", 39.45, -119.53, "Nevada", undefined, "approximate"),62 C("Salt Lake City", "US", 40.76, -111.89, "Utah"),63 C("Eagle Mountain", "US", 40.31, -112.01, "Utah"),64 C("Denver", "US", 39.74, -104.99, "Colorado"),65 C("Seattle", "US", 47.61, -122.33, "Washington"),66 C("Quincy", "US", 47.23, -119.85, "Washington"),67 C("Portland", "US", 45.52, -122.68, "Oregon"),68 C("The Dalles", "US", 45.59, -121.18, "Oregon"),69 C("Prineville", "US", 44.3, -120.83, "Oregon"),70 C("Boardman", "US", 45.84, -119.7, "Oregon"),71 C("Honolulu", "US", 21.31, -157.86, "Hawaii"),72 C("Minneapolis", "US", 44.98, -93.27, "Minnesota"),73 C("Rosemount", "US", 44.74, -93.13, "Minnesota"),74 C("Hermantown", "US", 46.81, -92.24, "Minnesota"),75 C("Pine Island", "US", 44.2, -92.65, "Minnesota"),76 C("Kansas City", "US", 39.1, -94.58, "Missouri"),77 C("New Florence", "US", 38.91, -91.45, "Missouri"),78 C("Council Bluffs", "US", 41.26, -95.86, "Iowa"),79 C("Cedar Rapids", "US", 41.98, -91.67, "Iowa"),80 C("Altoona", "US", 41.64, -93.47, "Iowa"),81 C("Des Moines", "US", 41.59, -93.62, "Iowa"),82 C("West Des Moines", "US", 41.58, -93.71, "Iowa"),83 C("Omaha", "US", 41.26, -95.94, "Nebraska"),84 C("Papillion", "US", 41.15, -96.04, "Nebraska"),85 C("Sarpy", "US", 41.11, -96.11, "Nebraska", ["Sarpy County"], "approximate"),86 C("Lincoln", "US", 40.81, -96.68, "Nebraska"),87 C("Cheyenne", "US", 41.14, -104.82, "Wyoming"),88 C("Atlanta", "US", 33.75, -84.39, "Georgia"),89 C("Douglas County", "US", 33.7, -84.77, "Georgia", undefined, "approximate"),90 C("Columbia County", "US", 33.55, -82.26, "Georgia", undefined, "approximate"),91 C("LaGrange", "US", 33.04, -85.03, "Georgia"),92 C("Stanton Springs", "US", 33.6, -83.72, "Georgia", undefined, "approximate"),93 C("Miami", "US", 25.76, -80.19, "Florida"),94 C("Boston", "US", 42.36, -71.06, "Massachusetts"),95 C("Washington, D.C.", "US", 38.91, -77.04, "District of Columbia", ["Washington DC", "Washington D.C.", "Washington, DC"]),96 C("New York City", "US", 40.71, -74.01, "New York", ["New York"]),97 C("Philadelphia", "US", 39.95, -75.17, "Pennsylvania"),98 C("Moncks Corner", "US", 33.2, -80.01, "South Carolina"),99 C("Berkeley County", "US", 33.2, -79.95, "South Carolina", undefined, "approximate"),100 C("Dorchester County", "US", 33.17, -80.54, "South Carolina", undefined, "approximate"),101 C("The Lowcountry", "US", 33.16, -80.01, "South Carolina", undefined, "approximate"),102 C("Aiken", "US", 33.56, -81.72, "South Carolina"),103 C("Lenoir", "US", 35.91, -81.54, "North Carolina"),104 C("Forest City", "US", 35.33, -81.87, "North Carolina"),105 C("Huntsville", "US", 34.73, -86.59, "Alabama"),106 C("Montgomery", "US", 32.38, -86.31, "Alabama"),107 C("Jackson County", "US", 34.78, -85.99, "Alabama", undefined, "approximate"),108 C("Gallatin", "US", 36.39, -86.45, "Tennessee"),109 C("Montgomery County", "US", 36.5, -87.38, "Tennessee", undefined, "approximate"),110 C("Fort Wayne", "US", 41.08, -85.14, "Indiana"),111 C("Michigan City", "US", 41.71, -86.9, "Indiana"),112 C("Morgan County", "US", 39.48, -86.45, "Indiana", undefined, "approximate"),113 C("Jeffersonville", "US", 38.28, -85.74, "Indiana"),114 C("Lebanon", "US", 40.05, -86.47, "Indiana"),115 C("Van Buren Township", "US", 42.22, -83.5, "Michigan", undefined, "approximate"),116 C("Tulsa", "US", 36.15, -95.99, "Oklahoma"),117 C("Stillwater", "US", 36.12, -97.06, "Oklahoma"),118 C("Mayes County", "US", 36.3, -95.23, "Oklahoma", ["Pryor"], "approximate"),119 C("Muskogee County", "US", 35.62, -95.37, "Oklahoma", undefined, "approximate"),120 C("Richland Parish", "US", 32.42, -91.76, "Louisiana", undefined, "approximate"),121 C("West Memphis", "US", 35.15, -90.18, "Arkansas"),122 C("Kuna", "US", 43.49, -116.42, "Idaho"),123 C("Los Lunas", "US", 34.81, -106.73, "New Mexico"),124 C("Beaver Dam", "US", 43.46, -88.84, "Wisconsin"),125 C("Mount Pleasant", "US", 42.72, -87.89, "Wisconsin"),126 // ---- Canada ----127 C("Toronto", "CA", 43.65, -79.38, "Ontario"),128 C("Montréal", "CA", 45.5, -73.57, "Québec", ["Montreal"]),129 C("Québec City", "CA", 46.81, -71.21, "Québec", ["Quebec City", "Quebec"]),130 C("Calgary", "CA", 51.05, -114.07, "Alberta"),131 C("Sturgeon County", "CA", 53.78, -113.55, "Alberta", undefined, "approximate"),132 C("Vancouver", "CA", 49.28, -123.12, "British Columbia"),133 // ---- Latin America ----134 C("Querétaro", "MX", 20.59, -100.39, "Querétaro", ["Queretaro", "Querétaro State"]),135 C("Monterrey", "MX", 25.69, -100.32, "Nuevo León"),136 C("São Paulo", "BR", -23.55, -46.63, "São Paulo", ["Sao Paulo", "Sau Paulo", "São Paulo State"]),137 C("Osasco", "BR", -23.53, -46.79, "São Paulo"),138 C("Vinhedo", "BR", -23.03, -46.98, "São Paulo"),139 C("Rio de Janeiro", "BR", -22.91, -43.17, "Rio de Janeiro"),140 C("Santiago", "CL", -33.45, -70.67, "Santiago Metropolitan"),141 C("Quilicura", "CL", -33.36, -70.73, "Santiago Metropolitan"),142 C("Valparaíso", "CL", -33.05, -71.62, "Valparaíso", ["Valparaiso"]),143 C("Bogotá", "CO", 4.71, -74.07, "Bogotá", ["Bogota"]),144 C("Buenos Aires", "AR", -34.6, -58.38),145 C("Lima", "PE", -12.05, -77.04),146 C("Canelones", "UY", -34.52, -56.28, "Canelones"),147 // ---- Europe ----148 C("Dublin", "IE", 53.35, -6.26, "Leinster"),149 C("Clonee", "IE", 53.41, -6.44, "Meath"),150 C("London", "GB", 51.51, -0.13, "England"),151 C("Cardiff", "GB", 51.48, -3.18, "Wales"),152 C("Newport", "GB", 51.58, -2.99, "Wales"),153 C("Waltham Cross", "GB", 51.69, -0.03, "England"),154 C("Amsterdam", "NL", 52.37, 4.9, "North Holland"),155 C("Eemshaven", "NL", 53.45, 6.83, "Groningen"),156 C("Groningen", "NL", 53.22, 6.57, "Groningen"),157 C("Middenmeer", "NL", 52.81, 4.99, "North Holland"),158 C("Winschoten", "NL", 53.14, 7.03, "Groningen"),159 C("Brussels", "BE", 50.85, 4.35, "Brussels-Capital"),160 C("St. Ghislain", "BE", 50.45, 3.82, "Hainaut", ["Saint-Ghislain", "St Ghislain"]),161 C("Farciennes", "BE", 50.43, 4.54, "Hainaut"),162 C("Paris", "FR", 48.86, 2.35, "Île-de-France"),163 C("Marseille", "FR", 43.3, 5.37, "Provence-Alpes-Côte d'Azur"),164 C("Frankfurt", "DE", 50.11, 8.68, "Hesse", ["Frankfurt am Main"]),165 C("Hanau", "DE", 50.13, 8.92, "Hesse"),166 C("Dietzenbach", "DE", 50.02, 8.79, "Hesse"),167 C("Berlin", "DE", 52.52, 13.41, "Berlin"),168 C("Hamburg", "DE", 53.55, 9.99, "Hamburg"),169 C("Magdeburg", "DE", 52.13, 11.63, "Saxony-Anhalt"),170 C("Zurich", "CH", 47.38, 8.54, "Zürich", ["Zürich"]),171 C("Geneva", "CH", 46.2, 6.14, "Geneva"),172 C("Vienna", "AT", 48.21, 16.37, "Vienna"),173 C("Kronstorf", "AT", 48.14, 14.46, "Upper Austria"),174 C("Milan", "IT", 45.46, 9.19, "Lombardy"),175 C("Turin", "IT", 45.07, 7.69, "Piedmont"),176 C("Madrid", "ES", 40.42, -3.7, "Community of Madrid"),177 C("Aragón", "ES", 41.65, -0.89, "Aragón", ["Aragon", "Zaragoza"], "metro"),178 C("Lisbon", "PT", 38.72, -9.14),179 C("Stockholm", "SE", 59.33, 18.07, "Stockholm"),180 C("Gävle", "SE", 60.67, 17.14, "Gävleborg", ["Gävle and Sandviken", "Gavle"]),181 C("Luleå", "SE", 65.58, 22.16, "Norrbotten", ["Lulea"]),182 C("Horndal", "SE", 60.3, 16.42, "Dalarna"),183 C("Oslo", "NO", 59.91, 10.75, "Oslo"),184 C("Skien", "NO", 59.21, 9.61, "Telemark"),185 C("Copenhagen", "DK", 55.68, 12.57, "Capital Region"),186 C("Odense", "DK", 55.4, 10.39, "Southern Denmark"),187 C("Fredericia", "DK", 55.57, 9.75, "Southern Denmark"),188 C("Helsinki", "FI", 60.17, 24.94, "Uusimaa"),189 C("Hamina", "FI", 60.57, 27.2, "Kymenlaakso"),190 C("Muhos", "FI", 64.81, 25.99, "North Ostrobothnia"),191 C("Vaala", "FI", 64.56, 26.84, "Kainuu"),192 C("Warsaw", "PL", 52.23, 21.01, "Masovian"),193 C("Athens", "GR", 37.98, 23.73, "Attica"),194 C("Istanbul", "TR", 41.01, 28.98),195 C("Jovanovac", "RS", 44.06, 20.95, "Šumadija", ["Kragujevac"], "approximate"),196 // ---- Middle East & Africa ----197 C("Tel Aviv", "IL", 32.09, 34.78),198 C("Jerusalem", "IL", 31.77, 35.21),199 C("Dubai", "AE", 25.2, 55.27, "Dubai"),200 C("Abu Dhabi", "AE", 24.45, 54.38, "Abu Dhabi"),201 C("Doha", "QA", 25.29, 51.53),202 C("Riyadh", "SA", 24.71, 46.68, "Riyadh"),203 C("Jeddah", "SA", 21.49, 39.19, "Makkah"),204 C("Dammam", "SA", 26.43, 50.1, "Eastern Province"),205 C("Manama", "BH", 26.23, 50.59),206 C("Muscat", "OM", 23.59, 58.41),207 C("Johannesburg", "ZA", -26.2, 28.05, "Gauteng"),208 C("Cape Town", "ZA", -33.92, 18.42, "Western Cape"),209 C("Casablanca", "MA", 33.57, -7.59),210 C("Lagos", "NG", 6.52, 3.38, "Lagos"),211 C("Nairobi", "KE", -1.29, 36.82),212 // ---- Asia Pacific ----213 C("Tokyo", "JP", 35.68, 139.69, "Tokyo", ["Tokyo, Saitama", "Saitama"]),214 C("Osaka", "JP", 34.69, 135.5, "Osaka"),215 C("Inzai", "JP", 35.83, 140.15, "Chiba"),216 C("Seoul", "KR", 37.57, 126.98, "Seoul"),217 C("Busan", "KR", 35.18, 129.08, "Busan"),218 C("Chuncheon", "KR", 37.88, 127.73, "Gangwon"),219 C("Hong Kong", "HK", 22.32, 114.17),220 C("Taipei", "TW", 25.03, 121.57, "Taipei"),221 C("Changhua County", "TW", 24.08, 120.54, "Changhua", ["Changhua"], "approximate"),222 C("Singapore", "SG", 1.35, 103.82),223 C("Jurong West", "SG", 1.34, 103.71),224 C("Kuala Lumpur", "MY", 3.14, 101.69, "Federal Territory"),225 C("Johor Bahru", "MY", 1.49, 103.74, "Johor", ["Johorbahru", "Johor"]),226 C("Kulai", "MY", 1.66, 103.6, "Johor"),227 C("Selangor", "MY", 3.07, 101.52, "Selangor", undefined, "approximate"),228 C("Jakarta", "ID", -6.21, 106.85, "Jakarta"),229 C("Batam", "ID", 1.13, 104.05, "Riau Islands"),230 C("Bangkok", "TH", 13.76, 100.5, "Bangkok"),231 C("Chonburi", "TH", 13.36, 100.98, "Chonburi"),232 C("Manila", "PH", 14.6, 120.98, "Metro Manila"),233 C("Hanoi", "VN", 21.03, 105.85),234 C("Mumbai", "IN", 19.08, 72.88, "Maharashtra"),235 C("Pune", "IN", 18.52, 73.86, "Maharashtra"),236 C("Hyderabad", "IN", 17.39, 78.49, "Telangana"),237 C("Chennai", "IN", 13.08, 80.27, "Tamil Nadu"),238 C("Delhi", "IN", 28.61, 77.21, "Delhi", ["New Delhi"]),239 C("Kolkata", "IN", 22.57, 88.36, "West Bengal"),240 C("Andhra Pradesh", "IN", 15.91, 79.74, "Andhra Pradesh", ["Visakhapatnam"], "approximate"),241 C("Sydney", "AU", -33.87, 151.21, "New South Wales", ["New South Wales"]),242 C("Melbourne", "AU", -37.81, 144.96, "Victoria", ["Victoria"]),243 C("Canberra", "AU", -35.28, 149.13, "Australian Capital Territory"),244 C("Perth", "AU", -31.95, 115.86, "Western Australia"),245 C("Auckland", "NZ", -36.85, 174.76, "Auckland"),246 // ---- China ----247 C("Beijing", "CN", 39.9, 116.41, "Beijing"),248 C("Shanghai", "CN", 31.23, 121.47, "Shanghai"),249 C("Shenzhen", "CN", 22.54, 114.06, "Guangdong"),250 C("Guangzhou", "CN", 23.13, 113.26, "Guangdong"),251 C("Heyuan", "CN", 23.74, 114.7, "Guangdong"),252 C("Hangzhou", "CN", 30.27, 120.15, "Zhejiang"),253 C("Nanjing", "CN", 32.06, 118.8, "Jiangsu"),254 C("Qingdao", "CN", 36.07, 120.38, "Shandong"),255 C("Zhangjiakou", "CN", 40.77, 114.89, "Hebei"),256 C("Hohhot", "CN", 40.84, 111.75, "Inner Mongolia"),257 C("Ulanqab", "CN", 41.02, 113.13, "Inner Mongolia"),258 C("Chengdu", "CN", 30.57, 104.07, "Sichuan"),259 C("Chongqing", "CN", 29.56, 106.55, "Chongqing"),260 C("Zhongwei", "CN", 37.5, 105.19, "Ningxia"),261 C("Wuhan", "CN", 30.59, 114.31, "Hubei"),262 C("Fuzhou", "CN", 26.07, 119.3, "Fujian"),263 C("Ningxia", "CN", 37.5, 105.19, "Ningxia", undefined, "approximate"),264 C("Macao", "MO", 22.2, 113.54, undefined, ["Macau"]),265];266267/** US state name → ISO 3166-2 style code (used for regionName and to resolve countryIso2 = US). */268export const US_STATES: Record<string, string> = {269 alabama: "AL", alaska: "AK", arizona: "AZ", arkansas: "AR", california: "CA", colorado: "CO", connecticut: "CT", delaware: "DE", florida: "FL", georgia: "GA", hawaii: "HI", idaho: "ID", illinois: "IL", indiana: "IN", iowa: "IA", kansas: "KS", kentucky: "KY", louisiana: "LA", maine: "ME", maryland: "MD", massachusetts: "MA", michigan: "MI", minnesota: "MN", mississippi: "MS", missouri: "MO", montana: "MT", nebraska: "NE", nevada: "NV", "new hampshire": "NH", "new jersey": "NJ", "new mexico": "NM", "new york": "NY", "north carolina": "NC", "north dakota": "ND", ohio: "OH", oklahoma: "OK", oregon: "OR", pennsylvania: "PA", "rhode island": "RI", "south carolina": "SC", "south dakota": "SD", tennessee: "TN", texas: "TX", utah: "UT", vermont: "VT", virginia: "VA", washington: "WA", "west virginia": "WV", wisconsin: "WI", wyoming: "WY", "district of columbia": "DC", "washington dc": "DC", "washington, d.c.": "DC",270};271272export const CA_PROVINCES: Record<string, string> = {273 ontario: "ON", québec: "QC", quebec: "QC", alberta: "AB", "british columbia": "BC", manitoba: "MB", saskatchewan: "SK", "nova scotia": "NS", "new brunswick": "NB", "newfoundland and labrador": "NL", "prince edward island": "PE",274};275276export function normKey(s: string): string {277 return s.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();278}279280const INDEX = new Map<string, CityEntry>();281for (const e of CITIES) {282 for (const n of [e.city, ...(e.aliases ?? [])]) {283 const k = normKey(n);284 const withIso = `${k}|${e.iso}`;285 if (!INDEX.has(withIso)) INDEX.set(withIso, e);286 if (!INDEX.has(k)) INDEX.set(k, e);287 }288}289290/** Look a city up by name (accent/case-insensitive), optionally constrained to a country. */291export function lookupCity(name: string | null | undefined, iso?: string | null): CityEntry | null {292 if (!name) return null;293 const k = normKey(name);294 if (!k) return null;295 if (iso) return INDEX.get(`${k}|${iso.toUpperCase()}`) ?? null;296 return INDEX.get(k) ?? null;297}298299/** "Virginia" → "US", "Ontario" → "CA", else null. */300export function countryFromStateName(name: string | null | undefined): string | null {301 if (!name) return null;302 const k = name.trim().toLowerCase();303 if (US_STATES[k]) return "US";304 if (CA_PROVINCES[k]) return "CA";305 return null;306}307308/** Title-case a state name key from US_STATES / CA_PROVINCES for display. */309export function stateDisplayName(name: string): string {310 return name.trim().replace(/\s+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).replace(/\bDc\b/, "DC").replace(/\bOf\b/, "of").replace(/\bAnd\b/, "and");311}312