diff --git a/Sources/APNS/APNSBroadcastClient.swift b/Sources/APNS/APNSBroadcastClient.swift index 8cab985..b71f0ef 100644 --- a/Sources/APNS/APNSBroadcastClient.swift +++ b/Sources/APNS/APNSBroadcastClient.swift @@ -145,6 +145,13 @@ extension APNSBroadcastClient { headers.add(name: "authorization", value: token) } + // Append operation specific HTTPS headers + if let operationHeaders = request.operation.headers { + for (name, value) in operationHeaders { + headers.add(name: name, value: value) + } + } + // Build the request URL let requestURL = "\(self.environment.url):\(self.environment.port)/1/apps/\(self.bundleID)\(request.operation.path)" @@ -165,12 +172,15 @@ extension APNSBroadcastClient { // Extract request ID from response let apnsRequestID = response.headers.first(name: "apns-request-id").flatMap { UUID(uuidString: $0) } - + + // Extract channel ID from response, or from request headers (as 'read' operation doesn't return in payload + let channelID = response.headers.first(name: "apns-channel-id") ?? request.operation.headers?["apns-channel-id"] + // Handle successful responses - if response.status == .ok || response.status == .created { + if response.status == .ok || response.status == .created || response.status == .noContent { let body = try await response.body.collect(upTo: 1024 * 1024) // 1MB max - let responseBody = try responseDecoder.decode(ResponseBody.self, from: body) - return APNSBroadcastResponse(apnsRequestID: apnsRequestID, body: responseBody) + let responseBody = try? responseDecoder.decode(ResponseBody.self, from: body) + return APNSBroadcastResponse(apnsRequestID: apnsRequestID, channelID: channelID, body: responseBody) } // Handle error responses diff --git a/Sources/APNSCore/Broadcast/APNSBroadcastChannel.swift b/Sources/APNSCore/Broadcast/APNSBroadcastChannel.swift index 092dd86..67686a0 100644 --- a/Sources/APNSCore/Broadcast/APNSBroadcastChannel.swift +++ b/Sources/APNSCore/Broadcast/APNSBroadcastChannel.swift @@ -15,14 +15,10 @@ /// Represents a broadcast channel configuration. public struct APNSBroadcastChannel: Codable, Sendable { enum CodingKeys: String, CodingKey { - case channelID = "channel-id" case messageStoragePolicy = "message-storage-policy" case pushType = "push-type" } - /// The unique identifier for the broadcast channel (only present in responses). - public let channelID: String? - /// The message storage policy for this channel. public let messageStoragePolicy: APNSBroadcastMessageStoragePolicy @@ -34,14 +30,12 @@ public struct APNSBroadcastChannel: Codable, Sendable { /// /// - Parameter messageStoragePolicy: The storage policy for messages in this channel. public init(messageStoragePolicy: APNSBroadcastMessageStoragePolicy) { - self.channelID = nil self.messageStoragePolicy = messageStoragePolicy self.pushType = "LiveActivity" } /// Internal initializer used for decoding responses that include channel ID. - public init(channelID: String?, messageStoragePolicy: APNSBroadcastMessageStoragePolicy, pushType: String = "LiveActivity") { - self.channelID = channelID + public init(messageStoragePolicy: APNSBroadcastMessageStoragePolicy, pushType: String = "LiveActivity") { self.messageStoragePolicy = messageStoragePolicy self.pushType = pushType } diff --git a/Sources/APNSCore/Broadcast/APNSBroadcastClientProtocol.swift b/Sources/APNSCore/Broadcast/APNSBroadcastClientProtocol.swift index 28c5458..ae91701 100644 --- a/Sources/APNSCore/Broadcast/APNSBroadcastClientProtocol.swift +++ b/Sources/APNSCore/Broadcast/APNSBroadcastClientProtocol.swift @@ -35,7 +35,7 @@ extension APNSBroadcastClientProtocol { public func create( channel: APNSBroadcastChannel, apnsRequestID: UUID? = nil - ) async throws -> APNSBroadcastResponse { + ) async throws -> APNSBroadcastResponse { let request = APNSBroadcastRequest( operation: .create, message: channel, diff --git a/Sources/APNSCore/Broadcast/APNSBroadcastRequest.swift b/Sources/APNSCore/Broadcast/APNSBroadcastRequest.swift index 4f48bfa..8e95584 100644 --- a/Sources/APNSCore/Broadcast/APNSBroadcastRequest.swift +++ b/Sources/APNSCore/Broadcast/APNSBroadcastRequest.swift @@ -42,10 +42,18 @@ public struct APNSBroadcastRequest: Sendable where Message: /// The path for this operation. public var path: String { switch self { - case .create, .listAll: + case .create, .delete, .read, .listAll: return "/channels" - case .read(let channelID), .delete(let channelID): - return "/channels/\(channelID)" + } + } + + /// HTTP Headers for this operation. + public var headers: [String: String]? { + switch self { + case .delete(let channelID), .read(channelID: let channelID): + return ["apns-channel-id": channelID] + default: + return nil } } } diff --git a/Sources/APNSCore/Broadcast/APNSBroadcastResponse.swift b/Sources/APNSCore/Broadcast/APNSBroadcastResponse.swift index 9e2d3fb..dcf8847 100644 --- a/Sources/APNSCore/Broadcast/APNSBroadcastResponse.swift +++ b/Sources/APNSCore/Broadcast/APNSBroadcastResponse.swift @@ -19,11 +19,15 @@ public struct APNSBroadcastResponse: Sendable where Body: Senda /// The request ID returned by APNs. public let apnsRequestID: UUID? + /// The channel ID returned by APNs. + public let channelID: String? + /// The response body. - public let body: Body + public let body: Body? - public init(apnsRequestID: UUID?, body: Body) { + public init(apnsRequestID: UUID?, channelID: String?, body: Body?) { self.apnsRequestID = apnsRequestID + self.channelID = channelID self.body = body } }