// // SharedInbox.swift // Poche // // Author: Simon-Pierre Boucher // Contact: contact@spboucher.ai // // Compiled into BOTH the app and the Share Extension: the extension // appends, the app drains. Everything stays inside the app group — // shared content never touches the network (CLAUDE.md §7). // import Foundation struct SharedInboxItem: Codable, Sendable { let title: String let content: String let date: Date } enum SharedInbox { static let groupID = "group.ai.spboucher.poche" static var url: URL? { FileManager.default .containerURL(forSecurityApplicationGroupIdentifier: groupID)? .appendingPathComponent("inbox.json") } static func append(_ item: SharedInboxItem, at url: URL? = SharedInbox.url) { guard let url else { return } var items = read(at: url) items.append(item) let encoder = JSONEncoder() encoder.dateEncodingStrategy = .iso8601 if let data = try? encoder.encode(items) { try? data.write(to: url, options: .atomic) } } /// Returns all pending items and empties the inbox. static func drain(at url: URL? = SharedInbox.url) -> [SharedInboxItem] { guard let url else { return [] } let items = read(at: url) if !items.isEmpty { try? FileManager.default.removeItem(at: url) } return items } private static func read(at url: URL) -> [SharedInboxItem] { guard let data = try? Data(contentsOf: url) else { return [] } let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 return (try? decoder.decode([SharedInboxItem].self, from: data)) ?? [] } }