import Foundation /// Uploads via the Org Social vhost multipart endpoint. /// /// The vfile token URL is sent as the `vfile` form field so the host knows /// which file to replace. Only `POST /upload` is used; GET on a vfile URL /// always returns 404 and must not be used for downloading. public struct VFileUploader: FeedUploader { private let tokenURL: URL private let session: URLSession public init(tokenURL: URL, session: URLSession = .shared) { self.tokenURL = tokenURL self.session = session } public func upload(content: String) async throws { guard let scheme = tokenURL.scheme, let host = tokenURL.host else { throw UploadError.invalidConfiguration("Cannot derive host from vfile token URL.") } let base = tokenURL.port.map { "\(scheme)://\(host):\($0)" } ?? "\(scheme)://\(host)" guard let uploadURL = URL(string: "\(base)/upload") else { throw UploadError.invalidConfiguration("Could not build upload URL.") } let boundary = "----OrgSocialBoundary\(UInt32.random(in: 0.. (Data, URLResponse) { do { return try await session.data(for: request) } catch { throw UploadError.networkError(underlying: error.localizedDescription) } } }