apple 0.2.0

A Rust library for Apple Sign-In authentication, CloudKit Web Services, and App Store Server API
Documentation
use crate::error::{AppStoreErrorResponse, AppleError};

#[derive(Debug, Clone, PartialEq)]
pub enum AppStoreErrorCode {
    AccountNotFound,
    AccountNotFoundRetryable,
    AppNotFound,
    AppNotFoundRetryable,
    FamilySharedSubscriptionExtensionIneligible,
    GeneralBadRequest,
    GeneralInternal,
    GeneralInternalRetryable,
    InvalidAppIdentifier,
    InvalidEmptyStorefrontCountryCodeList,
    InvalidExtendByDays,
    InvalidExtendReasonCode,
    InvalidOriginalTransactionId,
    InvalidRequestIdentifier,
    InvalidRequestRevision,
    InvalidRenewalDateNotYetPast,
    InvalidStartDate,
    InvalidEndDate,
    InvalidNotificationType,
    InvalidPaginationToken,
    InvalidPlayTime,
    InvalidProductId,
    InvalidProductType,
    InvalidRefundPreference,
    InvalidSort,
    InvalidStatus,
    InvalidStorefrontCountryCode,
    InvalidSubscriptionGroupIdentifier,
    InvalidTestNotificationToken,
    InvalidTransactionId,
    MultipleFiltersSupplied,
    OriginalTransactionIdNotFound,
    OriginalTransactionIdNotFoundRetryable,
    RateLimitExceeded,
    ServerNotificationUrlNotFound,
    StartDateAfterEndDate,
    StartDateTooFarInPast,
    StatusRequestNotFound,
    SubscriptionExtensionIneligible,
    SubscriptionGroupIdentifierNotFound,
    SubscriptionMaxExtension,
    SubscriptionNotFound,
    SubscriptionNotFoundRetryable,
    TestNotificationNotFound,
    TransactionIdNotFound,
    TransactionIdNotFoundRetryable,
    // Messaging errors
    InvalidImageIdentifier,
    InvalidMessageIdentifier,
    InvalidLocale,
    ImageNotFound,
    MessageNotFound,
    ImageUploadFailed,
    MessageUploadFailed,
    InvalidImageData,
    InvalidMessageBody,
    ImageQuotaExceeded,
    MessageQuotaExceeded,
    DefaultMessageNotFound,
    InvalidDefaultMessageBody,
    // Additional error codes
    UnauthorizedAccess,
    ForbiddenAccess,
    TooManyRequests,
    InternalServerError,
    ServiceUnavailable,
    InvalidInAppOwnershipType,
    InvalidAccountTenure,
    InvalidConsumptionStatus,
    InvalidCustomerConsented,
    InvalidDeliveryStatus,
    InvalidLifetimeDollarsPurchased,
    InvalidLifetimeDollarsRefunded,
    InvalidPlatform,
    InvalidSampleContentProvided,
    InvalidUserStatus,
    InvalidTransactionTypeNotSupported,
    AppTransactionNotFound,
    InvalidAppAccountToken,
    Unknown(i64),
}

