feat(remote-config): add static fallback config endpoint (#7182)

* feat(remote-config): add static fallback config endpoint

* refactor(remote-config): clarify static fallback path name

* test(remote-config): cover static fallback signature failures

* fix(remote-config): use static fallback only without cache

* test(remote-config): cover static fallback external blobs

* refactor(remote-config): align static fallback naming

* refactor(remote-config): scope static fallback path

* fix(remote-config): mark fallback no content fresh

* fix(remote-config): align fallback accept headers

* refactor(remote-config): rename fallback endpoint types

* fix(remote-config): enable etags for fallback config

* fix(remote-config): skip fallback when proxy is configured

* fix(remote-config): rely on etag cache for fallback

* refactor(remote-config): reuse fallback retry eligibility

* fix(remote-config): disable after fallback client errors
This commit is contained in:
Rick authored and GitHub committed 2026-07-10 14:17:31 +02:00
1 parent cba4ccddee
commit b82223e5a1
22 files changed
+994 -36

No files matched your search

@@ -153,6 +153,12 @@ extension HTTPRequest {
}
enum FallbackPath: Hashable {
case remoteConfig(domain: String)
}
enum FeatureEventsPath: Hashable {
case postEvents
@@ -196,8 +202,6 @@ extension HTTPRequest.Path: HTTPRequestPath {
return "/v1/offerings"
case .getProductEntitlementMapping:
return "/v1/product_entitlement_mapping"
case let .remoteConfig(domain):
return "/v1/config/\(Self.escape(domain))"
default:
return nil
}
@@ -485,3 +489,66 @@ extension HTTPRequest.Path: HTTPRequestPath {
return appUserID.trimmedAndEscaped
}
}
extension HTTPRequest.FallbackPath: HTTPRequestPath {
// swiftlint:disable:next force_unwrapping
static let serverHostURL = URL(string: "https://api-production.8-lives-cat.io")!
var authenticated: Bool {
switch self {
case .remoteConfig:
return true
}
}
var shouldSendEtag: Bool {
switch self {
case .remoteConfig:
return true
}
}
var supportsSignatureVerification: Bool {
switch self {
case .remoteConfig:
return true
}
}
var needsNonceForSigning: Bool {
switch self {
case .remoteConfig:
return false
}
}
var responseSignatureContextProvider: ResponseSignatureContextProvider {
switch self {
case .remoteConfig:
return FallbackSignatureContextProvider()
}
}
var relativePath: String {
switch self {
case let .remoteConfig(domain):
return "/v1/config/\(domain.trimmedAndEscaped)"
}
}
var name: String {
switch self {
case .remoteConfig:
return "remote_config_fallback"
}
}
var additionalHeaders: HTTPRequest.Headers {
switch self {
case .remoteConfig:
return [:]
}
}
}