Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
88dfac6
Fetch MiniMax Token Plan recharge credit balance
Yuxin-Qiao Jul 1, 2026
972cffa
Address MiniMax credit balance review feedback
Yuxin-Qiao Jul 1, 2026
2431a49
Persist MiniMax API region after global-to-CN retry.
Yuxin-Qiao Jul 1, 2026
d58793c
Re-trigger CI after cancelled macOS shards.
Yuxin-Qiao Jul 1, 2026
8d40b54
chore: retrigger CI after cancelled runs.
Yuxin-Qiao Jul 1, 2026
227ed49
Address ClawSweeper MiniMax credit review findings.
Yuxin-Qiao Jul 1, 2026
94b454e
Re-trigger CI for ClawSweeper follow-up.
Yuxin-Qiao Jul 1, 2026
6c49ef2
Merge upstream main and resolve CHANGELOG conflict.
Yuxin-Qiao Jul 1, 2026
6a3451d
Avoid persisting MiniMax env fallback region
Yuxin-Qiao Jul 2, 2026
30cf613
Keep MiniMax fallback region fetch-scoped
Yuxin-Qiao Jul 2, 2026
adbc2c2
Remove stale MiniMax region persistence release note.
Yuxin-Qiao Jul 2, 2026
a3137c8
Align no-billing MiniMax test with credit enrichment request.
Yuxin-Qiao Jul 2, 2026
1883738
Update MiniMax web fetch tests for token plan credit requests.
Yuxin-Qiao Jul 2, 2026
17f2e21
Add MiniMax usage summary dashboard and quota utilization charts.
Yuxin-Qiao Jul 2, 2026
204dde1
Merge upstream main and resolve zh-Hant localization conflict.
Yuxin-Qiao Jul 2, 2026
2baec7b
Fix MiniMax reset timing, pricing, and CI compile failures.
Yuxin-Qiao Jul 2, 2026
e5c0443
Document MiniMax usage dashboard scope in changelog and docs.
Yuxin-Qiao Jul 2, 2026
c446b1a
Fix MiniMax reset description test compile timeout in CI.
Yuxin-Qiao Jul 2, 2026
8c248c1
Improve MiniMax web enrichment for credits and usage summary.
Yuxin-Qiao Jul 2, 2026
bc0b960
Fix PR 1821 CI: update MiniMax test and complete tr/it/id/pl locales
cursoragent Jul 2, 2026
4be8e94
Translate Italian MiniMax cache-hit strings for localization catalog …
cursoragent Jul 2, 2026
c8541d9
Update MiniMaxProviderTests for always-on credit and usage-summary en…
cursoragent Jul 2, 2026
1b14fa1
Address ClawSweeper P2 review findings for MiniMax enrichment
cursoragent Jul 2, 2026
b7470c9
Fix MiniMax plan utilization helper closure call labels
cursoragent Jul 2, 2026
b447e20
Map MiniMax weekly window type to 10080 minutes in plan history
cursoragent Jul 2, 2026
98d35cd
Align MiniMax cost dashboard tests with cost-summary toggle
cursoragent Jul 2, 2026
ee3547c
Gate MiniMax generic cost-history dashboard on cost-summary toggle
cursoragent Jul 3, 2026
0a20638
Align MiniMax docs with explicit-cookie-only API enrichment
cursoragent Jul 3, 2026
0728e28
Add MiniMax web session expiry detection and re-import UX.
Yuxin-Qiao Jul 3, 2026
2185751
Harden MiniMax web session recovery and menu switch prewarm.
Yuxin-Qiao Jul 3, 2026
669f6fd
Fix PR 1821 CI: add MiniMax web session locale keys
cursoragent Jul 3, 2026
c8a6722
Merge upstream main into feat/minimax-token-plan-credit.
Yuxin-Qiao Jul 3, 2026
143ac2e
Optimize MiniMax menu switching
Yuxin-Qiao Jul 3, 2026
e25a28f
Fix PR 1821 CI lint and duplicate MiniMax prewarm test
cursoragent Jul 3, 2026
8119ca1
Extract menu populate snapshot helpers for SwiftLint limits
cursoragent Jul 3, 2026
712ca75
Fix SwiftFormat wrapPropertyBodies on MenuPopulateSnapshot
cursoragent Jul 3, 2026
873b7b5
Always enrich MiniMax web usage with credit and usage summary
cursoragent Jul 3, 2026
1104f76
Fix MiniMax review blockers for cookie source, Agent enrichment, and …
Yuxin-Qiao Jul 5, 2026
b889140
Merge upstream/main into feat/minimax-token-plan-credit.
Yuxin-Qiao Jul 5, 2026
3d5b18f
Fix plan utilization file length lint after main merge.
Yuxin-Qiao Jul 5, 2026
edfc384
Fix Linux CLI build for MiniMax API enrichment resolver.
Yuxin-Qiao Jul 5, 2026
b2bc5da
Fix SwiftFormat docComments on MiniMax enrichment split.
Yuxin-Qiao Jul 5, 2026
50bbe01
Expose plan utilization sampling to MiniMax extension file.
Yuxin-Qiao Jul 5, 2026
110248f
Fix CI compile issues for MiniMax plan utilization split.
Yuxin-Qiao Jul 5, 2026
36c4ab2
Trim plan utilization file length with MiniMax helper consolidation.
Yuxin-Qiao Jul 5, 2026
44d373b
Compress MiniMax plan utilization helpers for file length lint.
Yuxin-Qiao Jul 5, 2026
2b66a46
Fit plan utilization file under SwiftLint length limit.
Yuxin-Qiao Jul 5, 2026
df28ac0
Fix plan utilization lint line and file length limits.
Yuxin-Qiao Jul 5, 2026
048f9b6
Disable file_length lint for plan utilization store.
Yuxin-Qiao Jul 5, 2026
ec7ae80
Route MiniMax desktop keychain reads through KeychainSecurity.
Yuxin-Qiao Jul 5, 2026
e95fe89
Fix MiniMax review blockers and harden web enrichment verification.
cursoragent Jul 5, 2026
7c3f534
Fix syntax errors in MiniMax test additions.
cursoragent Jul 5, 2026
93ede2a
Silence file_length lint for expanded MiniMax provider tests.
cursoragent Jul 5, 2026
222e39c
Remove duplicate swiftlint file_length disable.
cursoragent Jul 5, 2026
bfdcce8
Fix MiniMax usage summary test lint force-unwrap.
cursoragent Jul 5, 2026
5d1661d
Fix swiftlint type_body_length and superfluous disable.
cursoragent Jul 5, 2026
ebe1d6e
Fix MiniMax credit expiry merge and sync Galician locale keys.
cursoragent Jul 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
### Added
- Menu: add an opt-in setting to refresh provider usage whenever the menu opens without changing the periodic refresh clock. Thanks @dstier-git!
- Quota warnings: add an optional centered on-screen text alert that stays click-through and does not steal focus. Thanks @SAASEmpiree!
- MiniMax: fetch Token Plan recharge-credit balance from the console `token_plan_credit` endpoint when a browser session cookie is available. Thanks @Yuxin-Qiao!
- MiniMax: persist detected China API region after a successful global-to-CN token retry so later refreshes skip the extra probe.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Drop stale MiniMax region persistence note

