@@ -57,7 +57,24 @@ public class AppStoreServerAPIClient {
5757        try ?   self . client. syncShutdown ( ) 
5858    } 
5959
60+     private  enum  RequestBody  { 
61+         case  encodable( any  Encodable ) 
62+         case  raw( Data ,  contentType:  String ) 
63+     } 
64+ 
6065    private  func  makeRequest< T:  Encodable > ( path:  String ,  method:  HTTPMethod ,  queryParameters:  [ String :  [ String ] ] ,  body:  T ? )  async  ->  APIResult < Data >  { 
66+         if  let  b =  body { 
67+             return  await  makeRequest ( path:  path,  method:  method,  queryParameters:  queryParameters,  body:  . encodable( b) ) 
68+         }  else  { 
69+             return  await  makeRequest ( path:  path,  method:  method,  queryParameters:  queryParameters,  body:  nil ) 
70+         } 
71+     } 
72+ 
73+     private  func  makeRequest( path:  String ,  method:  HTTPMethod ,  queryParameters:  [ String :  [ String ] ] ,  body:  Data ,  contentType:  String )  async  ->  APIResult < Data >  { 
74+         return  await  makeRequest ( path:  path,  method:  method,  queryParameters:  queryParameters,  body:  . raw( body,  contentType:  contentType) ) 
75+     } 
76+ 
77+     private  func  makeRequest( path:  String ,  method:  HTTPMethod ,  queryParameters:  [ String :  [ String ] ] ,  body:  RequestBody ? )  async  ->  APIResult < Data >  { 
6178        do  { 
6279            var  queryItems :  [ URLQueryItem ]  =  [ ] 
6380            for  (parameter,  values)    in  queryParameters { 
@@ -84,11 +101,20 @@ public class AppStoreServerAPIClient {
84101
85102            let  requestBody :  Data ? 
86103            if  let  b =  body { 
87-                 let  jsonEncoder  =  getJsonEncoder ( ) 
88-                 let  encodedBody  =  try   jsonEncoder. encode ( b) 
89-                 requestBody =  encodedBody
90-                 urlRequest. body =  . bytes( . init( data:  encodedBody) ) 
91-                 urlRequest. headers. add ( name:  " Content-Type " ,  value:  " application/json " ) 
104+                 let  data :  Data 
105+                 let  contentType :  String 
106+                 switch  b { 
107+                 case  . encodable( let  encodable) : 
108+                     let  jsonEncoder  =  getJsonEncoder ( ) 
109+                     data =  try   jsonEncoder. encode ( encodable) 
110+                     contentType =  " application/json " 
111+                 case  . raw( let  rawData,  let  ct) : 
112+                     data =  rawData
113+                     contentType =  ct
114+                 } 
115+                 requestBody =  data
116+                 urlRequest. body =  . bytes( . init( data:  data) ) 
117+                 urlRequest. headers. add ( name:  " Content-Type " ,  value:  contentType) 
92118            }  else  { 
93119                requestBody =  nil 
94120            } 
@@ -140,7 +166,17 @@ public class AppStoreServerAPIClient {
140166                return  APIResult . failure ( statusCode:  statusCode,  rawApiError:  rawApiError,  apiError:  apiError,  errorMessage:  errorMessage,  causedBy:  causedBy) 
141167        } 
142168    } 
143-         
169+ 
170+     private  func  makeRequestWithoutResponseBody( path:  String ,  method:  HTTPMethod ,  queryParameters:  [ String :  [ String ] ] ,  body:  Data ,  contentType:  String )  async  ->  APIResult < Void >  { 
171+         let  response  =  await  makeRequest ( path:  path,  method:  method,  queryParameters:  queryParameters,  body:  body,  contentType:  contentType) 
172+         switch  response { 
173+             case  . success: 
174+                 return  APIResult . success ( response:  ( ) ) 
175+             case  . failure( let  statusCode,  let  rawApiError,  let  apiError,  let  errorMessage,  let  causedBy) : 
176+                 return  APIResult . failure ( statusCode:  statusCode,  rawApiError:  rawApiError,  apiError:  apiError,  errorMessage:  errorMessage,  causedBy:  causedBy) 
177+         } 
178+     } 
179+ 
144180    private  func  generateToken( )  async  throws  ->  String  { 
145181        let  keys  =  JWTKeyCollection ( ) 
146182        let  payload  =  AppStoreServerAPIJWT ( 
@@ -335,7 +371,87 @@ public class AppStoreServerAPIClient {
335371    public  func  setAppAccountToken( originalTransactionId:  String ,  updateAppAccountTokenRequest:  UpdateAppAccountTokenRequest )  async  ->  APIResult < Void >  { 
336372        return  await  makeRequestWithoutResponseBody ( path:  " /inApps/v1/transactions/ "  +  originalTransactionId +  " /appAccountToken " ,  method:  . PUT,  queryParameters:  [ : ] ,  body:  updateAppAccountTokenRequest) 
337373    } 
338-     
374+ 
375+     ///Upload an image to use for retention messaging.
376+     ///
377+     ///- Parameter imageIdentifier: A UUID you provide to uniquely identify the image you upload.
378+     ///- Parameter image: The image file to upload.
379+     ///- Returns: Success, or information about the failure
380+     ///[Upload Image](https://developer.apple.com/documentation/retentionmessaging/upload-image)
381+     public  func  uploadImage( imageIdentifier:  UUID ,  image:  Data )  async  ->  APIResult < Void >  { 
382+         return  await  makeRequestWithoutResponseBody ( path:  " /inApps/v1/messaging/image/ "  +  imageIdentifier. uuidString,  method:  . PUT,  queryParameters:  [ : ] ,  body:  image,  contentType:  " image/png " ) 
383+     } 
384+ 
385+     ///Delete a previously uploaded image.
386+     ///
387+     ///- Parameter imageIdentifier: The identifier of the image to delete.
388+     ///- Returns: Success, or information about the failure
389+     ///[Delete Image](https://developer.apple.com/documentation/retentionmessaging/delete-image)
390+     public  func  deleteImage( imageIdentifier:  UUID )  async  ->  APIResult < Void >  { 
391+         let  request :  String ?   =  nil 
392+         return  await  makeRequestWithoutResponseBody ( path:  " /inApps/v1/messaging/image/ "  +  imageIdentifier. uuidString,  method:  . DELETE,  queryParameters:  [ : ] ,  body:  request) 
393+     } 
394+ 
395+     ///Get the image identifier and state for all uploaded images.
396+     ///
397+     ///- Returns: A response that contains status information for all images.
398+     ///[Get Image List](https://developer.apple.com/documentation/retentionmessaging/get-image-list)
399+     public  func  getImageList( )  async  ->  APIResult < GetImageListResponse >  { 
400+         let  request :  String ?   =  nil 
401+         return  await  makeRequestWithResponseBody ( path:  " /inApps/v1/messaging/image/list " ,  method:  . GET,  queryParameters:  [ : ] ,  body:  request) 
402+     } 
403+ 
404+     ///Upload a message to use for retention messaging.
405+     ///
406+     ///- Parameter messageIdentifier: A UUID you provide to uniquely identify the message you upload.
407+     ///- Parameter uploadMessageRequestBody: The message text to upload.
408+     ///- Returns: Success, or information about the failure
409+     ///[Upload Message](https://developer.apple.com/documentation/retentionmessaging/upload-message)
410+     public  func  uploadMessage( messageIdentifier:  UUID ,  uploadMessageRequestBody:  UploadMessageRequestBody )  async  ->  APIResult < Void >  { 
411+         return  await  makeRequestWithoutResponseBody ( path:  " /inApps/v1/messaging/message/ "  +  messageIdentifier. uuidString,  method:  . PUT,  queryParameters:  [ : ] ,  body:  uploadMessageRequestBody) 
412+     } 
413+ 
414+     ///Delete a previously uploaded message.
415+     ///
416+     ///- Parameter messageIdentifier: The identifier of the message to delete.
417+     ///- Returns: Success, or information about the failure
418+     ///[Delete Message](https://developer.apple.com/documentation/retentionmessaging/delete-message)
419+     public  func  deleteMessage( messageIdentifier:  UUID )  async  ->  APIResult < Void >  { 
420+         let  request :  String ?   =  nil 
421+         return  await  makeRequestWithoutResponseBody ( path:  " /inApps/v1/messaging/message/ "  +  messageIdentifier. uuidString,  method:  . DELETE,  queryParameters:  [ : ] ,  body:  request) 
422+     } 
423+ 
424+     ///Get the message identifier and state of all uploaded messages.
425+     ///
426+     ///- Returns: A response that contains status information for all messages, or information about the failure
427+     ///[Get Message List](https://developer.apple.com/documentation/retentionmessaging/get-message-list)
428+     public  func  getMessageList( )  async  ->  APIResult < GetMessageListResponse >  { 
429+         let  request :  String ?   =  nil 
430+         return  await  makeRequestWithResponseBody ( path:  " /inApps/v1/messaging/message/list " ,  method:  . GET,  queryParameters:  [ : ] ,  body:  request) 
431+     } 
432+ 
433+     ///Configure a default message for a specific product in a specific locale.
434+     ///
435+     ///- Parameter productId: The product identifier for the default configuration.
436+     ///- Parameter locale: The locale for the default configuration.
437+     ///- Parameter defaultConfigurationRequest: The request body that includes the message identifier to configure as the default message.
438+     ///- Returns: Success, or information about the failure
439+     ///[Configure Default Message](https://developer.apple.com/documentation/retentionmessaging/configure-default-message)
440+     public  func  configureDefaultMessage( productId:  String ,  locale:  String ,  defaultConfigurationRequest:  DefaultConfigurationRequest )  async  ->  APIResult < Void >  { 
441+         return  await  makeRequestWithoutResponseBody ( path:  " /inApps/v1/messaging/default/ "  +  productId +  " / "  +  locale,  method:  . PUT,  queryParameters:  [ : ] ,  body:  defaultConfigurationRequest) 
442+     } 
443+ 
444+     ///Delete a default message for a product in a locale.
445+     ///
446+     ///- Parameter productId: The product ID of the default message configuration.
447+     ///- Parameter locale: The locale of the default message configuration.
448+     ///- Returns: Success, or information about the failure
449+     ///[Delete Default Message](https://developer.apple.com/documentation/retentionmessaging/delete-default-message)
450+     public  func  deleteDefaultMessage( productId:  String ,  locale:  String )  async  ->  APIResult < Void >  { 
451+         let  request :  String ?   =  nil 
452+         return  await  makeRequestWithoutResponseBody ( path:  " /inApps/v1/messaging/default/ "  +  productId +  " / "  +  locale,  method:  . DELETE,  queryParameters:  [ : ] ,  body:  request) 
453+     } 
454+ 
339455    internal  struct  AppStoreServerAPIJWT :  JWTPayload ,  Equatable  { 
340456        var  exp :  ExpirationClaim 
341457        var  iss :  IssuerClaim 
@@ -562,6 +678,31 @@ public enum APIError: Int64 {
562678    ///[AppTransactionIdNotSupportedError](https://developer.apple.com/documentation/appstoreserverapi/apptransactionidnotsupportederror)
563679    case  appTransactionIdNotSupported =  4000048 
564680
681+     ///An error that indicates the image that's uploading is invalid.
682+     ///
683+     ///[InvalidImageError](https://developer.apple.com/documentation/retentionmessaging/invalidimageerror)
684+     case  invalidImage =  4000161 
685+ 
686+     ///An error that indicates the header text is too long.
687+     ///
688+     ///[HeaderTooLongError](https://developer.apple.com/documentation/retentionmessaging/headertoolongerror)
689+     case  headerTooLong =  4000162 
690+ 
691+     ///An error that indicates the body text is too long.
692+     ///
693+     ///[BodyTooLongError](https://developer.apple.com/documentation/retentionmessaging/bodytoolongerror)
694+     case  bodyTooLong =  4000163 
695+ 
696+     ///An error that indicates the locale is invalid.
697+     ///
698+     ///[InvalidLocaleError](https://developer.apple.com/documentation/retentionmessaging/invalidlocaleerror)
699+     case  invalidLocale =  4000164 
700+ 
701+     ///An error that indicates the alternative text for an image is too long.
702+     ///
703+     ///[AltTextTooLongError](https://developer.apple.com/documentation/retentionmessaging/alttexttoolongerror)
704+     case  altTextTooLong =  4000175 
705+ 
565706    ///An error that indicates the app account token value is not a valid UUID.
566707    ///
567708    ///[InvalidAppAccountTokenUUIDError](https://developer.apple.com/documentation/appstoreserverapi/invalidappaccounttokenuuiderror)
@@ -592,7 +733,32 @@ public enum APIError: Int64 {
592733    ///[FamilySharedSubscriptionExtensionIneligibleError](https://developer.apple.com/documentation/appstoreserverapi/familysharedsubscriptionextensionineligibleerror)
593734    case  familySharedSubscriptionExtensionIneligible =  4030007 
594735
595-     ///An error that indicates the App Store account wasn’t found.
736+     ///An error that indicates when you reach the maximum number of uploaded images.
737+     ///
738+     ///[MaximumNumberOfImagesReachedError](https://developer.apple.com/documentation/retentionmessaging/maximumnumberofimagesreachederror)
739+     case  maximumNumberOfImagesReached =  4030014 
740+ 
741+     ///An error that indicates when you reach the maximum number of uploaded messages.
742+     ///
743+     ///[MaximumNumberOfMessagesReachedError](https://developer.apple.com/documentation/retentionmessaging/maximumnumberofmessagesreachederror)
744+     case  maximumNumberOfMessagesReached =  4030016 
745+ 
746+     ///An error that indicates the message isn't in the approved state, so you can't configure it as a default message.
747+     ///
748+     ///[MessageNotApprovedError](https://developer.apple.com/documentation/retentionmessaging/messagenotapprovederror)
749+     case  messageNotApproved =  4030017 
750+ 
751+     ///An error that indicates the image isn't in the approved state, so you can't configure it as part of a default message.
752+     ///
753+     ///[ImageNotApprovedError](https://developer.apple.com/documentation/retentionmessaging/imagenotapprovederror)
754+     case  imageNotApproved =  4030018 
755+ 
756+     ///An error that indicates the image is currently in use as part of a message, so you can't delete it.
757+     ///
758+     ///[ImageInUseError](https://developer.apple.com/documentation/retentionmessaging/imageinuseerror)
759+     case  imageInUse =  4030019 
760+ 
761+     ///An error that indicates the App Store account wasn't found.
596762    ///
597763    ///[AccountNotFoundError](https://developer.apple.com/documentation/appstoreserverapi/accountnotfounderror)
598764    case  accountNotFound =  4040001 
@@ -642,6 +808,26 @@ public enum APIError: Int64 {
642808    ///[TransactionIdNotFoundError](https://developer.apple.com/documentation/appstoreserverapi/transactionidnotfounderror)
643809    case  transactionIdNotFound =  4040010 
644810
811+     ///An error that indicates the system can't find the image identifier.
812+     ///
813+     ///[ImageNotFoundError](https://developer.apple.com/documentation/retentionmessaging/imagenotfounderror)
814+     case  imageNotFound =  4040014 
815+ 
816+     ///An error that indicates the system can't find the message identifier.
817+     ///
818+     ///[MessageNotFoundError](https://developer.apple.com/documentation/retentionmessaging/messagenotfounderror)
819+     case  messageNotFound =  4040015 
820+ 
821+     ///An error that indicates the image identifier already exists.
822+     ///
823+     ///[ImageAlreadyExistsError](https://developer.apple.com/documentation/retentionmessaging/imagealreadyexistserror)
824+     case  imageAlreadyExists =  4090000 
825+ 
826+     ///An error that indicates the message identifier already exists.
827+     ///
828+     ///[MessageAlreadyExistsError](https://developer.apple.com/documentation/retentionmessaging/messagealreadyexistserror)
829+     case  messageAlreadyExists =  4090001 
830+ 
645831    ///An error that indicates that the request exceeded the rate limit.
646832    ///
647833    ///[RateLimitExceededError](https://developer.apple.com/documentation/appstoreserverapi/ratelimitexceedederror)
0 commit comments