feat(imessage): improve iMessage service detection and error handling

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-05-21 20:24:45 -07:00
parent b104ee1b12
commit 5290e1de2f

View file

@ -88,9 +88,23 @@ class SendService {
.replacingOccurrences(of: "\\", with: "\\\\")
.replacingOccurrences(of: "\"", with: "\\\"")
// Resolve the iMessage service by iterating with a per-service `try`.
// A plain `1st service whose service type = iMessage` throws (-1728)
// when any stale service errors on `service type`, and it would also
// pick a *disabled* service. Require an enabled iMessage service; if
// none, fail with a clear reason instead of a cryptic delivery error.
let script = """
tell application "Messages"
set targetService to 1st service whose service type = iMessage
set targetService to missing value
repeat with s in services
try
if (service type of s) is iMessage and (enabled of s) then
set targetService to s
exit repeat
end if
end try
end repeat
if targetService is missing value then error "no enabled iMessage service"
set targetBuddy to buddy "\(sanitizedBuddy)" of targetService
send "\(sanitizedBody)" to targetBuddy
end tell
@ -143,6 +157,17 @@ class SendService {
return (false, nil, errorMessage)
}
// osascript exiting 0 only means Messages accepted the command NOT
// that the message transmitted. Verify against chat.db: a disabled
// iMessage service still creates a message row, but with error != 0
// (e.g. error 33). Never report success the ground truth contradicts.
Thread.sleep(forTimeInterval: 4)
if let sendError = Self.chatDBSendError(buddyId: buddyId), sendError != 0 {
osLog.error("send: chat.db reports error=\(sendError, privacy: .public) for \(logPrefix, privacy: .public) — NOT delivered")
activityLog.error("iMessage send failed to \(logPrefix)...: Messages error \(sendError)")
return (false, nil, "Messages reported error \(sendError) — not delivered (iMessage service may be disabled)")
}
dailySendCount += 1
hourlySendCount += 1
@ -192,6 +217,27 @@ class SendService {
}
}
/// Most-recent outbound `message.error` for `buddyId` from chat.db, or nil
/// if no row is found. A non-zero value means Messages failed the send
/// even when `osascript` exited 0 (e.g. disabled iMessage service 33).
nonisolated static func chatDBSendError(buddyId: String) -> Int? {
guard let dbQueue = iMessageReader.shared.getDatabaseQueue() else { return nil }
let suffix = String(buddyId.suffix(7))
let value: Int? = (try? dbQueue.read { db -> Int? in
guard let row = try Row.fetchOne(db, sql: """
SELECT m.error AS err
FROM message m
JOIN handle h ON h.ROWID = m.handle_id
WHERE m.is_from_me = 1 AND h.id LIKE ?
ORDER BY m.date DESC
LIMIT 1
""", arguments: ["%\(suffix)"])
else { return nil }
return (row["err"] as? Int64).map(Int.init)
}) ?? nil
return value
}
func getRateLimitStatus() -> (dailyRemaining: Int, hourlyRemaining: Int) {
resetCountersIfNeeded()
return (max(0, maxDailyMessages - dailySendCount), max(0, maxHourlyMessages - hourlySendCount))