@sriinnu/runic 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +8 -1
- package/RuniciOS/Core/RunicTypographyiOS.swift +24 -0
- package/RuniciOS/Views/ProviderDetailView.swift +9 -9
- package/RuniciOS/Views/ProviderListView.swift +10 -10
- package/RuniciOS/Widgets/LargeWidget.swift +14 -14
- package/RuniciOS/Widgets/LiveActivity.swift +19 -19
- package/RuniciOS/Widgets/LockScreenWidget.swift +15 -15
- package/RuniciOS/Widgets/MediumWidget.swift +10 -10
- package/RuniciOS/Widgets/RunicWidget.swift +5 -5
- package/RuniciOS/Widgets/SmallWidget.swift +9 -9
- package/Sources/Runic/About.swift +3 -3
- package/Sources/Runic/AppNotifications.swift +5 -3
- package/Sources/Runic/Controllers/StatusItemController+Actions.swift +7 -3
- package/Sources/Runic/Controllers/StatusItemController+Animation.swift +5 -4
- package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +30 -16
- package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +6 -3
- package/Sources/Runic/Controllers/StatusItemController+Menu.swift +18 -13
- package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +6 -4
- package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +40 -12
- package/Sources/Runic/Controllers/StatusItemController.swift +43 -43
- package/Sources/Runic/Core/BudgetNotificationManager.swift +2 -1
- package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +2 -2
- package/Sources/Runic/Core/Login/CodexLoginRunner.swift +1 -1
- package/Sources/Runic/Core/Login/CursorLoginRunner.swift +4 -4
- package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +1 -1
- package/Sources/Runic/Core/Rendering/IconRenderer.swift +91 -85
- package/Sources/Runic/Core/Rendering/IconView.swift +3 -1
- package/Sources/Runic/Core/RunicColors.swift +6 -6
- package/Sources/Runic/Core/RunicSpacing.swift +7 -7
- package/Sources/Runic/Core/RunicTypography.swift +206 -0
- package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/CohereTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/CustomProviderStore.swift +10 -10
- package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/GroqTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/KimiTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +1 -3
- package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +1 -3
- package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/MistralTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +1 -1
- package/Sources/Runic/Core/Stores/QwenTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/SettingsStore.swift +89 -51
- package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +19 -6
- package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +1 -1
- package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +1 -1
- package/Sources/Runic/Core/Stores/UsageStore.swift +187 -161
- package/Sources/Runic/Core/Stores/XAITokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +1 -2
- package/Sources/Runic/Core/UsageExporter.swift +8 -4
- package/Sources/Runic/ProviderRegistry.swift +1 -1
- package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +5 -2
- package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +1 -1
- package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +1 -1
- package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +1 -1
- package/Sources/Runic/Resources/Fonts/Caveat-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Caveat-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Light.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/SpaceMono-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/SpaceMono-Regular.ttf +0 -0
- package/Sources/Runic/RunicApp.swift +46 -36
- package/Sources/Runic/SessionQuotaNotifications.swift +2 -2
- package/Sources/Runic/UsagePaceText.swift +1 -1
- package/Sources/Runic/UsageProgressBar.swift +13 -9
- package/Sources/Runic/Utilities/LoadingPattern.swift +4 -2
- package/Sources/Runic/Utilities/PerformanceConstants.swift +28 -28
- package/Sources/Runic/Views/Menu/AlertsMenuView.swift +19 -21
- package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +19 -19
- package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +7 -7
- package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +5 -5
- package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +29 -30
- package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +20 -17
- package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +14 -14
- package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +12 -10
- package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +3 -4
- package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +5 -25
- package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +1 -1
- package/Sources/Runic/Views/Menu/MenuCardView.swift +120 -131
- package/Sources/Runic/Views/Menu/MenuContent.swift +11 -8
- package/Sources/Runic/Views/Menu/MenuDescriptor.swift +4 -2
- package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +1 -8
- package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +20 -14
- package/Sources/Runic/Views/Menu/OverviewMenuView.swift +18 -15
- package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +16 -11
- package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +27 -27
- package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +4 -6
- package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +24 -11
- package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +5 -5
- package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +7 -8
- package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +22 -17
- package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +8 -7
- package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +7 -7
- package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +50 -47
- package/Sources/Runic/Views/Preferences/LiquidComponents.swift +15 -14
- package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +7 -7
- package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +27 -27
- package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +38 -42
- package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +39 -43
- package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +21 -21
- package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +7 -7
- package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +49 -50
- package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +10 -10
- package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +40 -21
- package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +7 -7
- package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +44 -39
- package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +26 -23
- package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +271 -226
- package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +6 -2
- package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +7 -5
- package/Sources/Runic/Views/Preferences/PreferencesView.swift +38 -31
- package/Sources/Runic/Views/Rating/QualityRatingView.swift +11 -11
- package/Sources/Runic/Views/Team/TeamDashboardView.swift +29 -24
- package/Sources/Runic/Views/Team/TeamInviteSheet.swift +16 -16
- package/Sources/Runic/Views/Team/TeamManagementView.swift +50 -49
- package/Sources/Runic/Views/Team/TeamMemberRow.swift +8 -8
- package/Sources/RunicCLI/CLIEntry.swift +83 -42
- package/Sources/RunicCLI/CLIRenderer.swift +1 -1
- package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +60 -60
- package/Sources/RunicCLI/Commands/ModelsCommand.swift +45 -44
- package/Sources/RunicCLI/Commands/ProjectsCommand.swift +83 -69
- package/Sources/RunicCLI/Commands/ResetCommand.swift +50 -49
- package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +31 -32
- package/Sources/RunicClaudeWebProbe/main.swift +1 -1
- package/Sources/RunicCore/AlertRuleStore.swift +20 -20
- package/Sources/RunicCore/BrowserCookieImportOrder.swift +3 -3
- package/Sources/RunicCore/CostUsageModels.swift +1 -1
- package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +29 -30
- package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +73 -75
- package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +53 -109
- package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +3 -3
- package/Sources/RunicCore/Integrations/GitHubIntegration.swift +3 -3
- package/Sources/RunicCore/Models/EnhancedUsageModels.swift +47 -48
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +1 -1
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +1 -1
- package/Sources/RunicCore/Performance/PerformanceModels.swift +4 -4
- package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +81 -64
- package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +2 -2
- package/Sources/RunicCore/ProjectBudgetStore.swift +15 -12
- package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +2 -2
- package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +3 -3
- package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +8 -8
- package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +3 -3
- package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +6 -6
- package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +3 -7
- package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +3 -3
- package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +4 -4
- package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +3 -1
- package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +1 -1
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +1 -1
- package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +3 -1
- package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +5 -3
- package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +3 -3
- package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +7 -4
- package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +4 -4
- package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +5 -3
- package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +9 -10
- package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +4 -4
- package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +2 -2
- package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +5 -2
- package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +10 -5
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +7 -7
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +10 -10
- package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +23 -10
- package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +2 -2
- package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +2 -2
- package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +5 -3
- package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +26 -13
- package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +5 -5
- package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +1 -1
- package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +3 -3
- package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +48 -21
- package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +76 -77
- package/Sources/RunicCore/Sync/SyncConflictResolver.swift +55 -58
- package/Sources/RunicCore/Sync/SyncProtocol.swift +21 -22
- package/Sources/RunicCore/Sync/SyncRecord.swift +46 -49
- package/Sources/RunicCore/Sync/SyncUsageExample.swift +44 -50
- package/Sources/RunicCore/Sync/TeamSyncRecords.swift +94 -101
- package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +51 -46
- package/Sources/RunicCore/Team/TeamModels.swift +111 -110
- package/Sources/RunicCore/Team/TeamStore.swift +126 -109
- package/Sources/RunicCore/UsageFetcher.swift +2 -2
- package/Sources/RunicCore/UsageFormatter.swift +25 -25
- package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +27 -13
- package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +11 -3
- package/Sources/RunicCore/UsageLedger/LedgerCache.swift +5 -2
- package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +1 -1
- package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +40 -25
- package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +1 -1
- package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +55 -16
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +6 -6
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +1 -1
- package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +2 -2
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +5 -5
- package/Tests/RunicTests/AppDelegateTests.swift +8 -3
- package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +2 -3
- package/Tests/RunicTests/CLIArgumentParsingTests.swift +3 -4
- package/Tests/RunicTests/CLICostTests.swift +6 -7
- package/Tests/RunicTests/CLIProviderSelectionTests.swift +2 -3
- package/Tests/RunicTests/CLISnapshotTests.swift +3 -4
- package/Tests/RunicTests/CLIWebFallbackTests.swift +3 -4
- package/Tests/RunicTests/ClaudeOAuthTests.swift +11 -12
- package/Tests/RunicTests/ClaudeResilienceTests.swift +3 -4
- package/Tests/RunicTests/ClaudeUsageTests.swift +20 -21
- package/Tests/RunicTests/CodexOAuthTests.swift +7 -8
- package/Tests/RunicTests/CodexUsageLogSourceTests.swift +1 -3
- package/Tests/RunicTests/CopilotTokenResolverTests.swift +5 -6
- package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +4 -5
- package/Tests/RunicTests/CostUsageDecodingTests.swift +15 -17
- package/Tests/RunicTests/CostUsagePricingTests.swift +5 -7
- package/Tests/RunicTests/CostUsageScannerTests.swift +10 -12
- package/Tests/RunicTests/CursorStatusProbeTests.swift +15 -16
- package/Tests/RunicTests/FactoryStatusProbeTests.swift +3 -5
- package/Tests/RunicTests/GeminiLoginAlertTests.swift +3 -4
- package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +11 -11
- package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +8 -8
- package/Tests/RunicTests/GeminiStatusProbeTests.swift +20 -21
- package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +2 -3
- package/Tests/RunicTests/InstallOriginTests.swift +1 -2
- package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +2 -2
- package/Tests/RunicTests/LiveAccountTests.swift +3 -3
- package/Tests/RunicTests/LoadingPatternTests.swift +3 -4
- package/Tests/RunicTests/MenuCardModelTests.swift +33 -34
- package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +4 -1
- package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +4 -1
- package/Tests/RunicTests/MiniMaxParsingTests.swift +4 -5
- package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +4 -1
- package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +4 -6
- package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +1 -2
- package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +5 -6
- package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +2 -3
- package/Tests/RunicTests/OpenAIDashboardParserTests.swift +12 -13
- package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +17 -6
- package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +52 -13
- package/Tests/RunicTests/PathBuilderTests.swift +14 -15
- package/Tests/RunicTests/ProviderFetchPipelineTests.swift +3 -4
- package/Tests/RunicTests/ProviderIconResourcesTests.swift +1 -2
- package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +1 -2
- package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +53 -19
- package/Tests/RunicTests/ProviderToggleStoreTests.swift +10 -11
- package/Tests/RunicTests/RunicTests.swift +6 -7
- package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +5 -6
- package/Tests/RunicTests/SettingsStoreTests.swift +149 -45
- package/Tests/RunicTests/StatusItemAnimationTests.swift +8 -3
- package/Tests/RunicTests/StatusMenuTests.swift +63 -22
- package/Tests/RunicTests/StatusProbeTests.swift +28 -29
- package/Tests/RunicTests/SubprocessRunnerTests.swift +1 -3
- package/Tests/RunicTests/SubscriptionDetectionTests.swift +8 -9
- package/Tests/RunicTests/TTYCommandRunnerTests.swift +8 -9
- package/Tests/RunicTests/TeamShowbackExporterTests.swift +2 -4
- package/Tests/RunicTests/TextParsingTests.swift +1 -2
- package/Tests/RunicTests/UsageFormatterTests.swift +15 -16
- package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +12 -14
- package/Tests/RunicTests/UsageLedgerForecastTests.swift +4 -6
- package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +7 -9
- package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +6 -8
- package/Tests/RunicTests/UsagePaceTests.swift +5 -6
- package/Tests/RunicTests/UsagePaceTextTests.swift +8 -9
- package/Tests/RunicTests/UsagePolicyEngineTests.swift +3 -5
- package/Tests/RunicTests/WidgetSnapshotTests.swift +1 -3
- package/Tests/RunicTests/ZaiProviderTests.swift +3 -5
- package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +4 -1
- package/appcast.xml +36 -76
- package/package.json +1 -1
- package/runic.png +0 -0
- package/runic.svg +15 -0
- package/version.env +2 -2
|
@@ -33,7 +33,7 @@ public actor GenericProviderFetcher {
|
|
|
33
33
|
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
34
34
|
|
|
35
35
|
// Add auth headers
|
|
36
|
-
try await addAuthHeaders(to: &request)
|
|
36
|
+
try await self.addAuthHeaders(to: &request)
|
|
37
37
|
|
|
38
38
|
// 3. Make request
|
|
39
39
|
let (data, response) = try await URLSession.shared.data(for: request)
|
|
@@ -52,7 +52,7 @@ public actor GenericProviderFetcher {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
// 5. Extract fields using mapping
|
|
55
|
-
return try extractUsageData(from: json, mapping: endpoint.mapping)
|
|
55
|
+
return try self.extractUsageData(from: json, mapping: endpoint.mapping)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/// Fetch balance data from the custom provider
|
|
@@ -70,7 +70,7 @@ public actor GenericProviderFetcher {
|
|
|
70
70
|
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
71
71
|
|
|
72
72
|
// Add auth headers
|
|
73
|
-
try await addAuthHeaders(to: &request)
|
|
73
|
+
try await self.addAuthHeaders(to: &request)
|
|
74
74
|
|
|
75
75
|
// 3. Make request
|
|
76
76
|
let (data, response) = try await URLSession.shared.data(for: request)
|
|
@@ -89,34 +89,31 @@ public actor GenericProviderFetcher {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
// 5. Extract fields using mapping
|
|
92
|
-
return try extractBalanceData(from: json, mapping: endpoint.mapping)
|
|
92
|
+
return try self.extractBalanceData(from: json, mapping: endpoint.mapping)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
/// Convert usage data to Runic's UsageSnapshot format
|
|
96
96
|
public func toUsageSnapshot(_ data: UsageData) -> UsageSnapshot {
|
|
97
|
-
let usedPercent: Double
|
|
98
|
-
|
|
99
|
-
usedPercent = (used / quota) * 100.0
|
|
97
|
+
let usedPercent: Double = if let quota = data.quota, let used = data.used, quota > 0 {
|
|
98
|
+
(used / quota) * 100.0
|
|
100
99
|
} else if let remaining = data.remaining, let quota = data.quota, quota > 0 {
|
|
101
|
-
|
|
100
|
+
((quota - remaining) / quota) * 100.0
|
|
102
101
|
} else {
|
|
103
|
-
|
|
102
|
+
0
|
|
104
103
|
}
|
|
105
104
|
|
|
106
105
|
let primary = RateWindow(
|
|
107
106
|
usedPercent: max(0, min(100, usedPercent)),
|
|
108
107
|
windowMinutes: nil,
|
|
109
108
|
resetsAt: data.resetDate,
|
|
110
|
-
resetDescription: data.resetDate.map { resetDescription(from: $0) }
|
|
111
|
-
)
|
|
109
|
+
resetDescription: data.resetDate.map { self.resetDescription(from: $0) })
|
|
112
110
|
|
|
113
111
|
return UsageSnapshot(
|
|
114
112
|
primary: primary,
|
|
115
113
|
secondary: nil,
|
|
116
114
|
tertiary: nil,
|
|
117
115
|
updatedAt: Date(),
|
|
118
|
-
identity: nil
|
|
119
|
-
)
|
|
116
|
+
identity: nil)
|
|
120
117
|
}
|
|
121
118
|
|
|
122
119
|
// MARK: - URL Building
|
|
@@ -126,7 +123,7 @@ public actor GenericProviderFetcher {
|
|
|
126
123
|
var urlString = template
|
|
127
124
|
|
|
128
125
|
// Replace date variables
|
|
129
|
-
urlString = try substituteDateVariables(in: urlString)
|
|
126
|
+
urlString = try self.substituteDateVariables(in: urlString)
|
|
130
127
|
|
|
131
128
|
// Build URL components
|
|
132
129
|
guard var components = URLComponents(string: urlString) else {
|
|
@@ -134,7 +131,7 @@ public actor GenericProviderFetcher {
|
|
|
134
131
|
}
|
|
135
132
|
|
|
136
133
|
// Add query parameters
|
|
137
|
-
if let params
|
|
134
|
+
if let params, !params.isEmpty {
|
|
138
135
|
var queryItems = components.queryItems ?? []
|
|
139
136
|
queryItems.append(contentsOf: params.map { URLQueryItem(name: $0.key, value: $0.value) })
|
|
140
137
|
components.queryItems = queryItems
|
|
@@ -205,10 +202,10 @@ public actor GenericProviderFetcher {
|
|
|
205
202
|
let token = try await loadToken()
|
|
206
203
|
|
|
207
204
|
// Add auth header based on type
|
|
208
|
-
switch config.auth.type {
|
|
205
|
+
switch self.config.auth.type {
|
|
209
206
|
case .apiKey:
|
|
210
207
|
let value = (config.auth.headerPrefix ?? "") + token
|
|
211
|
-
request.setValue(value, forHTTPHeaderField: config.auth.headerName)
|
|
208
|
+
request.setValue(value, forHTTPHeaderField: self.config.auth.headerName)
|
|
212
209
|
|
|
213
210
|
case .bearer:
|
|
214
211
|
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
@@ -224,11 +221,11 @@ public actor GenericProviderFetcher {
|
|
|
224
221
|
case .custom:
|
|
225
222
|
// Custom auth uses the exact header name and prefix from config
|
|
226
223
|
let value = (config.auth.headerPrefix ?? "") + token
|
|
227
|
-
request.setValue(value, forHTTPHeaderField: config.auth.headerName)
|
|
224
|
+
request.setValue(value, forHTTPHeaderField: self.config.auth.headerName)
|
|
228
225
|
}
|
|
229
226
|
|
|
230
227
|
// Add additional headers
|
|
231
|
-
config.auth.additionalHeaders?.forEach { key, value in
|
|
228
|
+
self.config.auth.additionalHeaders?.forEach { key, value in
|
|
232
229
|
request.setValue(value, forHTTPHeaderField: key)
|
|
233
230
|
}
|
|
234
231
|
}
|
|
@@ -241,12 +238,12 @@ public actor GenericProviderFetcher {
|
|
|
241
238
|
}
|
|
242
239
|
|
|
243
240
|
// Try environment variable
|
|
244
|
-
let envKey = config.auth.tokenKeychain.uppercased().replacingOccurrences(of: "-", with: "_")
|
|
241
|
+
let envKey = self.config.auth.tokenKeychain.uppercased().replacingOccurrences(of: "-", with: "_")
|
|
245
242
|
if let token = ProcessInfo.processInfo.environment[envKey] {
|
|
246
243
|
return token.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
247
244
|
}
|
|
248
245
|
|
|
249
|
-
throw FetchError.missingToken(config.auth.tokenKeychain)
|
|
246
|
+
throw FetchError.missingToken(self.config.auth.tokenKeychain)
|
|
250
247
|
}
|
|
251
248
|
|
|
252
249
|
/// Read token from keychain
|
|
@@ -255,18 +252,18 @@ public actor GenericProviderFetcher {
|
|
|
255
252
|
var result: CFTypeRef?
|
|
256
253
|
var query: [String: Any] = [
|
|
257
254
|
kSecClass as String: kSecClassGenericPassword,
|
|
258
|
-
kSecAttrService as String: keychainService,
|
|
255
|
+
kSecAttrService as String: self.keychainService,
|
|
259
256
|
kSecAttrAccount as String: account,
|
|
260
257
|
kSecUseDataProtectionKeychain as String: true,
|
|
261
258
|
kSecUseAuthenticationUI as String: "kSecUseAuthenticationUIFail" as CFString,
|
|
262
259
|
kSecMatchLimit as String: kSecMatchLimitOne,
|
|
263
260
|
kSecReturnData as String: true,
|
|
264
261
|
]
|
|
265
|
-
#if canImport(LocalAuthentication)
|
|
262
|
+
#if canImport(LocalAuthentication)
|
|
266
263
|
let authContext = LAContext()
|
|
267
264
|
authContext.interactionNotAllowed = true
|
|
268
265
|
query[kSecUseAuthenticationContext as String] = authContext
|
|
269
|
-
#endif
|
|
266
|
+
#endif
|
|
270
267
|
|
|
271
268
|
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
272
269
|
if status == errSecItemNotFound {
|
|
@@ -276,7 +273,7 @@ public actor GenericProviderFetcher {
|
|
|
276
273
|
return nil
|
|
277
274
|
}
|
|
278
275
|
guard status == errSecSuccess else {
|
|
279
|
-
log.error("Keychain read failed for \(account): \(status)")
|
|
276
|
+
self.log.error("Keychain read failed for \(account): \(status)")
|
|
280
277
|
return nil
|
|
281
278
|
}
|
|
282
279
|
|
|
@@ -303,32 +300,32 @@ public actor GenericProviderFetcher {
|
|
|
303
300
|
|
|
304
301
|
// Extract quota
|
|
305
302
|
if let quotaPath = mapping.quota {
|
|
306
|
-
data.quota = extractDouble(from: json, path: quotaPath, nested: mapping.nestedPaths)
|
|
303
|
+
data.quota = self.extractDouble(from: json, path: quotaPath, nested: mapping.nestedPaths)
|
|
307
304
|
}
|
|
308
305
|
|
|
309
306
|
// Extract used amount
|
|
310
307
|
if let usedPath = mapping.used {
|
|
311
|
-
data.used = extractDouble(from: json, path: usedPath, nested: mapping.nestedPaths)
|
|
308
|
+
data.used = self.extractDouble(from: json, path: usedPath, nested: mapping.nestedPaths)
|
|
312
309
|
}
|
|
313
310
|
|
|
314
311
|
// Extract remaining amount
|
|
315
312
|
if let remainingPath = mapping.remaining {
|
|
316
|
-
data.remaining = extractDouble(from: json, path: remainingPath, nested: mapping.nestedPaths)
|
|
313
|
+
data.remaining = self.extractDouble(from: json, path: remainingPath, nested: mapping.nestedPaths)
|
|
317
314
|
}
|
|
318
315
|
|
|
319
316
|
// Extract cost
|
|
320
317
|
if let costPath = mapping.cost {
|
|
321
|
-
data.cost = extractDouble(from: json, path: costPath, nested: mapping.nestedPaths)
|
|
318
|
+
data.cost = self.extractDouble(from: json, path: costPath, nested: mapping.nestedPaths)
|
|
322
319
|
}
|
|
323
320
|
|
|
324
321
|
// Extract reset date
|
|
325
322
|
if let resetPath = mapping.resetDate {
|
|
326
|
-
data.resetDate = extractDate(from: json, path: resetPath, nested: mapping.nestedPaths)
|
|
323
|
+
data.resetDate = self.extractDate(from: json, path: resetPath, nested: mapping.nestedPaths)
|
|
327
324
|
}
|
|
328
325
|
|
|
329
326
|
// Extract tokens
|
|
330
327
|
if let tokensPath = mapping.tokens {
|
|
331
|
-
data.tokens = extractInt(from: json, path: tokensPath, nested: mapping.nestedPaths)
|
|
328
|
+
data.tokens = self.extractInt(from: json, path: tokensPath, nested: mapping.nestedPaths)
|
|
332
329
|
}
|
|
333
330
|
|
|
334
331
|
return data
|
|
@@ -340,11 +337,11 @@ public actor GenericProviderFetcher {
|
|
|
340
337
|
|
|
341
338
|
// Extract balance (use 'remaining' or 'used' mapping)
|
|
342
339
|
if let balancePath = mapping.remaining ?? mapping.used {
|
|
343
|
-
data.balance = extractDouble(from: json, path: balancePath, nested: mapping.nestedPaths)
|
|
340
|
+
data.balance = self.extractDouble(from: json, path: balancePath, nested: mapping.nestedPaths)
|
|
344
341
|
}
|
|
345
342
|
|
|
346
343
|
// Try to detect currency from response
|
|
347
|
-
data.currency = extractString(from: json, path: "currency", nested: true) ?? "USD"
|
|
344
|
+
data.currency = self.extractString(from: json, path: "currency", nested: true) ?? "USD"
|
|
348
345
|
|
|
349
346
|
return data
|
|
350
347
|
}
|
|
@@ -363,14 +360,16 @@ public actor GenericProviderFetcher {
|
|
|
363
360
|
for component in components {
|
|
364
361
|
// Handle array indexing: field[0]
|
|
365
362
|
if let bracketIndex = component.firstIndex(of: "["),
|
|
366
|
-
let closeBracket = component.firstIndex(of: "]")
|
|
363
|
+
let closeBracket = component.firstIndex(of: "]")
|
|
364
|
+
{
|
|
367
365
|
let fieldName = String(component[..<bracketIndex])
|
|
368
366
|
let indexStr = String(component[component.index(after: bracketIndex)..<closeBracket])
|
|
369
367
|
|
|
370
368
|
guard let dict = current as? [String: Any],
|
|
371
369
|
let array = dict[fieldName] as? [Any],
|
|
372
370
|
let index = Int(indexStr),
|
|
373
|
-
index < array.count
|
|
371
|
+
index < array.count
|
|
372
|
+
else {
|
|
374
373
|
return nil
|
|
375
374
|
}
|
|
376
375
|
current = array[index]
|
|
@@ -520,8 +519,8 @@ public struct UsageData: Sendable {
|
|
|
520
519
|
remaining: Double? = nil,
|
|
521
520
|
cost: Double? = nil,
|
|
522
521
|
resetDate: Date? = nil,
|
|
523
|
-
tokens: Int? = nil
|
|
524
|
-
|
|
522
|
+
tokens: Int? = nil)
|
|
523
|
+
{
|
|
525
524
|
self.quota = quota
|
|
526
525
|
self.used = used
|
|
527
526
|
self.remaining = remaining
|
|
@@ -531,14 +530,13 @@ public struct UsageData: Sendable {
|
|
|
531
530
|
}
|
|
532
531
|
|
|
533
532
|
public func toCustomUsageData() -> CustomUsageData {
|
|
534
|
-
|
|
533
|
+
CustomUsageData(
|
|
535
534
|
quota: self.quota,
|
|
536
535
|
used: self.used,
|
|
537
536
|
remaining: self.remaining,
|
|
538
537
|
cost: self.cost,
|
|
539
538
|
resetDate: self.resetDate,
|
|
540
|
-
tokens: self.tokens
|
|
541
|
-
)
|
|
539
|
+
tokens: self.tokens)
|
|
542
540
|
}
|
|
543
541
|
}
|
|
544
542
|
|
|
@@ -571,63 +569,63 @@ public enum FetchError: LocalizedError, Sendable {
|
|
|
571
569
|
public var errorDescription: String? {
|
|
572
570
|
switch self {
|
|
573
571
|
case .noUsageEndpoint:
|
|
574
|
-
|
|
572
|
+
"No usage endpoint configured for this provider"
|
|
575
573
|
case .noBalanceEndpoint:
|
|
576
|
-
|
|
577
|
-
case .invalidURL(
|
|
578
|
-
|
|
574
|
+
"No balance endpoint configured for this provider"
|
|
575
|
+
case let .invalidURL(url):
|
|
576
|
+
"Invalid URL: \(url)"
|
|
579
577
|
case .invalidResponse:
|
|
580
|
-
|
|
581
|
-
case .httpError(
|
|
582
|
-
|
|
578
|
+
"Invalid response from provider API"
|
|
579
|
+
case let .httpError(code):
|
|
580
|
+
"HTTP error \(code) from provider API"
|
|
583
581
|
case .invalidJSON:
|
|
584
|
-
|
|
585
|
-
case .missingToken(
|
|
586
|
-
|
|
582
|
+
"Failed to parse JSON response from provider"
|
|
583
|
+
case let .missingToken(account):
|
|
584
|
+
"No API token found for '\(account)'. Store it in Keychain or set as environment variable."
|
|
587
585
|
case .invalidDateRange:
|
|
588
|
-
|
|
589
|
-
case .extractionFailed(
|
|
590
|
-
|
|
591
|
-
case .insecureURL(
|
|
592
|
-
|
|
586
|
+
"Failed to calculate date range for URL template"
|
|
587
|
+
case let .extractionFailed(field):
|
|
588
|
+
"Failed to extract field '\(field)' from response"
|
|
589
|
+
case let .insecureURL(url):
|
|
590
|
+
"Only HTTPS URLs are allowed. Got: \(url)"
|
|
593
591
|
}
|
|
594
592
|
}
|
|
595
593
|
|
|
596
594
|
public var failureReason: String? {
|
|
597
595
|
switch self {
|
|
598
|
-
case .missingToken(
|
|
599
|
-
|
|
600
|
-
case .httpError(
|
|
601
|
-
|
|
596
|
+
case let .missingToken(account):
|
|
597
|
+
"The token for account '\(account)' is not configured in Keychain or environment variables"
|
|
598
|
+
case let .httpError(code):
|
|
599
|
+
"The server returned HTTP status code \(code)"
|
|
602
600
|
case .invalidJSON:
|
|
603
|
-
|
|
604
|
-
case .extractionFailed(
|
|
605
|
-
|
|
601
|
+
"The response is not valid JSON or has unexpected structure"
|
|
602
|
+
case let .extractionFailed(field):
|
|
603
|
+
"The field '\(field)' was not found in the response or has wrong type"
|
|
606
604
|
case .insecureURL:
|
|
607
|
-
|
|
605
|
+
"The URL scheme is not HTTPS"
|
|
608
606
|
default:
|
|
609
|
-
|
|
607
|
+
nil
|
|
610
608
|
}
|
|
611
609
|
}
|
|
612
610
|
|
|
613
611
|
public var recoverySuggestion: String? {
|
|
614
612
|
switch self {
|
|
615
|
-
case .missingToken(
|
|
616
|
-
|
|
613
|
+
case let .missingToken(account):
|
|
614
|
+
"Store your API token in Keychain with account name '\(account)' or set it as environment variable"
|
|
617
615
|
case .noUsageEndpoint:
|
|
618
|
-
|
|
616
|
+
"Configure a usage endpoint in the provider settings"
|
|
619
617
|
case .noBalanceEndpoint:
|
|
620
|
-
|
|
621
|
-
case .httpError(
|
|
622
|
-
|
|
623
|
-
case .httpError(
|
|
624
|
-
|
|
618
|
+
"Configure a balance endpoint in the provider settings"
|
|
619
|
+
case let .httpError(code) where code == 401:
|
|
620
|
+
"Check that your API token is valid and has not expired"
|
|
621
|
+
case let .httpError(code) where code == 429:
|
|
622
|
+
"You have been rate limited. Try again later."
|
|
625
623
|
case .invalidJSON:
|
|
626
|
-
|
|
624
|
+
"Check the API endpoint URL and response mapping configuration"
|
|
627
625
|
case .insecureURL:
|
|
628
|
-
|
|
626
|
+
"Change the provider URL to use HTTPS (e.g., https://api.example.com)"
|
|
629
627
|
default:
|
|
630
|
-
|
|
628
|
+
nil
|
|
631
629
|
}
|
|
632
630
|
}
|
|
633
631
|
}
|