impl AppStoreErrorCode {
    pub fn from_code(code: i64) -> Self {
        match code {
            4040001 => AppStoreErrorCode::AccountNotFound,
            4040002 => AppStoreErrorCode::AccountNotFoundRetryable,
            4040003 => AppStoreErrorCode::AppNotFound,
            4040004 => AppStoreErrorCode::AppNotFoundRetryable,
            4030007 => AppStoreErrorCode::FamilySharedSubscriptionExtensionIneligible,
            4000000 => AppStoreErrorCode::GeneralBadRequest,
            5000000 => AppStoreErrorCode::GeneralInternal,
            5000001 => AppStoreErrorCode::GeneralInternalRetryable,
            4000002 => AppStoreErrorCode::InvalidAppIdentifier,
            4000027 => AppStoreErrorCode::InvalidEmptyStorefrontCountryCodeList,
            4000009 => AppStoreErrorCode::InvalidExtendByDays,
            4000010 => AppStoreErrorCode::InvalidExtendReasonCode,
            4000008 => AppStoreErrorCode::InvalidOriginalTransactionId,
            4000018 => AppStoreErrorCode::InvalidRequestIdentifier,
            4000019 => AppStoreErrorCode::InvalidRequestRevision,
            4000022 => AppStoreErrorCode::InvalidRenewalDateNotYetPast,
            4000015 => AppStoreErrorCode::InvalidStartDate,
            4000016 => AppStoreErrorCode::InvalidEndDate,
            4000017 => AppStoreErrorCode::InvalidNotificationType,
            4000014 => AppStoreErrorCode::InvalidPaginationToken,
            4000024 => AppStoreErrorCode::InvalidPlayTime,
            4000023 => AppStoreErrorCode::InvalidProductId,
            4000003 => AppStoreErrorCode::InvalidProductType,
            4000031 => AppStoreErrorCode::InvalidRefundPreference,
            4000011 => AppStoreErrorCode::InvalidSort,
            4000012 => AppStoreErrorCode::InvalidStatus,
            4000028 => AppStoreErrorCode::InvalidStorefrontCountryCode,
            4000013 => AppStoreErrorCode::InvalidSubscriptionGroupIdentifier,
            4000020 => AppStoreErrorCode::InvalidTestNotificationToken,
            4000021 => AppStoreErrorCode::InvalidTransactionId,
            4000004 => AppStoreErrorCode::MultipleFiltersSupplied,
            4040005 => AppStoreErrorCode::OriginalTransactionIdNotFound,
            4040006 => AppStoreErrorCode::OriginalTransactionIdNotFoundRetryable,
            4290000 => AppStoreErrorCode::RateLimitExceeded,
            4040007 => AppStoreErrorCode::ServerNotificationUrlNotFound,
            4000005 => AppStoreErrorCode::StartDateAfterEndDate,
            4000006 => AppStoreErrorCode::StartDateTooFarInPast,
            4040008 => AppStoreErrorCode::StatusRequestNotFound,
            4030004 => AppStoreErrorCode::SubscriptionExtensionIneligible,
            4040009 => AppStoreErrorCode::SubscriptionGroupIdentifierNotFound,
            4030005 => AppStoreErrorCode::SubscriptionMaxExtension,
            4040010 => AppStoreErrorCode::SubscriptionNotFound,
            4040011 => AppStoreErrorCode::SubscriptionNotFoundRetryable,
            4040012 => AppStoreErrorCode::TestNotificationNotFound,
            4040013 => AppStoreErrorCode::TransactionIdNotFound,
            4040014 => AppStoreErrorCode::TransactionIdNotFoundRetryable,
            4000032 => AppStoreErrorCode::InvalidImageIdentifier,
            4000033 => AppStoreErrorCode::InvalidMessageIdentifier,
            4000034 => AppStoreErrorCode::InvalidLocale,
            4040015 => AppStoreErrorCode::ImageNotFound,
            4040016 => AppStoreErrorCode::MessageNotFound,
            4000035 => AppStoreErrorCode::ImageUploadFailed,
            4000036 => AppStoreErrorCode::MessageUploadFailed,
            4000037 => AppStoreErrorCode::InvalidImageData,
            4000038 => AppStoreErrorCode::InvalidMessageBody,
            4030008 => AppStoreErrorCode::ImageQuotaExceeded,
            4030009 => AppStoreErrorCode::MessageQuotaExceeded,
            4040017 => AppStoreErrorCode::DefaultMessageNotFound,
            4000039 => AppStoreErrorCode::InvalidDefaultMessageBody,
            4010000 => AppStoreErrorCode::UnauthorizedAccess,
            4030000 => AppStoreErrorCode::ForbiddenAccess,
            4290001 => AppStoreErrorCode::TooManyRequests,
            5000002 => AppStoreErrorCode::InternalServerError,
            5030000 => AppStoreErrorCode::ServiceUnavailable,
            4000025 => AppStoreErrorCode::InvalidInAppOwnershipType,
            4000040 => AppStoreErrorCode::InvalidAccountTenure,
            4000041 => AppStoreErrorCode::InvalidConsumptionStatus,
            4000042 => AppStoreErrorCode::InvalidCustomerConsented,
            4000043 => AppStoreErrorCode::InvalidDeliveryStatus,
            4000044 => AppStoreErrorCode::InvalidLifetimeDollarsPurchased,
            4000045 => AppStoreErrorCode::InvalidLifetimeDollarsRefunded,
            4000026 => AppStoreErrorCode::InvalidPlatform,
            4000046 => AppStoreErrorCode::InvalidSampleContentProvided,
            4000047 => AppStoreErrorCode::InvalidUserStatus,
            4000048 => AppStoreErrorCode::InvalidTransactionTypeNotSupported,
            4040018 => AppStoreErrorCode::AppTransactionNotFound,
            4000049 => AppStoreErrorCode::InvalidAppAccountToken,
            code => AppStoreErrorCode::Unknown(code),
        }
    }

