Files
OSGKeyboard/OSGKeyboardShared/Services/FlowSessionBridge.swift
T
Rocky 9f308fadd2 feat(keyboard): ship AI hint carousel, home library cards, and clipboard polish
Rotate AI idle suggestions with optional remote packs, move history/dictionary onto self-sizing Home preview cards, harden clipboard capture/prompting, and simplify keyboard chrome by dropping most liquid-glass shadows.
2026-08-13 01:00:51 +08:00

53 lines
1.8 KiB
Swift

// FlowSessionBridge.swift
// OSGKeyboard · Shared
//
// TypeWhisper-style Flow session bridge: keyboard writes recording
// signals; host app writes transcription results.
import Foundation
enum FlowSessionBridgeStorage {
static func resolvedDefaults(_ defaults: UserDefaults?) -> UserDefaults {
if let defaults { return defaults }
guard let available = AppGroup.defaultsIfAvailable else {
#if DEBUG
fatalError("App Group unavailable — inject UserDefaults in tests or fix entitlements.")
#else
fatalError("App Group unavailable.")
#endif
}
return available
}
/// Force cross-process visibility. Must only be called on the main thread.
static func flush(_ store: UserDefaults) {
if Thread.isMainThread {
store.synchronize()
}
}
static func encode<T: Encodable>(_ value: T) -> Data? {
try? JSONEncoder().encode(value)
}
static func decode<T: Decodable>(_ type: T.Type, from data: Data?) -> T? {
guard let data else { return nil }
return try? JSONDecoder().decode(type, from: data)
}
}
/// Cross-process Flow mailbox backed by App Group defaults and lossy Darwin
/// wakeups. Payload writes precede posts, and main-thread writes synchronize
/// for visibility. Readers still poll/reload because wakeups may be missed;
/// `hostGeneration` rejects state left by a dead host process.
public enum FlowSessionBridge {
/// Keyboard/read side: refresh App Group defaults after the extension was
/// suspended so decisions are not based on stale in-process caches.
public static func reloadFromDisk(defaults: UserDefaults? = nil) {
let store = FlowSessionBridgeStorage.resolvedDefaults(defaults)
if Thread.isMainThread {
store.synchronize()
}
}
}