crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

commit fa22f91fc24578e27a065075b8ce09ea075c9de8
parent da5eacca4a39307d777fd5e29038e7dd513d9c05
Author: Michael Camilleri <[email protected]>
Date:   Fri,  8 May 2026 21:29:08 +0900

Add more instrumentation to push notifications

Diffstat:
MCrossmate/Sync/SyncEngine.swift | 33+++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+), 0 deletions(-)

diff --git a/Crossmate/Sync/SyncEngine.swift b/Crossmate/Sync/SyncEngine.swift @@ -410,9 +410,42 @@ actor SyncEngine { } catch { results.append(("sharedZones", describe(error))) } + // CKSyncEngine creates a CKDatabaseSubscription per scope on first + // start. If subscription creation silently failed, no push will ever + // fire for that scope — surface what's actually present so a missing + // entry is visible from the diagnostics view rather than diagnosed + // by elimination. + results.append(await probeSubscriptions(database: container.privateCloudDatabase, label: "privateSubs")) + results.append(await probeSubscriptions(database: container.sharedCloudDatabase, label: "sharedSubs")) return results } + private func probeSubscriptions( + database: CKDatabase, + label: String + ) async -> (String, String) { + do { + let subs = try await database.allSubscriptions() + if subs.isEmpty { + return (label, "0 subscriptions — pushes will not fire") + } + let descriptions = subs.map { sub -> String in + let kind: String + switch sub { + case is CKDatabaseSubscription: kind = "database" + case is CKQuerySubscription: kind = "query" + case is CKRecordZoneSubscription: kind = "zone" + default: kind = "other(\(type(of: sub)))" + } + let silent = sub.notificationInfo?.shouldSendContentAvailable == true ? "silent" : "alert-only" + return "\(kind):\(sub.subscriptionID)[\(silent)]" + } + return (label, "\(subs.count): [\(descriptions.joined(separator: ", "))]") + } catch { + return (label, describe(error)) + } + } + /// Fetches a single record by ID for the in-app record editor. Bypasses /// CKSyncEngine's tracked changes — caller is responsible for triggering a /// reconciling fetch if the record corresponds to a tracked local entity.