fix: comprehensive codebase hardening — crashes, silent failures, performance, and security
Fixes ~95 issues from deep audit across 12 categories in 82 files: - Crash prevention: double-resume in PhotoMetadataExtractor, force unwraps in DateRangePicker, array bounds checks in polls/achievements, ProGate hit-test bypass, Dictionary(uniqueKeysWithValues:) → uniquingKeysWith in 4 files - Silent failure elimination: all 34 try? sites replaced with do/try/catch + logging (SavedTrip, TripDetailView, CanonicalSyncService, BootstrapService, CanonicalModels, CKModels, SportsTimeApp, and more) - Performance: cached DateFormatters (7 files), O(1) team lookups via AppDataProvider, achievement definition dictionary, AnimatedBackground consolidated from 19 Tasks to 1, task cancellation in SharePreviewView - Concurrency: UIKit drawing → MainActor.run, background fetch timeout guard, @MainActor on ThemeManager/AppearanceManager, SyncLogger read/write race fix - Planning engine: game end time in travel feasibility, state-aware city normalization, exact city matching, DrivingConstraints parameter propagation - IAP: unknown subscription states → expired, unverified transaction logging, entitlements updated before paywall dismiss, restore visible to all users - Security: API key to Info.plist lookup, filename sanitization in PDF export, honest User-Agent, removed stale "Feels" analytics super properties - Navigation: consolidated competing navigationDestination, boolean → value-based - Testing: 8 sleep() → waitForExistence, duplicates extracted, Swift 6 compat - Service bugs: infinite retry cap, duplicate achievement prevention, TOCTOU vote fix, PollVote.odg → voterId rename, deterministic placeholder IDs, parallel MKDirections, Sendable-safe POI struct Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,9 @@ import SwiftUI
|
||||
import SwiftData
|
||||
import BackgroundTasks
|
||||
import CloudKit
|
||||
import os
|
||||
|
||||
private let appLogger = Logger(subsystem: "com.88oakapps.SportsTime", category: "SportsTimeApp")
|
||||
|
||||
@main
|
||||
struct SportsTimeApp: App {
|
||||
@@ -74,6 +77,8 @@ struct SportsTimeApp: App {
|
||||
return try ModelContainer(for: schema, configurations: [modelConfiguration])
|
||||
} catch {
|
||||
assertionFailure("Could not create persistent ModelContainer: \(error)")
|
||||
// Log the error so it's visible in release builds (assertionFailure is stripped)
|
||||
os_log(.error, "Could not create persistent ModelContainer: %@. Falling back to in-memory store.", error.localizedDescription)
|
||||
do {
|
||||
let fallbackConfiguration = ModelConfiguration(
|
||||
schema: schema,
|
||||
@@ -110,6 +115,7 @@ struct BootstrappedContentView: View {
|
||||
@State private var showOnboardingPaywall = false
|
||||
@State private var deepLinkHandler = DeepLinkHandler.shared
|
||||
@State private var appearanceManager = AppearanceManager.shared
|
||||
@State private var showDeepLinkError = false
|
||||
|
||||
private var shouldShowOnboardingPaywall: Bool {
|
||||
guard !ProcessInfo.isUITesting else { return false }
|
||||
@@ -137,11 +143,14 @@ struct BootstrappedContentView: View {
|
||||
PollDetailView(shareCode: code.value)
|
||||
}
|
||||
}
|
||||
.alert("Error", isPresented: .constant(deepLinkHandler.error != nil)) {
|
||||
.alert("Error", isPresented: $showDeepLinkError) {
|
||||
Button("OK") { deepLinkHandler.clearPending() }
|
||||
} message: {
|
||||
Text(deepLinkHandler.error?.localizedDescription ?? "")
|
||||
}
|
||||
.onChange(of: deepLinkHandler.error != nil) { _, hasError in
|
||||
showDeepLinkError = hasError
|
||||
}
|
||||
.onAppear {
|
||||
if shouldShowOnboardingPaywall {
|
||||
showOnboardingPaywall = true
|
||||
@@ -351,7 +360,11 @@ struct BootstrappedContentView: View {
|
||||
|
||||
log.log("⚠️ [SYNC] Resetting stale syncInProgress flag")
|
||||
syncState.syncInProgress = false
|
||||
try? context.save()
|
||||
do {
|
||||
try context.save()
|
||||
} catch {
|
||||
log.log("⚠️ [SYNC] Failed to save stale sync flag reset: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
let syncService = CanonicalSyncService()
|
||||
|
||||
Reference in New Issue
Block a user