Openstatus www.openstatus.dev

chore: @openstatus/regions package (#1448)

* chore: openstatus regions package

* chore: available regions

authored by

Maximilian Kaske and committed by
GitHub
c45933c7 d23d97c1

+655 -591
+1
apps/dashboard/package.json
··· 39 39 "@openstatus/notification-slack": "workspace:*", 40 40 "@openstatus/notification-webhook": "workspace:*", 41 41 "@openstatus/react": "workspace:*", 42 + "@openstatus/regions": "workspace:*", 42 43 "@openstatus/tinybird": "workspace:*", 43 44 "@openstatus/tracker": "workspace:*", 44 45 "@openstatus/upstash": "workspace:*",
+1 -1
apps/dashboard/src/components/chart/chart-line-regions.tsx
··· 14 14 import { useIsMobile } from "@/hooks/use-mobile"; 15 15 import { cn } from "@/lib/utils"; 16 16 import { monitorRegions } from "@openstatus/db/src/schema/constants"; 17 - import { regionDict } from "@openstatus/utils"; 17 + import { regionDict } from "@openstatus/regions"; 18 18 import { ChartTooltipNumber } from "./chart-tooltip-number"; 19 19 20 20 const chartConfig = monitorRegions.reduce((config, region) => {
+1 -1
apps/dashboard/src/components/controls-search/command-region.tsx
··· 25 25 import { REGIONS } from "@/data/metrics.client"; 26 26 import { useTRPC } from "@/lib/trpc/client"; 27 27 import { cn } from "@/lib/utils"; 28 - import { formatRegionCode, groupByContinent } from "@openstatus/utils"; 28 + import { formatRegionCode, groupByContinent } from "@openstatus/regions"; 29 29 import { useQuery } from "@tanstack/react-query"; 30 30 import { Check, Lock } from "lucide-react"; 31 31 import { parseAsArrayOf, parseAsStringLiteral, useQueryState } from "nuqs";
+1 -1
apps/dashboard/src/components/data-table/response-logs/columns.tsx
··· 17 17 import { getStatusCodeVariant, textColors } from "@/data/status-codes"; 18 18 import { cn } from "@/lib/utils"; 19 19 import type { RouterOutputs } from "@openstatus/api"; 20 - import { regionDict } from "@openstatus/utils"; 20 + import { regionDict } from "@openstatus/regions"; 21 21 import { HoverCardPortal } from "@radix-ui/react-hover-card"; 22 22 import type { ColumnDef } from "@tanstack/react-table"; 23 23 import { Clock, Workflow } from "lucide-react";
+1 -1
apps/dashboard/src/components/data-table/response-logs/data-table-basics.tsx
··· 16 16 import { formatMilliseconds, formatPercentage } from "@/lib/formatter"; 17 17 import { cn } from "@/lib/utils"; 18 18 import type { RouterOutputs } from "@openstatus/api"; 19 - import { regionDict } from "@openstatus/utils"; 19 + import { regionDict } from "@openstatus/regions"; 20 20 import { Braces, TableProperties } from "lucide-react"; 21 21 22 22 type ResponseLog = RouterOutputs["tinybird"]["get"]["data"][number];
+1 -1
apps/dashboard/src/components/data-table/response-logs/regions/columns.tsx
··· 12 12 } from "@/components/ui/tooltip"; 13 13 import type { RegionMetric } from "@/data/region-metrics"; 14 14 import { getActions } from "@/data/region-metrics.client"; 15 - import { formatRegionCode, regionDict } from "@openstatus/utils"; 15 + import { formatRegionCode, regionDict } from "@openstatus/regions"; 16 16 import type { ColumnDef } from "@tanstack/react-table"; 17 17 // import { toast } from "sonner"; 18 18 import { useRouter } from "next/navigation";
+1 -1
apps/dashboard/src/components/forms/monitor/form-scheduling-regions.tsx
··· 47 47 formatRegionCode, 48 48 groupByContinent, 49 49 regionDict, 50 - } from "@openstatus/utils"; 50 + } from "@openstatus/regions"; 51 51 import { useQuery } from "@tanstack/react-query"; 52 52 import { isTRPCClientError } from "@trpc/client"; 53 53 import { CircleX, Info } from "lucide-react";
+1
apps/server/package.json
··· 20 20 "@openstatus/db": "workspace:*", 21 21 "@openstatus/emails": "workspace:*", 22 22 "@openstatus/error": "workspace:*", 23 + "@openstatus/regions": "workspace:*", 23 24 "@openstatus/tinybird": "workspace:*", 24 25 "@openstatus/tracker": "workspace:*", 25 26 "@openstatus/upstash": "workspace:*",
+7 -9
apps/server/src/routes/v1/monitors/schema.ts
··· 6 6 monitorPeriodicitySchema, 7 7 monitorRegions, 8 8 } from "@openstatus/db/src/schema/constants"; 9 - import { regionDict } from "@openstatus/utils"; 9 + import { AVAILABLE_REGIONS } from "@openstatus/regions"; 10 10 import { ZodError } from "zod"; 11 11 12 12 const statusAssertion = z ··· 105 105 } 106 106 107 107 const deprecatedRegions = regions.filter((r) => { 108 - const deprecated = 109 - regionDict[r as keyof typeof regionDict].deprecated; 110 - if (deprecated) return true; 111 - return false; 108 + return !AVAILABLE_REGIONS.includes( 109 + r as (typeof AVAILABLE_REGIONS)[number], 110 + ); 112 111 }); 113 112 114 113 if (deprecatedRegions.length > 0) { ··· 372 371 } 373 372 374 373 const deprecatedRegions = regions.filter((r) => { 375 - const deprecated = 376 - regionDict[r as keyof typeof regionDict].deprecated; 377 - if (deprecated) return true; 378 - return false; 374 + return !AVAILABLE_REGIONS.includes( 375 + r as (typeof AVAILABLE_REGIONS)[number], 376 + ); 379 377 }); 380 378 381 379 if (deprecatedRegions.length > 0) {
+1
apps/web/package.json
··· 33 33 "@openstatus/notification-slack": "workspace:*", 34 34 "@openstatus/notification-webhook": "workspace:*", 35 35 "@openstatus/react": "workspace:*", 36 + "@openstatus/regions": "workspace:*", 36 37 "@openstatus/tinybird": "workspace:*", 37 38 "@openstatus/tracker": "workspace:*", 38 39 "@openstatus/ui": "workspace:*",
+1 -1
apps/web/src/app/(pages)/(content)/play/checker/_components/checker-form.tsx
··· 46 46 import { toast } from "@/lib/toast"; 47 47 import { notEmpty } from "@/lib/utils"; 48 48 import { monitorRegions } from "@openstatus/db/src/schema/constants"; 49 - import { regionDict } from "@openstatus/utils"; 49 + import { regionDict } from "@openstatus/regions"; 50 50 import { ArrowRight, ChevronRight, Gauge, Info, Loader } from "lucide-react"; 51 51 import dynamic from "next/dynamic"; 52 52 import Link from "next/link";
+1 -1
apps/web/src/app/(pages)/(content)/play/checker/_components/global-monitoring.tsx
··· 10 10 CardIcon, 11 11 CardTitle, 12 12 } from "@/components/marketing/card"; 13 - import { regionDict } from "@openstatus/utils"; 13 + import { regionDict } from "@openstatus/regions"; 14 14 15 15 const TOTAL_REGIONS = Object.keys(regionDict).length; 16 16
+1 -1
apps/web/src/app/(pages)/(content)/play/checker/_components/informations.tsx
··· 1 1 import { Shell } from "@/components/dashboard/shell"; 2 + import { regionDict } from "@openstatus/regions"; 2 3 import { Separator } from "@openstatus/ui"; 3 - import { regionDict } from "@openstatus/utils"; 4 4 5 5 const TOTAL_REGIONS = Object.keys(regionDict).length; 6 6 const TOTAL_PROVIDERS = Object.keys(regionDict).reduce((acc, region) => {
+5 -2
apps/web/src/app/api/checker/cron/_cron.ts
··· 16 16 17 17 import { env } from "@/env"; 18 18 import type { Region } from "@openstatus/db/src/schema/constants"; 19 + import { regionDict } from "@openstatus/regions"; 19 20 import { 20 21 type httpPayloadSchema, 21 22 type tpcPayloadSchema, 22 23 transformHeaders, 23 24 } from "@openstatus/utils"; 24 - import { regionDict } from "@openstatus/utils"; 25 25 26 26 const periodicityAvailable = selectMonitorSchema.pick({ periodicity: true }); 27 27 ··· 263 263 function generateUrl({ 264 264 row, 265 265 region, 266 - }: { row: z.infer<typeof selectMonitorSchema>; region: Region }) { 266 + }: { 267 + row: z.infer<typeof selectMonitorSchema>; 268 + region: Region; 269 + }) { 267 270 const regionInfo = regionDict[region]; 268 271 269 272 switch (regionInfo.provider) {
+1 -1
apps/web/src/components/data-table/columns.tsx
··· 4 4 import { format } from "date-fns"; 5 5 import type * as z from "zod"; 6 6 7 - import { regionDict } from "@openstatus/utils"; 7 + import { regionDict } from "@openstatus/regions"; 8 8 9 9 import type { Trigger } from "@/lib/monitor/utils"; 10 10 import type { monitorRegionSchema } from "@openstatus/db/src/schema/constants";
+1 -1
apps/web/src/components/data-table/data-table-toolbar.tsx
··· 4 4 import { X } from "lucide-react"; 5 5 import { useRouter, useSearchParams } from "next/navigation"; 6 6 7 + import { regionDict } from "@openstatus/regions"; 7 8 import { Button } from "@openstatus/ui/src/components/button"; 8 - import { regionDict } from "@openstatus/utils"; 9 9 10 10 import { Icons } from "@/components/icons"; 11 11 import { codesDict } from "@/data/code-dictionary";
+1 -1
apps/web/src/components/data-table/single-region/columns.tsx
··· 4 4 import { formatNumber } from "@/components/monitor-dashboard/metrics-card"; 5 5 import type { ResponseTimeMetricsByRegion } from "@/lib/tb"; 6 6 import type { Region } from "@openstatus/db/src/schema/constants"; 7 - import { regionDict } from "@openstatus/utils"; 7 + import { regionDict } from "@openstatus/regions"; 8 8 import type { ColumnDef } from "@tanstack/react-table"; 9 9 import { DataTableColumnHeader } from "./data-table-column-header"; 10 10
+1 -1
apps/web/src/components/forms/monitor/request-test-button.tsx
··· 10 10 type Region, 11 11 monitorRegions, 12 12 } from "@openstatus/db/src/schema/constants"; 13 + import { regionDict } from "@openstatus/regions"; 13 14 import { 14 15 Button, 15 16 Dialog, ··· 26 27 TooltipProvider, 27 28 TooltipTrigger, 28 29 } from "@openstatus/ui"; 29 - import { regionDict } from "@openstatus/utils"; 30 30 31 31 import { LoadingAnimation } from "@/components/loading-animation"; 32 32 import { RegionInfo } from "@/components/ping-response-analysis/region-info";
+1 -1
apps/web/src/components/forms/monitor/section-scheduling.tsx
··· 9 9 import { getLimit } from "@openstatus/db/src/schema/plan/utils"; 10 10 11 11 import { cn } from "@/lib/utils"; 12 + import { groupByContinent } from "@openstatus/regions"; 12 13 import { 13 14 FormControl, 14 15 FormDescription, ··· 22 23 SelectTrigger, 23 24 SelectValue, 24 25 } from "@openstatus/ui"; 25 - import { groupByContinent } from "@openstatus/utils"; 26 26 27 27 import { CheckboxLabel } from "../shared/checkbox-label"; 28 28 import { SectionHeader } from "../shared/section-header";
+6 -6
apps/web/src/components/forms/monitor/select-region.tsx
··· 2 2 3 3 import { Check, ChevronsUpDown, Globe2 } from "lucide-react"; 4 4 5 + import { 6 + type Continent, 7 + type RegionInfo, 8 + formatRegionCode, 9 + regionDict, 10 + } from "@openstatus/regions"; 5 11 import { Button, type ButtonProps } from "@openstatus/ui/src/components/button"; 6 12 import { 7 13 Command, ··· 17 23 PopoverContent, 18 24 PopoverTrigger, 19 25 } from "@openstatus/ui/src/components/popover"; 20 - import { 21 - type Continent, 22 - type RegionInfo, 23 - formatRegionCode, 24 - regionDict, 25 - } from "@openstatus/utils"; 26 26 27 27 import { cn } from "@/lib/utils"; 28 28 import {
+1 -1
apps/web/src/components/monitor-charts/region-table.tsx
··· 1 + import { regionDict } from "@openstatus/regions"; 1 2 import { 2 3 Table, 3 4 TableBody, ··· 7 8 TableHeader, 8 9 TableRow, 9 10 } from "@openstatus/ui/src/components/table"; 10 - import { regionDict } from "@openstatus/utils"; 11 11 12 12 import { formatNumber } from "@/components/monitor-dashboard/metrics-card"; 13 13 import type { ResponseTimeMetricsByRegion } from "@/lib/tb";
+1 -1
apps/web/src/components/monitor-charts/utils.tsx
··· 1 - import { regionDict } from "@openstatus/utils"; 1 + import { regionDict } from "@openstatus/regions"; 2 2 3 3 import type { Period, Quantile } from "@/lib/monitor/utils"; 4 4 import type { ResponseGraph } from "@/lib/tb";
+6 -6
apps/web/src/components/monitor-dashboard/region-preset.tsx
··· 2 2 3 3 import { Check, ChevronsUpDown, Globe2 } from "lucide-react"; 4 4 5 + import { 6 + type Continent, 7 + type RegionInfo, 8 + formatRegionCode, 9 + regionDict, 10 + } from "@openstatus/regions"; 5 11 import { Button, type ButtonProps } from "@openstatus/ui/src/components/button"; 6 12 import { 7 13 Command, ··· 17 23 PopoverContent, 18 24 PopoverTrigger, 19 25 } from "@openstatus/ui/src/components/popover"; 20 - import { 21 - type Continent, 22 - type RegionInfo, 23 - formatRegionCode, 24 - regionDict, 25 - } from "@openstatus/utils"; 26 26 27 27 import { IconCloudProvider } from "@/components/icon-cloud-provider"; 28 28 import { cn } from "@/lib/utils";
+1 -1
apps/web/src/components/ping-response-analysis/columns.tsx
··· 6 6 import { DataTableColumnHeader } from "@/components/data-table/data-table-column-header"; 7 7 import { IconCloudProviderTooltip } from "@/components/icon-cloud-provider"; 8 8 import { cn } from "@/lib/utils"; 9 + import { formatRegionCode, regionDict } from "@openstatus/regions"; 9 10 import { 10 11 HoverCard, 11 12 HoverCardContent, 12 13 HoverCardPortal, 13 14 HoverCardTrigger, 14 15 } from "@openstatus/ui"; 15 - import { formatRegionCode, regionDict } from "@openstatus/utils"; 16 16 17 17 export const columns: ColumnDef<RegionChecker>[] = [ 18 18 {
+1 -1
apps/web/src/components/ping-response-analysis/multi-region-chart.tsx
··· 6 6 import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"; 7 7 8 8 import { IconCloudProvider } from "@/components/icon-cloud-provider"; 9 + import { formatRegionCode, regionDict } from "@openstatus/regions"; 9 10 import { 10 11 type ChartConfig, 11 12 ChartContainer, ··· 14 15 ChartTooltip, 15 16 ChartTooltipContent, 16 17 } from "@openstatus/ui/src/components/chart"; 17 - import { formatRegionCode, regionDict } from "@openstatus/utils"; 18 18 19 19 const chartConfig = { 20 20 dns: {
+1 -1
apps/web/src/components/ping-response-analysis/utils.ts
··· 6 6 monitorRegionSchema, 7 7 } from "@openstatus/db/src/schema/constants"; 8 8 import type { Region } from "@openstatus/db/src/schema/constants"; 9 - import { continentDict, regionDict } from "@openstatus/utils"; 9 + import { continentDict, regionDict } from "@openstatus/regions"; 10 10 11 11 export function latencyFormatter(value: number) { 12 12 return `${new Intl.NumberFormat("us").format(value).toString()}ms`;
+13 -2
apps/web/src/config/alternatives.ts
··· 45 45 features: [ 46 46 opensource(), 47 47 bootstrap(), 48 + multicloud(), 48 49 global(), 49 50 otelexport(), 50 51 githubaction(), ··· 58 59 logo: "/assets/alternatives/uptime-kuma.png", 59 60 features: [ 60 61 opensource(true), 62 + multicloud(), 61 63 global(), 62 64 selfhost(), 63 65 managed(), ··· 103 105 104 106 function global(alternative = false): Feature { 105 107 return { 106 - label: "Global (35 regions)", 108 + label: "Global (28 regions)", 107 109 description: "Monitor your endpoints globally.", 108 110 openstatus: true, 109 111 alternative, ··· 114 116 return { 115 117 label: "Multi-region", 116 118 description: "Monitor your endpoints globally", 117 - openstatus: 35, 119 + openstatus: 28, 120 + alternative, 121 + }; 122 + } 123 + 124 + function multicloud(alternative = undefined): Feature { 125 + return { 126 + label: "Multi-cloud", 127 + description: "Monitor from different cloud providers", 128 + openstatus: 3, 118 129 alternative, 119 130 }; 120 131 }
+1
packages/api/package.json
··· 13 13 "@openstatus/db": "workspace:*", 14 14 "@openstatus/emails": "workspace:*", 15 15 "@openstatus/error": "workspace:*", 16 + "@openstatus/regions": "workspace:*", 16 17 "@openstatus/utils": "workspace:*", 17 18 "@openstatus/upstash": "workspace:*", 18 19 "@openstatus/tinybird": "workspace:*",
+1 -1
packages/api/src/router/monitor.ts
··· 41 41 monitorPeriodicity, 42 42 monitorRegions, 43 43 } from "@openstatus/db/src/schema/constants"; 44 - import { regionDict } from "@openstatus/utils"; 44 + import { regionDict } from "@openstatus/regions"; 45 45 import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc"; 46 46 import { testHttp, testTcp } from "./checker"; 47 47
+2 -1
packages/db/package.json
··· 14 14 }, 15 15 "dependencies": { 16 16 "@libsql/client": "0.15.14", 17 + "@openstatus/assertions": "workspace:*", 18 + "@openstatus/regions": "workspace:*", 17 19 "@t3-oss/env-core": "0.7.1", 18 20 "drizzle-orm": "0.44.4", 19 21 "drizzle-zod": "0.5.1", 20 22 "zod": "3.24.2" 21 23 }, 22 24 "devDependencies": { 23 - "@openstatus/assertions": "workspace:*", 24 25 "@openstatus/tsconfig": "workspace:*", 25 26 "@types/node": "22.10.2", 26 27 "drizzle-kit": "0.31.4",
+12 -71
packages/db/src/schema/constants.ts
··· 1 + import { 2 + ALL_REGIONS, 3 + AVAILABLE_REGIONS, 4 + FLY_REGIONS, 5 + FREE_FLY_REGIONS, 6 + } from "@openstatus/regions"; 1 7 import { z } from "zod"; 2 8 3 - export const flyRegions = [ 4 - "ams", 5 - "arn", 6 - "atl", 7 - "bog", 8 - "bom", 9 - "bos", 10 - "cdg", 11 - "den", 12 - "dfw", 13 - "ewr", 14 - "eze", 15 - "fra", 16 - "gdl", 17 - "gig", 18 - "gru", 19 - "hkg", 20 - "iad", 21 - "jnb", 22 - "lax", 23 - "lhr", 24 - "mad", 25 - "mia", 26 - "nrt", 27 - "ord", 28 - "otp", 29 - "phx", 30 - "qro", 31 - "scl", 32 - "sjc", 33 - "sea", 34 - "sin", 35 - "syd", 36 - "waw", 37 - "yul", 38 - "yyz", 39 - ] as const; 40 - 41 - export const koyebRegions = [ 42 - "koyeb_fra", 43 - "koyeb_was", 44 - "koyeb_sin", 45 - "koyeb_tyo", 46 - "koyeb_par", 47 - "koyeb_sfo", 48 - ] as const; 49 - 50 - export const railwayRegions = [ 51 - "railway_europe-west4-drams3a", 52 - "railway_us-east4-eqdc4a", 53 - "railway_asia-southeast1-eqsg3a", 54 - "railway_us-west2", 55 - ] as const; 56 - 57 - export const freeFlyRegions = [ 58 - "iad", 59 - "ams", 60 - "gru", 61 - "syd", 62 - "sin", 63 - "jnb", 64 - ] as const satisfies (typeof flyRegions)[number][]; 65 - 66 9 export const monitorPeriodicity = [ 67 10 "30s", 68 11 "1m", ··· 73 16 "other", 74 17 ] as const; 75 18 76 - export const monitorRegions = [ 77 - ...flyRegions, 78 - ...koyebRegions, 79 - ...railwayRegions, 80 - ] as const; 81 - 19 + export const availableRegions = AVAILABLE_REGIONS; 20 + export const monitorRegions = ALL_REGIONS; 21 + export const freeFlyRegions = FREE_FLY_REGIONS; 22 + export const flyRegions = FLY_REGIONS; 82 23 export const monitorPeriodicitySchema = z.enum(monitorPeriodicity); 83 - export const monitorRegionSchema = z.enum(monitorRegions); 84 - export const monitorFlyRegionSchema = z.enum(flyRegions); 24 + export const monitorRegionSchema = z.enum(ALL_REGIONS); 25 + export const monitorFlyRegionSchema = z.enum(FLY_REGIONS); 85 26 86 27 export type MonitorFlyRegion = z.infer<typeof monitorFlyRegionSchema>; 87 28 export type Region = z.infer<typeof monitorRegionSchema>;
+5 -5
packages/db/src/schema/plan/config.ts
··· 1 - import { type Region, monitorRegions } from "../constants"; 1 + import { type Region, availableRegions } from "../constants"; 2 2 import type { WorkspacePlan } from "../workspaces/validation"; 3 3 import type { Limits } from "./schema"; 4 4 ··· 51 51 "notification-channels": 1, 52 52 members: 1, 53 53 "audit-log": false, 54 - regions: ["ams", "gru", "iad", "jnb", "sin", "syd"] satisfies Region[], 54 + regions: ["ams", "gru", "iad", "jnb", "hkg", "syd"] satisfies Region[], 55 55 "private-locations": false, 56 56 }, 57 57 }, ··· 89 89 "notification-channels": 10, 90 90 members: "Unlimited", 91 91 "audit-log": false, 92 - regions: [...monitorRegions] satisfies Region[], 92 + regions: [...availableRegions], 93 93 "private-locations": false, 94 94 }, 95 95 }, ··· 107 107 "synthetic-checks": 300, 108 108 periodicity: ["30s", "1m", "5m", "10m", "30m", "1h"], 109 109 "multi-region": true, 110 - "max-regions": 41, 110 + "max-regions": availableRegions.length, 111 111 "data-retention": "12 months", 112 112 "status-pages": 5, 113 113 maintenance: true, ··· 127 127 "notification-channels": 20, 128 128 members: "Unlimited", 129 129 "audit-log": true, 130 - regions: [...monitorRegions] satisfies Region[], 130 + regions: [...availableRegions], 131 131 "private-locations": false, 132 132 }, 133 133 },
+1
packages/notifications/email/package.json
··· 6 6 "dependencies": { 7 7 "@openstatus/db": "workspace:*", 8 8 "@openstatus/emails": "workspace:*", 9 + "@openstatus/regions": "workspace:*", 9 10 "@openstatus/tinybird": "workspace:*", 10 11 "@openstatus/utils": "workspace:*", 11 12 "@react-email/components": "0.0.36",
+1 -1
packages/notifications/email/src/index.ts
··· 6 6 7 7 import type { Region } from "@openstatus/db/src/schema/constants"; 8 8 import { EmailClient } from "@openstatus/emails/src/client"; 9 - import { regionDict } from "@openstatus/utils"; 9 + import { regionDict } from "@openstatus/regions"; 10 10 import { env } from "../env"; 11 11 12 12 const emailClient = new EmailClient({ apiKey: env.RESEND_API_KEY });
+495
packages/regions/index.ts
··· 1 + export const FLY_REGIONS = [ 2 + "ams", 3 + "arn", 4 + "atl", 5 + "bog", 6 + "bom", 7 + "bos", 8 + "cdg", 9 + "den", 10 + "dfw", 11 + "ewr", 12 + "eze", 13 + "fra", 14 + "gdl", 15 + "gig", 16 + "gru", 17 + "hkg", 18 + "iad", 19 + "jnb", 20 + "lax", 21 + "lhr", 22 + "mad", 23 + "mia", 24 + "nrt", 25 + "ord", 26 + "otp", 27 + "phx", 28 + "qro", 29 + "scl", 30 + "sjc", 31 + "sea", 32 + "sin", 33 + "syd", 34 + "waw", 35 + "yul", 36 + "yyz", 37 + ] as const; 38 + 39 + export const KOYEB_REGIONS = [ 40 + "koyeb_fra", 41 + "koyeb_was", 42 + "koyeb_sin", 43 + "koyeb_tyo", 44 + "koyeb_par", 45 + "koyeb_sfo", 46 + ] as const; 47 + 48 + export const RAILWAY_REGIONS = [ 49 + "railway_europe-west4-drams3a", 50 + "railway_us-east4-eqdc4a", 51 + "railway_asia-southeast1-eqsg3a", 52 + "railway_us-west2", 53 + ] as const; 54 + 55 + export const FREE_FLY_REGIONS = [ 56 + "iad", 57 + "ams", 58 + "gru", 59 + "syd", 60 + "sin", 61 + "jnb", 62 + ] as const satisfies (typeof FLY_REGIONS)[number][]; 63 + 64 + export const ALL_REGIONS = [ 65 + ...FLY_REGIONS, 66 + ...KOYEB_REGIONS, 67 + ...RAILWAY_REGIONS, 68 + ] as const; 69 + 70 + export type Region = (typeof ALL_REGIONS)[number]; 71 + 72 + export type Continent = 73 + | "Europe" 74 + | "North America" 75 + | "South America" 76 + | "Asia" 77 + | "Africa" 78 + | "Oceania"; 79 + 80 + export type RegionInfo = { 81 + code: Region; 82 + location: string; 83 + flag: string; 84 + continent: Continent; 85 + deprecated: boolean; 86 + provider: "fly" | "koyeb" | "railway"; 87 + }; 88 + 89 + // TODO: we could think of doing the inverse and use "EU" as key 90 + export const continentDict: Record<Continent, { code: string }> = { 91 + Europe: { code: "EU" }, 92 + "North America": { code: "NA" }, 93 + "South America": { code: "SA" }, 94 + Asia: { code: "AS" }, 95 + Africa: { code: "AF" }, 96 + Oceania: { code: "OC" }, 97 + }; 98 + 99 + export const regionDict: Record<Region, RegionInfo> = { 100 + ams: { 101 + code: "ams", 102 + location: "Amsterdam, Netherlands", 103 + flag: "🇳🇱", 104 + continent: "Europe", 105 + deprecated: false, 106 + provider: "fly", 107 + }, 108 + arn: { 109 + code: "arn", 110 + location: "Stockholm, Sweden", 111 + flag: "🇸🇪", 112 + continent: "Europe", 113 + deprecated: false, 114 + provider: "fly", 115 + }, 116 + 117 + atl: { 118 + code: "atl", 119 + location: "Atlanta, Georgia, USA", 120 + flag: "🇺🇸", 121 + continent: "North America", 122 + deprecated: true, 123 + provider: "fly", 124 + }, 125 + bog: { 126 + code: "bog", 127 + location: "Bogotá, Colombia", 128 + flag: "🇨🇴", 129 + continent: "South America", 130 + deprecated: true, 131 + provider: "fly", 132 + }, 133 + bom: { 134 + code: "bom", 135 + location: "Mumbai, India", 136 + flag: "🇮🇳", 137 + continent: "Asia", 138 + deprecated: false, 139 + provider: "fly", 140 + }, 141 + bos: { 142 + code: "bos", 143 + location: "Boston, Massachusetts, USA", 144 + flag: "🇺🇸", 145 + continent: "North America", 146 + deprecated: true, 147 + provider: "fly", 148 + }, 149 + cdg: { 150 + code: "cdg", 151 + location: "Paris, France", 152 + flag: "🇫🇷", 153 + continent: "Europe", 154 + deprecated: false, 155 + provider: "fly", 156 + }, 157 + den: { 158 + code: "den", 159 + location: "Denver, Colorado, USA", 160 + flag: "🇺🇸", 161 + continent: "North America", 162 + deprecated: true, 163 + provider: "fly", 164 + }, 165 + dfw: { 166 + code: "dfw", 167 + location: "Dallas, Texas, USA", 168 + flag: "🇺🇸", 169 + continent: "North America", 170 + deprecated: false, 171 + provider: "fly", 172 + }, 173 + ewr: { 174 + code: "ewr", 175 + location: "Secaucus, New Jersey, USA", 176 + flag: "🇺🇸", 177 + continent: "North America", 178 + deprecated: false, 179 + provider: "fly", 180 + }, 181 + eze: { 182 + code: "eze", 183 + location: "Ezeiza, Argentina", 184 + flag: "🇦🇷", 185 + continent: "South America", 186 + deprecated: true, 187 + provider: "fly", 188 + }, 189 + fra: { 190 + code: "fra", 191 + location: "Frankfurt, Germany", 192 + flag: "🇩🇪", 193 + continent: "Europe", 194 + deprecated: false, 195 + provider: "fly", 196 + }, 197 + gdl: { 198 + code: "gdl", 199 + location: "Guadalajara, Mexico", 200 + flag: "🇲🇽", 201 + continent: "North America", 202 + deprecated: true, 203 + provider: "fly", 204 + }, 205 + gig: { 206 + code: "gig", 207 + location: "Rio de Janeiro, Brazil", 208 + flag: "🇧🇷", 209 + continent: "South America", 210 + deprecated: true, 211 + provider: "fly", 212 + }, 213 + gru: { 214 + code: "gru", 215 + location: "Sao Paulo, Brazil", 216 + flag: "🇧🇷", 217 + continent: "South America", 218 + deprecated: false, 219 + provider: "fly", 220 + }, 221 + hkg: { 222 + code: "hkg", 223 + location: "Hong Kong, Hong Kong", 224 + flag: "🇭🇰", 225 + continent: "Asia", 226 + deprecated: true, 227 + provider: "fly", 228 + }, 229 + iad: { 230 + code: "iad", 231 + location: "Ashburn, Virginia, USA", 232 + flag: "🇺🇸", 233 + continent: "North America", 234 + deprecated: false, 235 + provider: "fly", 236 + }, 237 + jnb: { 238 + code: "jnb", 239 + location: "Johannesburg, South Africa", 240 + flag: "🇿🇦", 241 + continent: "Africa", 242 + deprecated: false, 243 + provider: "fly", 244 + }, 245 + lax: { 246 + code: "lax", 247 + location: "Los Angeles, California, USA", 248 + flag: "🇺🇸", 249 + continent: "North America", 250 + deprecated: false, 251 + provider: "fly", 252 + }, 253 + lhr: { 254 + code: "lhr", 255 + location: "London, United Kingdom", 256 + flag: "🇬🇧", 257 + continent: "Europe", 258 + deprecated: false, 259 + provider: "fly", 260 + }, 261 + mad: { 262 + code: "mad", 263 + location: "Madrid, Spain", 264 + flag: "🇪🇸", 265 + continent: "Europe", 266 + deprecated: true, 267 + provider: "fly", 268 + }, 269 + mia: { 270 + code: "mia", 271 + location: "Miami, Florida, USA", 272 + flag: "🇺🇸", 273 + continent: "North America", 274 + deprecated: true, 275 + provider: "fly", 276 + }, 277 + nrt: { 278 + code: "nrt", 279 + location: "Tokyo, Japan", 280 + flag: "🇯🇵", 281 + continent: "Asia", 282 + deprecated: false, 283 + provider: "fly", 284 + }, 285 + ord: { 286 + code: "ord", 287 + location: "Chicago, Illinois, USA", 288 + flag: "🇺🇸", 289 + continent: "North America", 290 + deprecated: false, 291 + provider: "fly", 292 + }, 293 + otp: { 294 + code: "otp", 295 + location: "Bucharest, Romania", 296 + flag: "🇷🇴", 297 + continent: "Europe", 298 + deprecated: true, 299 + provider: "fly", 300 + }, 301 + phx: { 302 + code: "phx", 303 + location: "Phoenix, Arizona, USA", 304 + flag: "🇺🇸", 305 + continent: "North America", 306 + deprecated: true, 307 + provider: "fly", 308 + }, 309 + qro: { 310 + code: "qro", 311 + location: "Querétaro, Mexico", 312 + flag: "🇲🇽", 313 + continent: "North America", 314 + deprecated: true, 315 + provider: "fly", 316 + }, 317 + scl: { 318 + code: "scl", 319 + location: "Santiago, Chile", 320 + flag: "🇨🇱", 321 + continent: "South America", 322 + deprecated: true, 323 + provider: "fly", 324 + }, 325 + sjc: { 326 + code: "sjc", 327 + location: "San Jose, California, USA", 328 + flag: "🇺🇸", 329 + continent: "North America", 330 + deprecated: false, 331 + provider: "fly", 332 + }, 333 + sea: { 334 + code: "sea", 335 + location: "Seattle, Washington, USA", 336 + flag: "🇺🇸", 337 + continent: "North America", 338 + deprecated: true, 339 + provider: "fly", 340 + }, 341 + sin: { 342 + code: "sin", 343 + location: "Singapore, Singapore", 344 + flag: "🇸🇬", 345 + continent: "Asia", 346 + deprecated: false, 347 + provider: "fly", 348 + }, 349 + syd: { 350 + code: "syd", 351 + location: "Sydney, Australia", 352 + flag: "🇦🇺", 353 + continent: "Oceania", 354 + deprecated: false, 355 + provider: "fly", 356 + }, 357 + waw: { 358 + code: "waw", 359 + location: "Warsaw, Poland", 360 + flag: "🇵🇱", 361 + continent: "Europe", 362 + deprecated: true, 363 + provider: "fly", 364 + }, 365 + yul: { 366 + code: "yul", 367 + location: "Montreal, Canada", 368 + flag: "🇨🇦", 369 + continent: "North America", 370 + deprecated: true, 371 + provider: "fly", 372 + }, 373 + yyz: { 374 + code: "yyz", 375 + location: "Toronto, Canada", 376 + flag: "🇨🇦", 377 + continent: "North America", 378 + deprecated: false, 379 + provider: "fly", 380 + }, 381 + koyeb_fra: { 382 + code: "koyeb_fra", 383 + location: "Frankfurt, Germany", 384 + flag: "🇩🇪", 385 + continent: "Europe", 386 + deprecated: false, 387 + provider: "koyeb", 388 + }, 389 + koyeb_par: { 390 + code: "koyeb_par", 391 + location: "Paris, France", 392 + flag: "🇫🇷", 393 + continent: "Europe", 394 + deprecated: false, 395 + provider: "koyeb", 396 + }, 397 + koyeb_sfo: { 398 + code: "koyeb_sfo", 399 + location: "San Francisco, USA", 400 + flag: "🇺🇸", 401 + continent: "North America", 402 + deprecated: false, 403 + provider: "koyeb", 404 + }, 405 + koyeb_sin: { 406 + code: "koyeb_sin", 407 + location: "Singapore, Singapore", 408 + flag: "🇸🇬", 409 + continent: "Asia", 410 + deprecated: false, 411 + provider: "koyeb", 412 + }, 413 + koyeb_tyo: { 414 + code: "koyeb_tyo", 415 + location: "Tokyo, Japan", 416 + flag: "🇯🇵", 417 + continent: "Asia", 418 + deprecated: false, 419 + provider: "koyeb", 420 + }, 421 + koyeb_was: { 422 + code: "koyeb_was", 423 + location: "Washington, USA", 424 + flag: "🇺🇸", 425 + continent: "North America", 426 + deprecated: false, 427 + provider: "koyeb", 428 + }, 429 + "railway_us-west2": { 430 + code: "railway_us-west2", 431 + location: "California, USA", 432 + flag: "🇺🇸", 433 + continent: "North America", 434 + deprecated: false, 435 + provider: "railway", 436 + }, 437 + "railway_us-east4-eqdc4a": { 438 + code: "railway_us-east4-eqdc4a", 439 + location: "Virginia, USA", 440 + flag: "🇺🇸", 441 + continent: "North America", 442 + deprecated: false, 443 + provider: "railway", 444 + }, 445 + "railway_europe-west4-drams3a": { 446 + code: "railway_europe-west4-drams3a", 447 + location: "Amsterdam, Netherlands", 448 + flag: "🇳🇱", 449 + continent: "Europe", 450 + deprecated: false, 451 + provider: "railway", 452 + }, 453 + "railway_asia-southeast1-eqsg3a": { 454 + code: "railway_asia-southeast1-eqsg3a", 455 + location: "Singapore, Singapore", 456 + flag: "🇸🇬", 457 + continent: "Asia", 458 + deprecated: false, 459 + provider: "railway", 460 + }, 461 + } as const; 462 + 463 + export const AVAILABLE_REGIONS = ALL_REGIONS.filter( 464 + (r) => !regionDict[r].deprecated, 465 + ); 466 + 467 + export function formatRegionCode(region: RegionInfo | Region) { 468 + const r = typeof region === "string" ? regionDict[region] : region; 469 + const suffix = r.code.replace(/(koyeb_|railway_|fly_)/g, ""); 470 + 471 + if (r.provider === "railway") { 472 + return suffix.replace(/(-eqdc4a|-eqsg3a|-drams3a)/g, ""); 473 + } 474 + 475 + return suffix; 476 + } 477 + 478 + export const groupByContinent = Object.entries(regionDict).reduce< 479 + Record<Continent, RegionInfo[]> 480 + >( 481 + (acc, [_key, value]) => { 482 + Object.assign(acc, { 483 + [value.continent]: [...acc[value.continent], value], 484 + }); 485 + return acc; 486 + }, 487 + { 488 + "North America": [], 489 + Europe: [], 490 + "South America": [], 491 + Oceania: [], 492 + Asia: [], 493 + Africa: [], 494 + }, 495 + );
+17
packages/regions/package.json
··· 1 + { 2 + "name": "@openstatus/regions", 3 + "version": "1.0.0", 4 + "description": "", 5 + "main": "index.ts", 6 + "scripts": {}, 7 + "dependencies": { 8 + "zod": "3.24.2" 9 + }, 10 + "devDependencies": { 11 + "@openstatus/tsconfig": "workspace:*", 12 + "typescript": "5.7.2" 13 + }, 14 + "keywords": [], 15 + "author": "", 16 + "license": "ISC" 17 + }
+4
packages/regions/tsconfig.json
··· 1 + { 2 + "extends": "@openstatus/tsconfig/base.json", 3 + "include": ["src", "*.ts"] 4 + }
-448
packages/utils/index.ts
··· 1 - import type { Region } from "@openstatus/db/src/schema/constants"; 2 - 3 1 import { base } from "@openstatus/assertions"; 4 2 import { monitorMethods, monitorStatus } from "@openstatus/db/src/schema"; 5 3 6 4 import { z } from "zod"; 7 - 8 - export type Continent = 9 - | "Europe" 10 - | "North America" 11 - | "South America" 12 - | "Asia" 13 - | "Africa" 14 - | "Oceania"; 15 - 16 - export type RegionInfo = { 17 - code: Region; 18 - location: string; 19 - flag: string; 20 - continent: Continent; 21 - deprecated: boolean; 22 - provider: "fly" | "koyeb" | "railway"; 23 - }; 24 - 25 - // TODO: we could think of doing the inverse and use "EU" as key 26 - export const continentDict: Record<Continent, { code: string }> = { 27 - Europe: { code: "EU" }, 28 - "North America": { code: "NA" }, 29 - "South America": { code: "SA" }, 30 - Asia: { code: "AS" }, 31 - Africa: { code: "AF" }, 32 - Oceania: { code: "OC" }, 33 - }; 34 - 35 - export const regionDict: Record<Region, RegionInfo> = { 36 - ams: { 37 - code: "ams", 38 - location: "Amsterdam, Netherlands", 39 - flag: "🇳🇱", 40 - continent: "Europe", 41 - deprecated: false, 42 - provider: "fly", 43 - }, 44 - arn: { 45 - code: "arn", 46 - location: "Stockholm, Sweden", 47 - flag: "🇸🇪", 48 - continent: "Europe", 49 - deprecated: false, 50 - provider: "fly", 51 - }, 52 - 53 - atl: { 54 - code: "atl", 55 - location: "Atlanta, Georgia, USA", 56 - flag: "🇺🇸", 57 - continent: "North America", 58 - deprecated: true, 59 - provider: "fly", 60 - }, 61 - bog: { 62 - code: "bog", 63 - location: "Bogotá, Colombia", 64 - flag: "🇨🇴", 65 - continent: "South America", 66 - deprecated: true, 67 - provider: "fly", 68 - }, 69 - bom: { 70 - code: "bom", 71 - location: "Mumbai, India", 72 - flag: "🇮🇳", 73 - continent: "Asia", 74 - deprecated: false, 75 - provider: "fly", 76 - }, 77 - bos: { 78 - code: "bos", 79 - location: "Boston, Massachusetts, USA", 80 - flag: "🇺🇸", 81 - continent: "North America", 82 - deprecated: true, 83 - provider: "fly", 84 - }, 85 - cdg: { 86 - code: "cdg", 87 - location: "Paris, France", 88 - flag: "🇫🇷", 89 - continent: "Europe", 90 - deprecated: false, 91 - provider: "fly", 92 - }, 93 - den: { 94 - code: "den", 95 - location: "Denver, Colorado, USA", 96 - flag: "🇺🇸", 97 - continent: "North America", 98 - deprecated: true, 99 - provider: "fly", 100 - }, 101 - dfw: { 102 - code: "dfw", 103 - location: "Dallas, Texas, USA", 104 - flag: "🇺🇸", 105 - continent: "North America", 106 - deprecated: false, 107 - provider: "fly", 108 - }, 109 - ewr: { 110 - code: "ewr", 111 - location: "Secaucus, New Jersey, USA", 112 - flag: "🇺🇸", 113 - continent: "North America", 114 - deprecated: false, 115 - provider: "fly", 116 - }, 117 - eze: { 118 - code: "eze", 119 - location: "Ezeiza, Argentina", 120 - flag: "🇦🇷", 121 - continent: "South America", 122 - deprecated: true, 123 - provider: "fly", 124 - }, 125 - fra: { 126 - code: "fra", 127 - location: "Frankfurt, Germany", 128 - flag: "🇩🇪", 129 - continent: "Europe", 130 - deprecated: false, 131 - provider: "fly", 132 - }, 133 - gdl: { 134 - code: "gdl", 135 - location: "Guadalajara, Mexico", 136 - flag: "🇲🇽", 137 - continent: "North America", 138 - deprecated: true, 139 - provider: "fly", 140 - }, 141 - gig: { 142 - code: "gig", 143 - location: "Rio de Janeiro, Brazil", 144 - flag: "🇧🇷", 145 - continent: "South America", 146 - deprecated: true, 147 - provider: "fly", 148 - }, 149 - gru: { 150 - code: "gru", 151 - location: "Sao Paulo, Brazil", 152 - flag: "🇧🇷", 153 - continent: "South America", 154 - deprecated: false, 155 - provider: "fly", 156 - }, 157 - hkg: { 158 - code: "hkg", 159 - location: "Hong Kong, Hong Kong", 160 - flag: "🇭🇰", 161 - continent: "Asia", 162 - deprecated: true, 163 - provider: "fly", 164 - }, 165 - iad: { 166 - code: "iad", 167 - location: "Ashburn, Virginia, USA", 168 - flag: "🇺🇸", 169 - continent: "North America", 170 - deprecated: false, 171 - provider: "fly", 172 - }, 173 - jnb: { 174 - code: "jnb", 175 - location: "Johannesburg, South Africa", 176 - flag: "🇿🇦", 177 - continent: "Africa", 178 - deprecated: false, 179 - provider: "fly", 180 - }, 181 - lax: { 182 - code: "lax", 183 - location: "Los Angeles, California, USA", 184 - flag: "🇺🇸", 185 - continent: "North America", 186 - deprecated: false, 187 - provider: "fly", 188 - }, 189 - lhr: { 190 - code: "lhr", 191 - location: "London, United Kingdom", 192 - flag: "🇬🇧", 193 - continent: "Europe", 194 - deprecated: false, 195 - provider: "fly", 196 - }, 197 - mad: { 198 - code: "mad", 199 - location: "Madrid, Spain", 200 - flag: "🇪🇸", 201 - continent: "Europe", 202 - deprecated: true, 203 - provider: "fly", 204 - }, 205 - mia: { 206 - code: "mia", 207 - location: "Miami, Florida, USA", 208 - flag: "🇺🇸", 209 - continent: "North America", 210 - deprecated: true, 211 - provider: "fly", 212 - }, 213 - nrt: { 214 - code: "nrt", 215 - location: "Tokyo, Japan", 216 - flag: "🇯🇵", 217 - continent: "Asia", 218 - deprecated: false, 219 - provider: "fly", 220 - }, 221 - ord: { 222 - code: "ord", 223 - location: "Chicago, Illinois, USA", 224 - flag: "🇺🇸", 225 - continent: "North America", 226 - deprecated: false, 227 - provider: "fly", 228 - }, 229 - otp: { 230 - code: "otp", 231 - location: "Bucharest, Romania", 232 - flag: "🇷🇴", 233 - continent: "Europe", 234 - deprecated: true, 235 - provider: "fly", 236 - }, 237 - phx: { 238 - code: "phx", 239 - location: "Phoenix, Arizona, USA", 240 - flag: "🇺🇸", 241 - continent: "North America", 242 - deprecated: true, 243 - provider: "fly", 244 - }, 245 - qro: { 246 - code: "qro", 247 - location: "Querétaro, Mexico", 248 - flag: "🇲🇽", 249 - continent: "North America", 250 - deprecated: true, 251 - provider: "fly", 252 - }, 253 - scl: { 254 - code: "scl", 255 - location: "Santiago, Chile", 256 - flag: "🇨🇱", 257 - continent: "South America", 258 - deprecated: true, 259 - provider: "fly", 260 - }, 261 - sjc: { 262 - code: "sjc", 263 - location: "San Jose, California, USA", 264 - flag: "🇺🇸", 265 - continent: "North America", 266 - deprecated: false, 267 - provider: "fly", 268 - }, 269 - sea: { 270 - code: "sea", 271 - location: "Seattle, Washington, USA", 272 - flag: "🇺🇸", 273 - continent: "North America", 274 - deprecated: true, 275 - provider: "fly", 276 - }, 277 - sin: { 278 - code: "sin", 279 - location: "Singapore, Singapore", 280 - flag: "🇸🇬", 281 - continent: "Asia", 282 - deprecated: false, 283 - provider: "fly", 284 - }, 285 - syd: { 286 - code: "syd", 287 - location: "Sydney, Australia", 288 - flag: "🇦🇺", 289 - continent: "Oceania", 290 - deprecated: false, 291 - provider: "fly", 292 - }, 293 - waw: { 294 - code: "waw", 295 - location: "Warsaw, Poland", 296 - flag: "🇵🇱", 297 - continent: "Europe", 298 - deprecated: true, 299 - provider: "fly", 300 - }, 301 - yul: { 302 - code: "yul", 303 - location: "Montreal, Canada", 304 - flag: "🇨🇦", 305 - continent: "North America", 306 - deprecated: true, 307 - provider: "fly", 308 - }, 309 - yyz: { 310 - code: "yyz", 311 - location: "Toronto, Canada", 312 - flag: "🇨🇦", 313 - continent: "North America", 314 - deprecated: false, 315 - provider: "fly", 316 - }, 317 - koyeb_fra: { 318 - code: "koyeb_fra", 319 - location: "Frankfurt, Germany", 320 - flag: "🇩🇪", 321 - continent: "Europe", 322 - deprecated: false, 323 - provider: "koyeb", 324 - }, 325 - koyeb_par: { 326 - code: "koyeb_par", 327 - location: "Paris, France", 328 - flag: "🇫🇷", 329 - continent: "Europe", 330 - deprecated: false, 331 - provider: "koyeb", 332 - }, 333 - koyeb_sfo: { 334 - code: "koyeb_sfo", 335 - location: "San Francisco, USA", 336 - flag: "🇺🇸", 337 - continent: "North America", 338 - deprecated: false, 339 - provider: "koyeb", 340 - }, 341 - koyeb_sin: { 342 - code: "koyeb_sin", 343 - location: "Singapore, Singapore", 344 - flag: "🇸🇬", 345 - continent: "Asia", 346 - deprecated: false, 347 - provider: "koyeb", 348 - }, 349 - koyeb_tyo: { 350 - code: "koyeb_tyo", 351 - location: "Tokyo, Japan", 352 - flag: "🇯🇵", 353 - continent: "Asia", 354 - deprecated: false, 355 - provider: "koyeb", 356 - }, 357 - koyeb_was: { 358 - code: "koyeb_was", 359 - location: "Washington, USA", 360 - flag: "🇺🇸", 361 - continent: "North America", 362 - deprecated: false, 363 - provider: "koyeb", 364 - }, 365 - "railway_us-west2": { 366 - code: "railway_us-west2", 367 - location: "California, USA", 368 - flag: "🇺🇸", 369 - continent: "North America", 370 - deprecated: false, 371 - provider: "railway", 372 - }, 373 - "railway_us-east4-eqdc4a": { 374 - code: "railway_us-east4-eqdc4a", 375 - location: "Virginia, USA", 376 - flag: "🇺🇸", 377 - continent: "North America", 378 - deprecated: false, 379 - provider: "railway", 380 - }, 381 - "railway_europe-west4-drams3a": { 382 - code: "railway_europe-west4-drams3a", 383 - location: "Amsterdam, Netherlands", 384 - flag: "🇳🇱", 385 - continent: "Europe", 386 - deprecated: false, 387 - provider: "railway", 388 - }, 389 - "railway_asia-southeast1-eqsg3a": { 390 - code: "railway_asia-southeast1-eqsg3a", 391 - location: "Singapore, Singapore", 392 - flag: "🇸🇬", 393 - continent: "Asia", 394 - deprecated: false, 395 - provider: "railway", 396 - }, 397 - } as const; 398 - 399 - export function formatRegionCode(region: RegionInfo | Region) { 400 - const r = typeof region === "string" ? regionDict[region] : region; 401 - const suffix = r.code.replace(/(koyeb_|railway_|fly_)/g, ""); 402 - 403 - if (r.provider === "railway") { 404 - return suffix.replace(/(-eqdc4a|-eqsg3a|-drams3a)/g, ""); 405 - } 406 - 407 - return suffix; 408 - } 409 - 410 - export const groupByContinent = Object.entries(regionDict).reduce< 411 - Record<Continent, RegionInfo[]> 412 - >( 413 - (acc, [_key, value]) => { 414 - Object.assign(acc, { 415 - [value.continent]: [...acc[value.continent], value], 416 - }); 417 - return acc; 418 - }, 419 - { 420 - "North America": [], 421 - Europe: [], 422 - "South America": [], 423 - Oceania: [], 424 - Asia: [], 425 - Africa: [], 426 - }, 427 - ); 428 - 429 - export const vercelRegions = [ 430 - "arn1", 431 - "bom1", 432 - "cdg1", 433 - "cle1", 434 - "cpt1", 435 - "dub1", 436 - "fra1", 437 - "gru1", 438 - "hkg1", 439 - "hnd1", 440 - "iad1", 441 - "icn1", 442 - "kix1", 443 - "lhr1", 444 - "pdx1", 445 - "sfo1", 446 - "sin1", 447 - "syd1", 448 - ] as const; 449 - 450 - // export const availableRegions = [...vercelRegions, ...flyRegions] as const; 451 - 452 - // export const regionsDict = { ...vercelRegionsDict, ...flyRegionsDict } as const; 453 5 454 6 export const httpPayloadSchema = z.object({ 455 7 workspaceId: z.string(),
+6 -4
packages/utils/package.json
··· 4 4 "description": "", 5 5 "main": "index.ts", 6 6 "scripts": {}, 7 - "dependencies": {}, 8 - "devDependencies": { 7 + "dependencies": { 9 8 "@openstatus/assertions": "workspace:*", 10 9 "@openstatus/db": "workspace:*", 11 - "@openstatus/tsconfig": "workspace:*", 12 - "typescript": "5.7.2", 10 + "@openstatus/regions": "workspace:*", 13 11 "zod": "3.24.2" 12 + }, 13 + "devDependencies": { 14 + "@openstatus/tsconfig": "workspace:*", 15 + "typescript": "5.7.2" 14 16 }, 15 17 "keywords": [], 16 18 "author": "",
+51 -16
pnpm-lock.yaml
··· 113 113 '@openstatus/react': 114 114 specifier: workspace:* 115 115 version: link:../../packages/react 116 + '@openstatus/regions': 117 + specifier: workspace:* 118 + version: link:../../packages/regions 116 119 '@openstatus/theme-store': 117 120 specifier: workspace:* 118 121 version: link:../../packages/theme-store ··· 187 190 version: 1.2.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) 188 191 '@sentry/nextjs': 189 192 specifier: 8.46.0 190 - version: 8.46.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(webpack@5.97.1) 193 + version: 8.46.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.5.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(webpack@5.97.1) 191 194 '@stripe/stripe-js': 192 195 specifier: 2.1.6 193 196 version: 2.1.6 ··· 202 205 version: 11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2) 203 206 '@trpc/next': 204 207 specifier: 11.4.4 205 - version: 11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/react-query@11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2) 208 + version: 11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/react-query@11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(next@15.5.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2) 206 209 '@trpc/react-query': 207 210 specifier: 11.4.4 208 211 version: 11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2) ··· 440 443 '@openstatus/error': 441 444 specifier: workspace:* 442 445 version: link:../../packages/error 446 + '@openstatus/regions': 447 + specifier: workspace:* 448 + version: link:../../packages/regions 443 449 '@openstatus/tinybird': 444 450 specifier: workspace:* 445 451 version: link:../../packages/tinybird ··· 650 656 version: 1.2.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) 651 657 '@sentry/nextjs': 652 658 specifier: 8.46.0 653 - version: 8.46.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(webpack@5.97.1) 659 + version: 8.46.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.5.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(webpack@5.97.1) 654 660 '@stripe/stripe-js': 655 661 specifier: 2.1.6 656 662 version: 2.1.6 ··· 665 671 version: 11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2) 666 672 '@trpc/next': 667 673 specifier: 11.4.4 668 - version: 11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/react-query@11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2) 674 + version: 11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/react-query@11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(next@15.5.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2) 669 675 '@trpc/react-query': 670 676 specifier: 11.4.4 671 677 version: 11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2) ··· 853 859 '@openstatus/react': 854 860 specifier: workspace:* 855 861 version: link:../../packages/react 862 + '@openstatus/regions': 863 + specifier: workspace:* 864 + version: link:../../packages/regions 856 865 '@openstatus/tinybird': 857 866 specifier: workspace:* 858 867 version: link:../../packages/tinybird ··· 1180 1189 '@openstatus/error': 1181 1190 specifier: workspace:* 1182 1191 version: link:../error 1192 + '@openstatus/regions': 1193 + specifier: workspace:* 1194 + version: link:../regions 1183 1195 '@openstatus/tinybird': 1184 1196 specifier: workspace:* 1185 1197 version: link:../tinybird ··· 1263 1275 '@libsql/client': 1264 1276 specifier: 0.15.14 1265 1277 version: 0.15.14(bufferutil@4.0.8)(utf-8-validate@6.0.5) 1278 + '@openstatus/assertions': 1279 + specifier: workspace:* 1280 + version: link:../assertions 1281 + '@openstatus/regions': 1282 + specifier: workspace:* 1283 + version: link:../regions 1266 1284 '@t3-oss/env-core': 1267 1285 specifier: 0.7.1 1268 1286 version: 0.7.1(typescript@5.7.2)(zod@3.24.2) ··· 1276 1294 specifier: 3.24.2 1277 1295 version: 3.24.2 1278 1296 devDependencies: 1279 - '@openstatus/assertions': 1280 - specifier: workspace:* 1281 - version: link:../assertions 1282 1297 '@openstatus/tsconfig': 1283 1298 specifier: workspace:* 1284 1299 version: link:../tsconfig ··· 1415 1430 '@openstatus/emails': 1416 1431 specifier: workspace:* 1417 1432 version: link:../../emails 1433 + '@openstatus/regions': 1434 + specifier: workspace:* 1435 + version: link:../../regions 1418 1436 '@openstatus/tinybird': 1419 1437 specifier: workspace:* 1420 1438 version: link:../../tinybird ··· 1631 1649 specifier: 5.7.2 1632 1650 version: 5.7.2 1633 1651 1652 + packages/regions: 1653 + dependencies: 1654 + zod: 1655 + specifier: 3.24.2 1656 + version: 3.24.2 1657 + devDependencies: 1658 + '@openstatus/tsconfig': 1659 + specifier: workspace:* 1660 + version: link:../tsconfig 1661 + typescript: 1662 + specifier: 5.7.2 1663 + version: 5.7.2 1664 + 1634 1665 packages/theme-store: 1635 1666 devDependencies: 1636 1667 '@openstatus/tsconfig': ··· 1869 1900 version: 5.7.2 1870 1901 1871 1902 packages/utils: 1872 - devDependencies: 1903 + dependencies: 1873 1904 '@openstatus/assertions': 1874 1905 specifier: workspace:* 1875 1906 version: link:../assertions 1876 1907 '@openstatus/db': 1877 1908 specifier: workspace:* 1878 1909 version: link:../db 1910 + '@openstatus/regions': 1911 + specifier: workspace:* 1912 + version: link:../regions 1913 + zod: 1914 + specifier: 3.24.2 1915 + version: 3.24.2 1916 + devDependencies: 1879 1917 '@openstatus/tsconfig': 1880 1918 specifier: workspace:* 1881 1919 version: link:../tsconfig 1882 1920 typescript: 1883 1921 specifier: 5.7.2 1884 1922 version: 5.7.2 1885 - zod: 1886 - specifier: 3.24.2 1887 - version: 3.24.2 1888 1923 1889 1924 packages: 1890 1925 ··· 16339 16374 '@sentry/types': 8.9.2 16340 16375 '@sentry/utils': 8.9.2 16341 16376 16342 - '@sentry/nextjs@8.46.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(webpack@5.97.1(esbuild@0.21.5))': 16377 + '@sentry/nextjs@8.46.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.5.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(webpack@5.97.1)': 16343 16378 dependencies: 16344 16379 '@opentelemetry/api': 1.9.0 16345 16380 '@opentelemetry/semantic-conventions': 1.28.0 ··· 16350 16385 '@sentry/opentelemetry': 8.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.28.0) 16351 16386 '@sentry/react': 8.46.0(react@19.1.1) 16352 16387 '@sentry/vercel-edge': 8.46.0 16353 - '@sentry/webpack-plugin': 2.22.7(encoding@0.1.13)(webpack@5.97.1(esbuild@0.21.5)) 16388 + '@sentry/webpack-plugin': 2.22.7(encoding@0.1.13)(webpack@5.97.1) 16354 16389 chalk: 3.0.0 16355 16390 next: 15.5.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) 16356 16391 resolve: 1.22.8 ··· 16365 16400 - supports-color 16366 16401 - webpack 16367 16402 16368 - '@sentry/nextjs@8.46.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(webpack@5.97.1)': 16403 + '@sentry/nextjs@8.46.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(webpack@5.97.1(esbuild@0.21.5))': 16369 16404 dependencies: 16370 16405 '@opentelemetry/api': 1.9.0 16371 16406 '@opentelemetry/semantic-conventions': 1.28.0 ··· 16376 16411 '@sentry/opentelemetry': 8.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.28.0) 16377 16412 '@sentry/react': 8.46.0(react@19.1.1) 16378 16413 '@sentry/vercel-edge': 8.46.0 16379 - '@sentry/webpack-plugin': 2.22.7(encoding@0.1.13)(webpack@5.97.1) 16414 + '@sentry/webpack-plugin': 2.22.7(encoding@0.1.13)(webpack@5.97.1(esbuild@0.21.5)) 16380 16415 chalk: 3.0.0 16381 16416 next: 15.5.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) 16382 16417 resolve: 1.22.8 ··· 17129 17164 '@tanstack/react-query': 5.80.7(react@19.1.1) 17130 17165 '@trpc/react-query': 11.4.4(@tanstack/react-query@5.80.7(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2) 17131 17166 17132 - '@trpc/next@11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/react-query@11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2)': 17167 + '@trpc/next@11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/react-query@11.4.4(@tanstack/react-query@5.81.5(react@19.1.1))(@trpc/client@11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2))(@trpc/server@11.4.4(typescript@5.7.2))(next@15.5.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.7.2)': 17133 17168 dependencies: 17134 17169 '@trpc/client': 11.4.4(@trpc/server@11.4.4(typescript@5.7.2))(typescript@5.7.2) 17135 17170 '@trpc/server': 11.4.4(typescript@5.7.2)