import StoreKit @MainActor class StoreEngine: ObservableObject { @Published var products: [Product] = [] @Published var showThankYou = false var transactionListener: Task? = nil init() { // FIX: Added [weak self] to prevent retain cycle transactionListener = Task.detached { [weak self] in for await result in Transaction.updates { do { guard let self = self else { return } let transaction = try self.checkVerified(result) await transaction.finish() await MainActor.run { self.showThankYou = true } } catch {} } } } deinit { transactionListener?.cancel() } func loadProducts() async { do { let p = try await Product.products(for: AppConfig.tipJarProductIDs) self.products = p #if DEBUG if p.isEmpty { print("⚠️ StoreEngine: No products found. Verify IAP ID in AppConfig.") } #endif } catch { print("Store Error: \(error)") } } func purchase(_ product: Product) async { guard let result = try? await product.purchase() else { return } switch result { case .success(let verification): if let transaction = try? checkVerified(verification) { await transaction.finish() self.showThankYou = true } case .pending, .userCancelled: break @unknown default: break } } nonisolated func checkVerified(_ result: VerificationResult) throws -> T { switch result { case .unverified: throw StoreError.failedVerification case .verified(let safe): return safe } } enum StoreError: Error { case failedVerification } }