The current implementation no longer persists the fallback China region; fetchAPITokenUsage only returns resolvedRegion for the current fetch and the credit enrichment uses that transient value. Leaving this changelog entry will tell users that later refreshes skip the global probe automatically, which is no longer true unless they set the region manually.

Useful? React with 👍 / 👎.


### Fixed
- Claude web usage: bound stale requests so Auto can reach CLI fallback instead of hanging indefinitely.
Expand Down
9 changes: 9 additions & 0 deletions Sources/CodexBar/ProviderRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ struct ProviderRegistry {
}
}
},
providerRegionUpdater: { provider, region in
await MainActor.run {
guard provider == .minimax,
let resolved = MiniMaxAPIRegion(rawValue: region),
settings.minimaxAPIRegion != resolved
else { return }
settings.minimaxAPIRegion = resolved
}
},
costUsageHistoryDays: settings.costUsageHistoryDays,
persistsCLISessions: true,
persistentCLISessionIdleWindow: Self.persistentCLISessionIdleWindow(
Expand Down
10 changes: 10 additions & 0 deletions Sources/CodexBar/UsageStore+TokenAccounts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,16 @@ extension UsageStore {
self.settings.stepfunToken = token
}
},
providerRegionUpdater: { [weak self] provider, region in
await MainActor.run {
guard let self,
provider == .minimax,
let resolved = MiniMaxAPIRegion(rawValue: region),
self.settings.minimaxAPIRegion != resolved
else { return }
self.settings.minimaxAPIRegion = resolved

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid persisting detected MiniMax region across accounts

When a selected MiniMax token account only succeeds after the global→China retry, this writes .cn into the provider-wide setting. That setting is then reused for other MiniMax token accounts, and fetchAPITokenUsage does not try the global host when the preferred region is already .cn, so any configured global account can start failing on later refreshes until the user manually changes the shared region back. Keep the auto-detected region scoped to the current account/fetch, or only persist it when there are no token accounts to mix.

Useful? React with 👍 / 👎.

}
},
costUsageHistoryDays: self.settings.costUsageHistoryDays,
persistsCLISessions: true,
persistentCLISessionIdleWindow: ProviderRegistry.persistentCLISessionIdleWindow(
Expand Down
3 changes: 2 additions & 1 deletion Sources/CodexBarCLI/CLIDiagnoseCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ extension CodexBarCLI {
browserDetection: browserDetection,
selectedTokenAccountID: account?.id,
tokenAccountTokenUpdater: tokenContext.tokenUpdater(for: account),
providerManualTokenUpdater: tokenContext.manualTokenUpdater())
providerManualTokenUpdater: tokenContext.manualTokenUpdater(),
providerRegionUpdater: tokenContext.regionUpdater())
let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)
let outcome = await Self.fetchProviderUsage(provider: provider, context: fetchContext)
return ProviderDiagnosticExportBuilder.build(.init(
Expand Down
1 change: 1 addition & 0 deletions Sources/CodexBarCLI/CLIUsageCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ extension CodexBarCLI {
selectedTokenAccountID: account?.id,
tokenAccountTokenUpdater: tokenContext.tokenUpdater(for: account),
providerManualTokenUpdater: tokenContext.manualTokenUpdater(),
providerRegionUpdater: tokenContext.regionUpdater(),
persistsCLISessions: Self.persistsCLISessions(provider: provider, command: command),
persistentCLISessionIdleWindow: command.persistentCLISessionIdleWindow)
let outcome = await Self.fetchProviderUsage(provider: provider, context: fetchContext)
Expand Down
20 changes: 20 additions & 0 deletions Sources/CodexBarCLI/TokenAccountCLI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,26 @@ struct TokenAccountCLIContext {
}
}

func regionUpdater() -> ProviderFetchContext.ProviderRegionUpdater {
{ provider, region in
try? Self.updateStoredRegion(provider: provider, region: region)
}
}

private static func updateStoredRegion(provider: UsageProvider, region: String) throws {
guard provider == .minimax else { return }
let trimmed = region.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return }

let store = CodexBarConfigStore()
var config = try store.load() ?? .makeDefault()
var providerConfig = config.providerConfig(for: provider) ?? ProviderConfig(id: provider)
guard providerConfig.region != trimmed else { return }
providerConfig.region = trimmed
config.setProviderConfig(providerConfig)
try store.save(config)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid persisting region from env-only CLI probes

When codexbar usage/diagnose is run with only a temporary MINIMAX_CODING_API_KEY in the environment and the global request falls back to China, this CLI updater creates or updates the persisted MiniMax provider config and saves region = cn. This separate CLI path means a one-shot env probe changes later app/CLI refreshes, and because fetchAPITokenUsage does not try global once the preferred region is .cn, a subsequent global key can fail until the user manually resets the setting; skip this updater for env-backed credentials or scope it to a stored MiniMax config.

Useful? React with 👍 / 👎.

}