    pub fn code(&self) -> i64 {
        match self {
            AppStoreErrorCode::AccountNotFound => 4040001,
            AppStoreErrorCode::AccountNotFoundRetryable => 4040002,
            AppStoreErrorCode::AppNotFound => 4040003,
            AppStoreErrorCode::AppNotFoundRetryable => 4040004,
            AppStoreErrorCode::FamilySharedSubscriptionExtensionIneligible => 4030007,
            AppStoreErrorCode::GeneralBadRequest => 4000000,
            AppStoreErrorCode::GeneralInternal => 5000000,
            AppStoreErrorCode::GeneralInternalRetryable => 5000001,
            AppStoreErrorCode::InvalidAppIdentifier => 4000002,
            AppStoreErrorCode::InvalidEmptyStorefrontCountryCodeList => 4000027,
            AppStoreErrorCode::InvalidExtendByDays => 4000009,
            AppStoreErrorCode::InvalidExtendReasonCode => 4000010,
            AppStoreErrorCode::InvalidOriginalTransactionId => 4000008,
            AppStoreErrorCode::InvalidRequestIdentifier => 4000018,
            AppStoreErrorCode::InvalidRequestRevision => 4000019,
            AppStoreErrorCode::InvalidRenewalDateNotYetPast => 4000022,
            AppStoreErrorCode::InvalidStartDate => 4000015,
            AppStoreErrorCode::InvalidEndDate => 4000016,
            AppStoreErrorCode::InvalidNotificationType => 4000017,
            AppStoreErrorCode::InvalidPaginationToken => 4000014,
            AppStoreErrorCode::InvalidPlayTime => 4000024,
            AppStoreErrorCode::InvalidProductId => 4000023,
            AppStoreErrorCode::InvalidProductType => 4000003,
            AppStoreErrorCode::InvalidRefundPreference => 4000031,
            AppStoreErrorCode::InvalidSort => 4000011,
            AppStoreErrorCode::InvalidStatus => 4000012,
            AppStoreErrorCode::InvalidStorefrontCountryCode => 4000028,
            AppStoreErrorCode::InvalidSubscriptionGroupIdentifier => 4000013,
            AppStoreErrorCode::InvalidTestNotificationToken => 4000020,
            AppStoreErrorCode::InvalidTransactionId => 4000021,
            AppStoreErrorCode::MultipleFiltersSupplied => 4000004,
            AppStoreErrorCode::OriginalTransactionIdNotFound => 4040005,
            AppStoreErrorCode::OriginalTransactionIdNotFoundRetryable => 4040006,
            AppStoreErrorCode::RateLimitExceeded => 4290000,
            AppStoreErrorCode::ServerNotificationUrlNotFound => 4040007,
            AppStoreErrorCode::StartDateAfterEndDate => 4000005,
            AppStoreErrorCode::StartDateTooFarInPast => 4000006,
            AppStoreErrorCode::StatusRequestNotFound => 4040008,
            AppStoreErrorCode::SubscriptionExtensionIneligible => 4030004,
            AppStoreErrorCode::SubscriptionGroupIdentifierNotFound => 4040009,
            AppStoreErrorCode::SubscriptionMaxExtension => 4030005,
            AppStoreErrorCode::SubscriptionNotFound => 4040010,
            AppStoreErrorCode::SubscriptionNotFoundRetryable => 4040011,
            AppStoreErrorCode::TestNotificationNotFound => 4040012,
            AppStoreErrorCode::TransactionIdNotFound => 4040013,
            AppStoreErrorCode::TransactionIdNotFoundRetryable => 4040014,
            AppStoreErrorCode::InvalidImageIdentifier => 4000032,
            AppStoreErrorCode::InvalidMessageIdentifier => 4000033,
            AppStoreErrorCode::InvalidLocale => 4000034,
            AppStoreErrorCode::ImageNotFound => 4040015,
            AppStoreErrorCode::MessageNotFound => 4040016,
            AppStoreErrorCode::ImageUploadFailed => 4000035,
            AppStoreErrorCode::MessageUploadFailed => 4000036,
            AppStoreErrorCode::InvalidImageData => 4000037,
            AppStoreErrorCode::InvalidMessageBody => 4000038,
            AppStoreErrorCode::ImageQuotaExceeded => 4030008,
            AppStoreErrorCode::MessageQuotaExceeded => 4030009,
            AppStoreErrorCode::DefaultMessageNotFound => 4040017,
            AppStoreErrorCode::InvalidDefaultMessageBody => 4000039,
            AppStoreErrorCode::UnauthorizedAccess => 4010000,
            AppStoreErrorCode::ForbiddenAccess => 4030000,
            AppStoreErrorCode::TooManyRequests => 4290001,
            AppStoreErrorCode::InternalServerError => 5000002,
            AppStoreErrorCode::ServiceUnavailable => 5030000,
            AppStoreErrorCode::InvalidInAppOwnershipType => 4000025,
            AppStoreErrorCode::InvalidAccountTenure => 4000040,
            AppStoreErrorCode::InvalidConsumptionStatus => 4000041,
            AppStoreErrorCode::InvalidCustomerConsented => 4000042,
            AppStoreErrorCode::InvalidDeliveryStatus => 4000043,
            AppStoreErrorCode::InvalidLifetimeDollarsPurchased => 4000044,
            AppStoreErrorCode::InvalidLifetimeDollarsRefunded => 4000045,
            AppStoreErrorCode::InvalidPlatform => 4000026,
            AppStoreErrorCode::InvalidSampleContentProvided => 4000046,
            AppStoreErrorCode::InvalidUserStatus => 4000047,
            AppStoreErrorCode::InvalidTransactionTypeNotSupported => 4000048,
            AppStoreErrorCode::AppTransactionNotFound => 4040018,
            AppStoreErrorCode::InvalidAppAccountToken => 4000049,
            AppStoreErrorCode::Unknown(code) => *code,
        }
    }
}

impl std::fmt::Display for AppStoreErrorCode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?}({})", self, self.code())
    }
}

#[derive(Debug, serde::Deserialize)]
pub(crate) struct RawAppStoreErrorResponse {
    #[serde(rename = "errorCode")]
    pub error_code: i64,
    #[serde(rename = "errorMessage")]
    pub error_message: String,
}

pub(crate) fn parse_appstore_error(body: &str) -> AppleError {
    match serde_json::from_str::<RawAppStoreErrorResponse>(body) {
        Ok(raw) => AppleError::AppStoreError(AppStoreErrorResponse {
            error_code: raw.error_code,
            error_message: raw.error_message,
        }),
        Err(_) => AppleError::JsonError(format!("Failed to parse App Store error: {}", body)),
    }
}