···11+import Foundation
22+import os
33+44+public enum PDFSLog {
55+ public static let subsystem = "at.pdfs"
66+77+ public static let app = Logger(subsystem: subsystem, category: "app")
88+ public static let mount = Logger(subsystem: subsystem, category: "mount")
99+ public static let auth = Logger(subsystem: subsystem, category: "auth")
1010+ public static let xpc = Logger(subsystem: subsystem, category: "xpc")
1111+ public static let fsExtension = Logger(subsystem: subsystem, category: "fs")
1212+ public static let pds = Logger(subsystem: subsystem, category: "pds")
1313+}
···11+import Foundation
22+33+/// Wire protocol between the sandboxed FSKit extension (client) and the host
44+/// app (server). The host owns Keychain + OAuth; the extension asks the host
55+/// for a current access token for a given DID.
66+///
77+/// Callback-style (not async) because NSXPC's generated proxies require
88+/// `@objc` methods. Call sites wrap with `withCheckedThrowingContinuation`.
99+@objc public protocol PDFSSessionProtocol {
1010+ /// Returns the current access token for the given DID. Host refreshes if expired.
1111+ /// `tokenJSON` is a JSON blob shaped like `{"accessToken":"...","dpopJWK":"{...}","expiresAt":<epoch>}`.
1212+ func currentAccessToken(
1313+ for did: String,
1414+ reply: @escaping (_ tokenJSON: Data?, _ error: NSError?) -> Void
1515+ )
1616+1717+ /// Forces a refresh against the PDS, even if the cached token hasn't expired.
1818+ /// Called by the extension after receiving a 401 from the PDS.
1919+ func forceRefresh(
2020+ for did: String,
2121+ reply: @escaping (_ tokenJSON: Data?, _ error: NSError?) -> Void
2222+ )
2323+2424+ /// Returns the mount config for the given DID (used for re-validation).
2525+ func describeMount(
2626+ for did: String,
2727+ reply: @escaping (_ mountConfigJSON: Data?, _ error: NSError?) -> Void
2828+ )
2929+3030+ /// Called by the extension when a token was rejected mid-flight so the host
3131+ /// can invalidate its cache and start a fresh refresh.
3232+ func reportTokenRejected(
3333+ for did: String,
3434+ reply: @escaping () -> Void
3535+ )
3636+3737+ /// Liveness handshake performed during `loadResource` to confirm the host is reachable.
3838+ func ping(reply: @escaping (Bool) -> Void)
3939+}
4040+4141+public extension PDFSSessionProtocol {
4242+ static var defaultMachServiceName: String { "at.pdfs.session" }
4343+ static var defaultInterface: NSXPCInterface { NSXPCInterface(with: PDFSSessionProtocol.self) }
4444+}
···11-# pdfs
11+# [pdfs](https://pdfs.at/)
2233mount public data from the atmosphere to a virtual filesystem on macOS, using [fskit](https://developer.apple.com/documentation/fskit)