diff --git a/Package.resolved b/Package.resolved index 2731bb1..e06d653 100644 --- a/Package.resolved +++ b/Package.resolved @@ -7,7 +7,7 @@ "location" : "https://tangled.org/@sparrowtek.com/CoreATProtocol", "state" : { "branch" : "main", - "revision" : "d50e4c6a1c92a5e777fe5c642173be03b14116e5" + "revision" : "2dc3b3cd0dec29989befdd19c94b982ad0a9685d" } }, { @@ -25,7 +25,7 @@ "location" : "https://github.com/SparrowTek/NetworkingKit.git", "state" : { "branch" : "main", - "revision" : "15378e3cb097b485a20a1ddc705fea1455568354" + "revision" : "e1c325e58c64925c00063c0373f812101b041b43" } }, { diff --git a/Sources/EffemKit/Configuration.swift b/Sources/EffemKit/Configuration.swift index 2867519..9fad9bd 100644 --- a/Sources/EffemKit/Configuration.swift +++ b/Sources/EffemKit/Configuration.swift @@ -36,18 +36,31 @@ func ensurePDSConfigured() throws { } } +/// Injects the AppView read token into requests to the Effem AppView. +/// Separate from the AT Proto router delegate which injects user PDS tokens. +@NetworkingKitActor +final class AppViewRouterDelegate: NetworkRouterDelegate { + func intercept(_ request: inout URLRequest) async { + if let token = await EffemEnvironment.current.readToken { + request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") + } + } + + func shouldRetry(error: Error, attempts: Int) async throws -> Bool { + false + } +} + @NetworkingKitActor enum RouterCache { private static var _effemRouter: NetworkRouter? private static var _repoRouter: NetworkRouter? + private static let appViewDelegate = AppViewRouterDelegate() - static func effem(delegate: NetworkRouterDelegate) -> NetworkRouter { - if let router = _effemRouter { - router.delegate = delegate - return router - } + static func effem() -> NetworkRouter { + if let router = _effemRouter { return router } let router = NetworkRouter(decoder: .atDecoder) - router.delegate = delegate + router.delegate = appViewDelegate _effemRouter = router return router } diff --git a/Sources/EffemKit/EffemEnvironment.swift b/Sources/EffemKit/EffemEnvironment.swift index 1e12768..5a89f4e 100644 --- a/Sources/EffemKit/EffemEnvironment.swift +++ b/Sources/EffemKit/EffemEnvironment.swift @@ -6,10 +6,12 @@ public final class EffemEnvironment: Sendable { public static let current = EffemEnvironment() public private(set) var appViewHost: String? + public private(set) var readToken: String? private init() {} - public func setup(appViewHost: String) { + public func setup(appViewHost: String, readToken: String? = nil) { self.appViewHost = appViewHost + self.readToken = readToken } } diff --git a/Sources/EffemKit/EffemKit.swift b/Sources/EffemKit/EffemKit.swift index 5188948..edd39e9 100644 --- a/Sources/EffemKit/EffemKit.swift +++ b/Sources/EffemKit/EffemKit.swift @@ -5,8 +5,10 @@ import CoreATProtocol /// /// Call this once at app launch before using ``EffemService`` or ``EffemRepoService``. /// -/// - Parameter appViewHost: The full URL of your Effem AppView (e.g. `"https://appview.effem.fm"`). +/// - Parameters: +/// - appViewHost: The full URL of your Effem AppView (e.g. `"https://appview.effem.fm"`). +/// - readToken: An optional Bearer token for authenticating read requests to the AppView. @APActor -public func setup(appViewHost: String) { - EffemEnvironment.current.setup(appViewHost: appViewHost) +public func setup(appViewHost: String, readToken: String? = nil) { + EffemEnvironment.current.setup(appViewHost: appViewHost, readToken: readToken) } diff --git a/Sources/EffemKit/EffemService.swift b/Sources/EffemKit/EffemService.swift index 7eccba4..54b93c8 100644 --- a/Sources/EffemKit/EffemService.swift +++ b/Sources/EffemKit/EffemService.swift @@ -16,8 +16,7 @@ public struct EffemService: Sendable { private func execute(_ endpoint: EffemAPI) async throws -> T { try ensureAppViewConfigured() - let delegate = APEnvironment.current.routerDelegate - return try await RouterCache.effem(delegate: delegate).execute(endpoint) + return try await RouterCache.effem().execute(endpoint) } // MARK: - Subscriptions