spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1import type { Parser, ExtractedRecord, RawDocument } from "@dci/connectors";2import { resolvePlace, regionRecord, type Place } from "./shared.js";34/**5 * Microsoft Azure — https://datacenters.microsoft.com/globe/data/geo/regions.json6 * Public JSON behind the "Azure global infrastructure" globe. One object per region:7 * id, displayName, location (city or state), geographyId, latitude/longitude (region marker, NOT a8 * facility), typeId (regionaz | aregionaz | region | regionaaz), isOpen, yearOpen, monthOpen,9 * availabilityZonesId (available | soon | nearest | nearestSoon), availableTo, announcementLink.10 */11interface AzureRegion {12 id: string;13 displayName: string;14 location?: string;15 geographyId?: string;16 continent?: string;17 latitude?: number;18 longitude?: number;19 typeId?: string;20 isOpen?: boolean;21 yearOpen?: number | null;22 monthOpen?: string | null;23 availabilityZonesId?: string;24 availabilityZonesNearestRegionIds?: string[];25 availableTo?: string;26 announcementLink?: string;27 dataResidency?: string;28 hasGroundStation?: boolean;29}3031/** Azure geographyId → ISO-2 (fallback when `location` is a state/area that the city table cannot resolve). */32const GEOGRAPHY_ISO: Record<string, string> = {33 africa: "ZA", australia: "AU", austria: "AT", belgium: "BE", brazil: "BR", canada: "CA", chile: "CL", china: "CN", denmark: "DK", finland: "FI", france: "FR", germany: "DE", greece: "GR", india: "IN", indonesia: "ID", israel: "IL", italy: "IT", japan: "JP", korea: "KR", malaysia: "MY", mexico: "MX", newzealand: "NZ", norway: "NO", poland: "PL", qatar: "QA", saudiarabia: "SA", spain: "ES", sweden: "SE", switzerland: "CH", taiwan: "TW", unitedarabemirates: "AE", unitedkingdom: "GB", unitedstates: "US",34};35/** Regions whose `location` is ambiguous without a country (e.g. "Hong Kong" under geography asiapacific). */36const LOCATION_ISO_OVERRIDES: Record<string, string> = { eastasia: "HK", southeastasia: "SG", northeurope: "IE", westeurope: "NL", chinanorth3: "CN" };3738/** Sub-national areas Microsoft names that are neither a city nor a US state. */39const AREA_LOCATIONS: Record<string, { regionName: string; iso: string }> = { Hebei: { regionName: "Hebei", iso: "CN" } };4041const MONTHS: Record<string, string> = { january: "01", february: "02", march: "03", april: "04", may: "05", june: "06", july: "07", august: "08", september: "09", october: "10", november: "11", december: "12" };4243export const azureRegionsParser: Parser = {44 name: "cloud_azure_regions_v1",45 version: "1.0.0",46 pageTypes: ["cloud_region"],47 parse(doc: RawDocument, ctx): ExtractedRecord[] {48 let list: AzureRegion[];49 try { const parsed = JSON.parse(doc.text) as unknown; list = Array.isArray(parsed) ? (parsed as AzureRegion[]) : ((parsed as { regions?: AzureRegion[] }).regions ?? []); } catch (e) { ctx.log("warn", `azure regions.json not JSON: ${(e as Error).message}`); return []; }50 const out: ExtractedRecord[] = [];51 for (const r of list) {52 if (!r?.id || !r.displayName) continue;53 const isoHint = LOCATION_ISO_OVERRIDES[r.id] ?? (r.geographyId ? GEOGRAPHY_ISO[r.geographyId] : undefined) ?? null;54 const area = r.location ? AREA_LOCATIONS[r.location] : undefined;55 let place: Place = area ? { city: null, regionName: area.regionName, countryIso2: area.iso, lat: null, lng: null, geoPrecision: null } : resolvePlace(r.location ?? null, isoHint);56 if (!place.countryIso2 && isoHint) place.countryIso2 = isoHint;57 // Curated city coordinates first. When Microsoft only names a sub-national area (a US state, Hebei, …) fall58 // back to their own region marker flagged "approximate". When they only name a country ("Netherlands",59 // "Ireland", "Israel") no marker is emitted: their country markers can sit across a border or offshore.60 let geoSource: string | undefined;61 if (place.lat == null && place.regionName && !place.city && typeof r.latitude === "number" && typeof r.longitude === "number") {62 place = { ...place, lat: r.latitude, lng: r.longitude, geoPrecision: "approximate" };63 geoSource = "provider-marker:azure";64 }65 const open = r.isOpen === true;66 const restricted = /business presence in China|government|by invitation/i.test(r.availableTo ?? "");67 const status = !open ? "announced" : restricted ? "restricted" : "operational";68 const launchedOn = open && r.yearOpen ? (r.monthOpen && MONTHS[r.monthOpen.toLowerCase()] ? `${r.yearOpen}-${MONTHS[r.monthOpen.toLowerCase()]}` : String(r.yearOpen)) : null;69 const azState = r.availabilityZonesId ?? "";70 const externalIds: Record<string, string | number> = { azure_region_id: r.id, azure_type: r.typeId ?? "", azure_geography: r.geographyId ?? "", availability_zones_state: azState };71 if (r.availableTo) externalIds.available_to = r.availableTo;72 if (r.announcementLink) externalIds.announcement_url = r.announcementLink;73 if (r.dataResidency) externalIds.data_residency = r.dataResidency;74 if (r.location) externalIds.published_location = r.location;75 out.push(76 regionRecord({77 connectorId: ctx.connectorId,78 keyPrefix: "azure:region",79 providerName: "Microsoft Azure",80 code: r.id,81 name: r.displayName,82 place,83 // Microsoft publishes whether AZs are available, not how many; leave the count null when unknown.84 availabilityZones: null,85 launchedOn,86 status,87 isSovereign: false,88 externalIds,89 geoSource,90 url: doc.finalUrl,91 methods: { code: "json:id", name: "json:displayName", city: "json:location+curated-city-table", status: "json:isOpen", launchedOn: "json:yearOpen", ...(geoSource ? { lat: "json:latitude(region marker)" } : {}) },92 certainty: 0.98,93 }),94 );95 }96 ctx.log("info", `azure: ${out.length} regions (${out.filter((r) => r.data.status === "announced").length} announced)`);97 return out;98 },99};100