### Description
This adds a new diagnostics event `http_request_performed` with some
useful information we would like to track about the http requests
performed to our servers.
Depends on #2747.
### Changes:
- Changed `Signing` to a `final class`, so it can be instantiated with
the api key.
- Updated all `SigningTests` to include the correct signatures
Follow up to #2540.
This was necessary to ensure that we can implement #2533 without
reference cycles.
This was the hierarchy before this change:

The red arrows are what this PR removes.
## Changes:
- `TransactionPoster` no longer has references to `IdentityManager` and
`Attribution`
- `markSyncedIfNeeded` is no longer in `TransactionPoster`, moved back
to `PurchasesOrchestrator`
- Changed `TransactionPoster`'s callback to return `Result<CustomerInfo,
BackendError>`, providing greater flexibility for users to be able to
read the specific errors.
- Extracted `PurchasedTransactionData` to be reduce the number of
parameters passed around. This removed the need for 2
`swiftlint:disable:next function_parameter_count`. This is the majority
of this diff. It was helpful to combine in this PR because I needed to
add another parameter to the flow: `unsyncedAttributes`, since
`TransactionPoster` could no longer read these directly.
This was necessary for a follow-up refactor to #2540. The main change is
in `Backend`, the rest are test changes that are required now that the
closure is `@Sendable`.
### Changes:
- Created `PurchasedProductsFetcherType` to be able to mock and hold
fetchers, even on older devices
- Created `ProductEntitlementMappingFetcher` to abstract injecting
`ProductEntitlementMapping`
- Added logic to `CustomerInfoResponseHandler` to compute offline
`CustomerInfo` after a server error (see #2367). **This is used by all
`CustomerInfo` requests as well as `PostReceiptDataOperation`**.
- Wrote comprehensive `CustomerInfoResponseHandler` tests
### TODO:
- [x] Don't cache offline computed `CustomerInfo`: #2378
- [x] Integration tests: #2501.
### Changes:
- Added `Purchases.configureInCustomEntitlementsComputationMode`
- Added `Purchases.switchUser(to:)`
- Disabled parts of the SDK in this new mode
- New example app for testing `customEntitlementsComputation` mode
---------
Co-authored-by: NachoSoto <ignaciosoto90@gmail.com>
Finishes [CSDK-451].
This new small public API allows users to quickly figure out if
everything in the SDK is correctly configured in a simple way:
```swift
let diagnostics = PurchasesDiagnostics.default
do {
try await diagnostics.testSDKHealth()
} catch {
print(error)
}
```
The specific underlying errors will provide information about what
failed.
We can continue growing this to check for more specific things, but for
now it does 4 things:
- Verify API connectivity: networking issues, firewalling, etc.
- Verify API key is correct
- Verify `Offerings` are configured correctly
- Verify that all products in `Offerings` are configured correctly and
found in `StoreKit`
This new API is covered by:
- API testers
- Unit tests
- Integration tests (both on `SK1` and `SK2`)
_I've taken the "shortcut" of making this `async` only (while still
compatible with Objective-C), which means it's not compatible with iOS
12.x. But that made the implementation a lot simpler, which I think is a
useful tradeoff._
### Depends on:
- #1970
- #1971
- #1973
- #1974
- #1975
- #1976
[CSDK-451]:
https://revenuecats.atlassian.net/browse/CSDK-451?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
* [CF-106] Fetch AdServices Token (#1519)
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
Co-authored-by: Josh Holtz <me@joshholtz.com>
* [CF-553] Post AdServices token (#1534)
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
Co-authored-by: Josh Holtz <me@joshholtz.com>
* Update ios 14 snapshots tets
* Reworked adservices to use new Purchases.shared.attribution API
* Updated with some comments from PR
* Add iAd code back (#1739)
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
* use new mapKeys dictionary extension for device cache
* update for some pr comments
* remove purchasestests
* generate missing snapshots
* fix deprecation messages to clarify method now called on shared instance
* Fix for inserting nonstring into userdefaults
* Add tests for bug
* fix lint
* Added availablility checks for tests and removed unused varialbes
* Whoops... wrong class
Co-authored-by: beylmk <maddie@revenuecat.com>
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
* Create and plumb MockIdentityAPI
* MockOfferingsAPI and remove proxied OfferingsAPI api from Backend
* Reference identity directly, instead of backend.identity
### Motivation:
Initially I wanted to make `SubscriberAttribute.asDictionary` work using `Codable`. However, this isn't the right refactor because we need the actual raw types to be encoded inside `UserDefaults`.
At least this refactor provides several improvements:
### Changes:
- `SubscriberAttribute` now has value semantics
- ⚠️ `SubscriberAttribute.isSynced` used to be mutable, with reference semantics, which was dangerous
- `SubscriberAttribute: Equatable` implementation is now automatic
- Cleaned up `SubscriberAttribute.asDictionary` implementation, extracting keys into an `enum`
- Moved `Dictionary` -> `SubscriberAttribute` creation to the type itself
- ⚠️ `SubscriberAttribute.init(dictionary:)` returns an `Optional` instead of using force-unwrap, avoiding potential crashes
- Added more serialization / deserialization tests
- Removed `SubscriberAttributesMarshaller` and moved method into `SubscriberAttribute` extension
- Moved `SubscriberAttributeDict` into `SubscriberAttribute.Dictionary`
Extract out various dependencies that are required to instantiate the `Backend` object.
Refactor to assist with the next few PRs that extract out other pieces
See [CSDK-82]
Resolves [CSDK-155]
* Resolves [CF-443]
* Adds `configureWithConfiguration` to `RCPurchasesAPI.m`
* Create Configuration object and API to configure Purchases
* Update API doc for new Purchases API
* Add example code to Configuration documentation
* Adds deprecations for various Purchases.configure methods
Closes#695 and finishes [CF-195].
Depends on ~~#1431, #1432, #1433, #1437~~.
## Goals:
- [x] Handle all requests / response / deserialization errors in `HTTPClient`. Clients of `HTTPClient` will only have to handle the "happy" path: #1431
- [x] `HTTPClient` shouldn't return `Result.success` with failed responses, forcing clients to verify the response is actually a failure: https://github.com/RevenueCat/purchases-ios/pull/1431
- [x] Abstract error response deserialization / error creation: #1427
- [x] Abstract attribute error parsing: #1427
- [x] Move response deserialization to `HTTPClient` based on a `ResponseType: Decodable` type, so the completion block will simply return a `Result<HTTPResponse<ResponseType>, Error>`
- [x] `ETagManager` should store response `Data` instead of a deserialized `[String: Any]`
- [x] Improved error types in `HTTPClient` to fix tests: #1437
- [x] Dealt with non-backwards compatible `ETagManager: #1438
## Changes:
- Replaced `HTTPResponse`'s body from `[String: Any]` to a generic `HTTPResponseBody`.
- Created `HTTPResponseBody` to abstract `Decodable` and provide some default implementations for types like `Data,` `[String: Any]` (for backwards compatibility to types that aren't `Decodable` yet), and `Decodable` itself.
- New `HTTPResponse.Result` typealias (`Result<HTTPResponse<HTTPResponseBody>, Error>`) used everywhere. This will allow replacing `Error` with a more specific `Error` so we can forward known typed errors, and make sure that we don't end up with the wrong error type, or with a very complex error hierarchy and the details buried in `underlyingError`.
- Each layer (only a few for now) has its own error type: `NetworkError`, `BackendError`, `OfferingsManager.Error`.
- `HTTPClient` for example has to produce `NetworkError`, operations produce `BackendError`
- The parent `BackendError` can have specific errors like `.missingAppUserID`, but also be simply a child error `case networkError(NetworkError)`
- All of these conform to a `ErrorCodeConvertible`, so there is a single point of code that converts from simple and readable errors (like `BackendError.emptySubscriberAttributes`, `.unexpectedBackendResponse(.loginResponseDecoding)`) into errors with all the context using `ErrorUtils`
- Converted `DNSError` into `NetworkError.dnsError`. Its functionality remains unchanged.
- Removed `Backend.RCSuccessfullySyncedKey` and `ErrorDetails.finishableKey` in favor of tested properties on `NetworkError`
### Leftovers
There's a few things I've decided to not finish for now:
- [ ] `CustomerInfo` still does't conform to `Decodable` (manual deserialization is still supported by the current system): #1496
- `SubscriberAttributeDict` could also be `Codable`
- [x] Replace `OfferingsFactory` with `Decodable`: #1435
[CF-195]: https://revenuecats.atlassian.net/browse/CF-195?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