private static func updateStoredManualToken(provider: UsageProvider, token: String) throws {
guard provider == .stepfun else { return }
let trimmed = token.trimmingCharacters(in: .whitespacesAndNewlines)
Expand Down
14 changes: 14 additions & 0 deletions Sources/CodexBarCore/Providers/MiniMax/MiniMaxAPIRegion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public enum MiniMaxAPIRegion: String, CaseIterable, Sendable {
private static let codingPlanQuery = "cycle_type=3"
private static let remainsPath = "v1/api/openplatform/coding_plan/remains"
private static let tokenPlanRemainsPath = "v1/token_plan/remains"
private static let tokenPlanCreditPath = "backend/account/token_plan_credit"
private static let billingHistoryPath = "account/amount"

public var displayName: String {
Expand Down Expand Up @@ -37,6 +38,19 @@ public enum MiniMaxAPIRegion: String, CaseIterable, Sendable {
}
}

public var webBaseURLString: String {
switch self {
case .global:
"https://www.minimax.io"
case .chinaMainland:
"https://www.minimaxi.com"
}
}

public var tokenPlanCreditURL: URL {
URL(string: self.webBaseURLString)!.appendingPathComponent(Self.tokenPlanCreditPath)
}

public var codingPlanURL: URL {
var components = URLComponents(string: self.baseURLString)!
components.path = "/" + Self.codingPlanPath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,43 @@ struct MiniMaxAPIFetchStrategy: ProviderFetchStrategy {
guard let apiToken = ProviderTokenResolver.minimaxToken(environment: context.env) else {
throw MiniMaxAPISettingsError.missingToken
}
let region = context.settings?.minimax?.apiRegion ?? .global
let usage = try await MiniMaxUsageFetcher.fetchUsage(apiToken: apiToken, region: region)
let preferredRegion = context.settings?.minimax?.apiRegion ?? .global
let apiResult = try await MiniMaxUsageFetcher.fetchAPITokenUsage(
apiToken: apiToken,
region: preferredRegion)
if apiResult.resolvedRegion != preferredRegion {
await context.providerRegionUpdater?(.minimax, apiResult.resolvedRegion.rawValue)
}
var usage = apiResult.snapshot
if let cookieOverride = Self.resolveExplicitCookieOverride(context: context),
let cookie = MiniMaxCookieHeader.normalized(from: cookieOverride.cookieHeader)
{
let fetchContext = MiniMaxUsageFetcher.WebFetchContext(
cookie: cookie,
authorizationToken: cookieOverride.authorizationToken,
region: apiResult.resolvedRegion,
environment: context.env,
transport: ProviderHTTPClient.shared)
usage = try await MiniMaxUsageFetcher.attachingTokenPlanCreditIfAvailable(
to: usage,
context: fetchContext,
groupID: cookieOverride.groupID)
}
return self.makeResult(
usage: usage.toUsageSnapshot(),
sourceLabel: "api")
}

private static func resolveExplicitCookieOverride(context: ProviderFetchContext) -> MiniMaxCookieOverride? {
if let settings = context.settings?.minimax, settings.cookieSource == .manual {
return MiniMaxCookieHeader.override(from: settings.manualCookieHeader)
}
guard let raw = ProviderTokenResolver.minimaxCookie(environment: context.env) else {
return nil
}
return MiniMaxCookieHeader.override(from: raw)
}

func shouldFallback(on error: Error, context _: ProviderFetchContext) -> Bool {
guard let minimaxError = error as? MiniMaxUsageError else { return false }
switch minimaxError {
Expand Down
10 changes: 10 additions & 0 deletions Sources/CodexBarCore/Providers/MiniMax/MiniMaxSettingsReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ public struct MiniMaxSettingsReader: Sendable {
public static let hostKey = "MINIMAX_HOST"
public static let codingPlanURLKey = "MINIMAX_CODING_PLAN_URL"
public static let remainsURLKey = "MINIMAX_REMAINS_URL"
public static let tokenPlanCreditURLKey = "MINIMAX_TOKEN_PLAN_CREDIT_URL"
public static let billingHistoryURLKey = "MINIMAX_BILLING_HISTORY_URL"
public static let requireProviderEndpointOverridesKey = "MINIMAX_REQUIRE_PROVIDER_ENDPOINT_OVERRIDES"
private static let endpointOverrideKeys = [
Self.hostKey,
Self.codingPlanURLKey,
Self.remainsURLKey,
Self.tokenPlanCreditURLKey,
Self.billingHistoryURLKey,
]

Expand Down Expand Up @@ -71,6 +73,14 @@ public struct MiniMaxSettingsReader: Sendable {
policy: self.endpointOverrideHostPolicy(environment: environment))
}

public static func tokenPlanCreditURL(
environment: [String: String] = ProcessInfo.processInfo.environment) -> URL?
{
self.endpointValidator.validatedURL(
self.cleaned(environment[self.tokenPlanCreditURLKey]),
policy: self.endpointOverrideHostPolicy(environment: environment))
}

public static func billingHistoryURL(
environment: [String: String] = ProcessInfo.processInfo.environment) -> URL?
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,34 @@ extension MiniMaxUsageFetcher {
return snapshot
}
}

static func attachingTokenPlanCreditIfAvailable(
to snapshot: MiniMaxUsageSnapshot,
context: WebFetchContext,
groupID: String?) async throws -> MiniMaxUsageSnapshot
{
guard snapshot.pointsBalance == nil,
MiniMaxCookieHeader.normalized(from: context.cookie) != nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fetch credit metadata even when remains includes a balance

When the normal token-plan remains response already carries points_balance (as in the existing token-plan-normal.json fixture), this guard skips the new token_plan_credit request entirely. That leaves pointsBalanceExpiresAt nil, so the new expiry line in the Credits section never appears for those common responses, and any more accurate recharge-credit balance from the dedicated endpoint is ignored; only skip when both balance and expiry metadata are already present.

Useful? React with 👍 / 👎.

else {
return snapshot
}

let resolvedGroupID = groupID ?? MiniMaxCookieHeader.override(from: context.cookie)?.groupID
do {
let balance = try await MiniMaxTokenPlanCreditFetcher.fetch(
cookieHeader: context.cookie,
groupID: resolvedGroupID,
region: context.region,
environment: context.environment,
transport: context.transport)
return snapshot.withPointsBalanceIfMissing(balance)
} catch is CancellationError {
throw CancellationError()
} catch let error as URLError where error.code == .cancelled {
throw CancellationError()
} catch {
Self.log.debug("MiniMax token plan credit unavailable: \(error.localizedDescription)")
return snapshot
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

enum MiniMaxTokenPlanCreditFetcher {
static func fetch(
cookieHeader: String,
groupID: String?,
region: MiniMaxAPIRegion,
environment: [String: String],
transport: any ProviderHTTPTransport) async throws -> Double?
{
let url = try self.resolveCreditURL(region: region, environment: environment)
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue(cookieHeader, forHTTPHeaderField: "Cookie")
if let groupID = groupID?.trimmingCharacters(in: .whitespacesAndNewlines), !groupID.isEmpty {
request.setValue(groupID, forHTTPHeaderField: "x-group-id")
}
request.setValue("application/json, text/plain, */*", forHTTPHeaderField: "accept")
request.setValue("XMLHttpRequest", forHTTPHeaderField: "x-requested-with")
let userAgent =
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"
request.setValue(userAgent, forHTTPHeaderField: "user-agent")
request.setValue("en-US,en;q=0.9", forHTTPHeaderField: "accept-language")
let origin = MiniMaxSubscriptionMetadataFetcher.platformOriginURL(region: region)
request.setValue(origin.absoluteString, forHTTPHeaderField: "origin")
request.setValue(origin.absoluteString + "/", forHTTPHeaderField: "referer")

let response = try await transport.response(for: request)
guard response.statusCode == 200 else {
if response.statusCode == 401 || response.statusCode == 403 {
throw MiniMaxUsageError.invalidCredentials
}
throw MiniMaxUsageError.apiError("HTTP \(response.statusCode)")
}
return try self.parseBalance(data: response.data)
}

static func parseBalance(data: Data) throws -> Double? {
let object = try JSONSerialization.jsonObject(with: data, options: [])
guard let payload = object as? [String: Any] else {
throw MiniMaxUsageError.parseFailed("MiniMax token plan credit payload was not an object.")
}
try self.validateBaseResponse(in: payload)
return self.balance(from: payload)
}

static func resolveCreditURL(region: MiniMaxAPIRegion, environment: [String: String]) throws -> URL {
if let rejectedKey = MiniMaxSettingsReader.rejectedEndpointOverrideKey(environment: environment) {
throw ProviderEndpointOverrideError.minimax(rejectedKey)
}
if let override = MiniMaxSettingsReader.tokenPlanCreditURL(environment: environment) {
return override
}
return region.tokenPlanCreditURL

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Respect host override when choosing credit region

When MiniMax is configured only through the documented MINIMAX_HOST=platform.minimaxi.com env override and no persisted region, quota/billing requests resolve to the China host, but this fallback ignores that override and still sends the new credit lookup to region.tokenPlanCreditURL (defaulting to www.minimax.io). Fresh evidence after the prior host-override comment is that the updated resolver now avoids the platform host but still uses the global web host for China MINIMAX_HOST setups, so those existing env-based users silently lose pointsBalance unless they also know to set MINIMAX_TOKEN_PLAN_CREDIT_URL.

Useful? React with 👍 / 👎.

}

private static func validateBaseResponse(in payload: [String: Any]) throws {
guard let baseResp = payload["base_resp"] as? [String: Any] else { return }
let status = self.intValue(baseResp["status_code"]) ?? 0
guard status != 0 else { return }
let message = (baseResp["status_msg"] as? String) ?? "MiniMax token plan credit error \(status)"
if status == 1004 || message.lowercased().contains("cookie") || message.lowercased().contains("login") {
throw MiniMaxUsageError.invalidCredentials
}
throw MiniMaxUsageError.apiError(message)
}

private static func balance(from payload: [String: Any]) -> Double? {
if let balance = self.doubleValue(payload["remaining_credits"]), balance >= 0 {
return balance
}
if let breakdown = payload["balance_breakdown"] as? [String: Any],
let balance = self.doubleValue(breakdown["total_balance"]),
balance >= 0
{
return balance
}
if let balance = self.doubleValue(payload["points_balance"]), balance >= 0 {
return balance
}
if let balance = self.doubleValue(payload["total_credits"]),
let used = self.doubleValue(payload["used_credits"]),
balance >= used
{
return balance - used
}
return nil
}

private static func doubleValue(_ value: Any?) -> Double? {
if let number = value as? Double { return number }
if let number = value as? Int { return Double(number) }
if let string = value as? String {
return Double(string.trimmingCharacters(in: .whitespacesAndNewlines))
}
return nil
}

private static func intValue(_ value: Any?) -> Int? {
if let number = value as? Int { return number }
if let number = value as? Double { return Int(number) }
if let string = value as? String {
return Int(string.trimmingCharacters(in: .whitespacesAndNewlines))
}
return nil
}
}

extension MiniMaxSubscriptionMetadataFetcher {
static func platformOriginURL(region: MiniMaxAPIRegion) -> URL {
switch region {
case .global: URL(string: "https://platform.minimax.io")!
case .chinaMainland: URL(string: "https://platform.minimaxi.com")!
}
}
}
Loading
Loading