Some checks failed
CI / Run lints and checks (push) Failing after 47s
CI / Run tests (push) Failing after 1s
CI / Run race tests (push) Failing after 5s
CI / Build CLI docs (push) Has been skipped
CI / Run buf actions (push) Failing after 5s
CodeQL / Analyze (go) (push) Failing after 3s
CodeQL / Analyze (javascript) (push) Failing after 2s
Docker Image Scanners / scanners (push) Failing after 3s
Format / format (push) Failing after 3s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Draft newsletter (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
143 lines
3.6 KiB
Go
143 lines
3.6 KiB
Go
// Copyright © 2026 Ory Corp
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Package region defines the Ory Network region enumeration. Lives in x/ so
|
|
// kratos-oss and other OSS layers can use it without importing cloudlib.
|
|
package region
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/ory/herodot"
|
|
)
|
|
|
|
// Region is an Ory Network region. Specific regions map to a single CRDB
|
|
// region; super-regions (EU, Asia, US, Global) group specific regions that
|
|
// share a data-residency boundary.
|
|
//
|
|
// swagger:enum Region
|
|
type Region string
|
|
|
|
const (
|
|
EUCentral Region = "eu-central"
|
|
AsiaNorthEast Region = "asia-northeast"
|
|
USEast Region = "us-east"
|
|
USWest Region = "us-west"
|
|
|
|
EU Region = "eu"
|
|
Asia Region = "asia"
|
|
US Region = "us"
|
|
Global Region = "global"
|
|
)
|
|
|
|
// All returns every valid region in stable order: specific regions first,
|
|
// then super-regions.
|
|
func All() []Region {
|
|
return []Region{EUCentral, AsiaNorthEast, USEast, USWest, EU, Asia, US, Global}
|
|
}
|
|
|
|
func (r Region) String() string {
|
|
return string(r)
|
|
}
|
|
|
|
// Valid reports whether r is a known region.
|
|
func (r Region) Valid() bool {
|
|
switch r {
|
|
case EUCentral, AsiaNorthEast, USEast, USWest, EU, Asia, US, Global:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsSuperRegion reports whether r is a super-region.
|
|
func (r Region) IsSuperRegion() bool {
|
|
switch r {
|
|
case EU, Asia, US, Global:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Contains reports whether r contains other:
|
|
// - Global contains every valid region.
|
|
// - EU contains EUCentral; Asia contains AsiaNorthEast; US contains USEast and USWest.
|
|
// - Every region contains itself.
|
|
func (r Region) Contains(other Region) bool {
|
|
if !r.Valid() || !other.Valid() {
|
|
return false
|
|
}
|
|
if r == Global || r == other {
|
|
return true
|
|
}
|
|
switch r {
|
|
case EU:
|
|
return other == EUCentral
|
|
case Asia:
|
|
return other == AsiaNorthEast
|
|
case US:
|
|
return other == USEast || other == USWest
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Scan implements sql.Scanner. NULL and empty scan to the zero value;
|
|
// validate via Region.Valid if "unset" must be rejected.
|
|
func (r *Region) Scan(src any) error {
|
|
switch s := src.(type) {
|
|
case nil:
|
|
*r = ""
|
|
case string:
|
|
*r = Region(s)
|
|
case []byte:
|
|
*r = Region(s)
|
|
default:
|
|
return errors.Errorf("cannot scan %T into region.Region", src)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Value implements driver.Valuer. The empty Region writes as "".
|
|
func (r Region) Value() (driver.Value, error) {
|
|
return string(r), nil
|
|
}
|
|
|
|
// IsEqual compares two nullable *Region pointers (both nil = equal).
|
|
func IsEqual(a, b *Region) bool {
|
|
if a == nil && b == nil {
|
|
return true
|
|
}
|
|
if a == nil || b == nil {
|
|
return false
|
|
}
|
|
return *a == *b
|
|
}
|
|
|
|
// ErrInvalid is wrapped when a submitted region is not a known value.
|
|
// Use NewErrInvalid for a herodot 400; use errors.Is for chain checks.
|
|
var ErrInvalid = errors.New("the provided region is not a valid Ory region")
|
|
|
|
// ErrNotAllowed is wrapped when a valid region is outside the project's
|
|
// home_region constraint.
|
|
var ErrNotAllowed = errors.New("the provided region is not allowed by this project's home region")
|
|
|
|
// NewErrInvalid returns a fresh herodot 400 wrapping ErrInvalid.
|
|
func NewErrInvalid() error {
|
|
return errors.WithStack(
|
|
herodot.ErrBadRequest().
|
|
WithReason(ErrInvalid.Error()).
|
|
WithDebug(`region must be one of eu-central, asia-northeast, us-east, us-west, eu, asia, us, global`).
|
|
WithWrap(ErrInvalid),
|
|
)
|
|
}
|
|
|
|
// NewErrNotAllowed returns a fresh herodot 400 wrapping ErrNotAllowed.
|
|
func NewErrNotAllowed() error {
|
|
return errors.WithStack(
|
|
herodot.ErrBadRequest().
|
|
WithReason(ErrNotAllowed.Error()).
|
|
WithWrap(ErrNotAllowed),
|
|
)
|
|
}
|