* Pull files from staging branch to introduce a file repository and intelligent task sharing
* removed typed throws and fix some docs
* Make tests satisfy predictive swift 6 failures
* @_spi(Internal) public
* Stop using the shared instance in an instance method
* Pull cache directory logic out of file repository
* update cache naming conventions
* @fire-at-will feedback -> use url instead of path
* Use strings file pattern
* remove priority from repository
* Remove RC Internal access from keyed deferred value store
* Remove spi internal from cache and network service
* makeSUT -> makeSystemUnderTest
* remove public scope in extensions
* rename function for clarity
* Add validation logic for Test Store API keys under the TEST_STORE compiler flag
* add unit test for test store api key validation
* Move API key validation to `configure` and store validation result in `SystemInfo`
* start new flow for purchase of `TestStoreProduct`s
* WIP: implement alert for purchase of a Test Store product
* Add file to Xcode workspace
* WIP: implement fake purchase alert in all platforms and OSs
* Enforce only one test purchases at once. Use constants for test purchase alert strings
* Place new test store purchase APIs under the TEST_STORE compiler flag
* fix lint
* fix unit tests after change of internal APIs
* PR comments
* temporarily return hardcoded `CustomerInfo` on confirmed test purchase
* tests: adapt unit tests to new `TestStorePurchaseHandler` dependency of `PurchasesOrchestrator`
* fix lint
* Fix backend integration tests compilation
* Remove deprecation warning
* remove unnecessary OSs checks
Since the minimum supported versions of the SDK are iOS 13 and tvOS 13
* add `GetWebProductsOperation`
* avoid duplicating decoding objects from WebOfferingProductsResponse and WebProductsResponse
* add missing tests snapshots
* Add `WebProductsResponse.ProductType` enum
* Fix tests
* add web products decoding tests
* Rename WebProducts to WebBillingProducts
* (more) rename WebProducts to WebBillingProducts
* (even more) rename WebProducts to WebBillingProducts
* Move `getWebBillingProducts` outside of `OfferingsAPI` into a new `WebBillingAPI` object
* improve test
* remove unnecessary `sorted()` of `Set`
* fix lint
* fix tests
Since the GetWebBilling request path contains an unordered set of productIds, which the tests do not support, we're only doing snapshot tests with 1 product ID
* fix more tests
* Revert "Temporary revert of automatic health reporting in the SDK (#5353)"
This reverts commit dd7086fd98.
* Do not run health check when running integration tests
* Revert "fix `Purchases` temporary leak when running SDK health check (#5350)"
This reverts commit 26de54308c.
* Revert "[DX-457] Log the SDK configuration report on every `#DEBUG` run (#5317)"
This reverts commit 21f226de00.
* Creates a brand new SDK Manager to reuse logic across different classes
* Updates to use the new manager
* Adds a new method to log the health report to the console only for debug builds
* Run health check for debug builds
* Fixes sendable warnings that got introduced with new manager
* Fixes swiftlint violations
* Adds unit tests for the new SDK Health manager
* Creates a new authorization provider
* Injects the new authorization provider
* Tidies and cleans up unit tests
* Adds a new configuration value
* Updates configuration unit tests
* Makes sure that values are only set on DEBUG configuration
* Reverts state of default value
* Updates wording of output message
* Fixes the wrong wording of error message
* Logs the word RevenueCat along with report title
* Fixes wording issues in error messages
* Addresses PR comments
* Adds extra checks
* Renames configuration value
* Removes unnecessary `Task`
* Renames parameter
* Calls the new endpoint in the BE to check if the app is available or not
* Do not log or perform the report operations if it is not available
* Missing xcodeproj changes
* Adds unit test coverage
* Turns validation on by default
* Creates a new path for the report availability endpoint
* We need to bypass auth but make sure that requests are still signed
* Updates the name of the response field
* Updates unit tests target with new response structure
* Handles no credentials case more gracefully
* Adds new unit tests for the new No ASC credentials warning
* Updates the file's header comment
* Adds documentation
* Wraps calls in necessary compiler directives
* Hide all report-related content behind compiler directives
* Makes more health-related functionality DEBUG only
* Addresses PR comments
* Updates all unit test build failures
* Gets it back to compile on `CUSTOM_ENTITLEMENT_COMPUTATION`
* Removes configuration value
* Updates logging to only include issues
* Adds a mock method for the health report availability request
* Add new public APIs to RevenueCatUI to set the preferred local for the UI components
* fix compliation of RevenueCatUI with new APIs
* add API tests
* implement preferred locale in paywalls
* complete implementation
* adapt unit tests
* adapt paywalls tester
* Add new tests to check preferred locale override
* fix lint
* discard all changes in RevenueCatUI (for separate PR)
* remove trailing comma
* fix tests
* Fix tests
* fix paywalls tester compilation
* remove spoiler from future PR
* Refactor `PreferredLocalesProvider` (#5299)
* refactor: reduce `PreferredLocalesProviderType` into `PreferredLocalesProvider` class
* make `preferredLocaleOverride` private in `PreferredLocalesProvider`
* make `SystemInfo`'s `preferredLocalesProvider` private
* rename `PreferredLocalesProvider`'s mock init parameters
* fix compilation issue
* Change to use new endpoint to fetch web product info
* [skip ci] Generating new test snapshots (#5142)
* [skip ci] Generating new test snapshots (#5141)
* [skip ci] Generating new test snapshots (#5140)
* [skip ci] Generating new test snapshots (#5139)
* [skip ci] Generating new test snapshots (#5138)
* [skip ci] Generating new test snapshots (#5137)
* [skip ci] Generating new test snapshots (#5136)
* Add small utility function to know if offerings has any web biling offering available
---------
Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com>
* Add support for fetching web billing products
* Some fixes
* Escape product ids
* Fixes from review
* Support etags
* Change to Int64
* Add method to MockOfferingsAPI
* feat: implement fallback host in all URL requests
* cleanup fallback host API implementation
* Adapt existing tests to changes in `HTTPRequestPath`
* fix implementation
* add unit tests for fallback API host
* add extra unit test
* fix tests
* fix lint
* implement new `host` parameter in `http_request_performed` diagnostics event
* add unit tests for new `host` diagnostics parameter
* change the logic from fallback hosts to fallback paths
* fix test
* fix fallback endpoint for get product entitlement mapping
* fix backend integration tests not building after changes
* rewrite fallback host functionality knowing that only some specific requests support a fallback host
For those requests that support a fallback host, the path, headers and response structure remain the same
* fix text name
* fix unit test
* remove extra comma
* fix unit test
* feat: implement fallback host in all URL requests
* cleanup fallback host API implementation
* Adapt existing tests to changes in `HTTPRequestPath`
* fix implementation
* add unit tests for fallback API host
* add extra unit test
* fix tests
* fix lint
* change the logic from fallback hosts to fallback paths
* fix test
* fix fallback endpoint for get product entitlement mapping
* fix backend integration tests not building after changes
* rewrite fallback host functionality knowing that only some specific requests support a fallback host
For those requests that support a fallback host, the path, headers and response structure remain the same
* fix text name
* Initial app creation
* Initial screen
* Installs and configures the SDK
* Creates a full Swift 6 compliant ViewModel
* Adds a demo customer center button
* Fixes icon name
* Updates a bit of the logic to fetch offerings
* Updates initial layout by showing offerings
* Makes more progress with a VERY DRAFT and VERY WIP screen
* Creates a new network path and requests
* Creates a new health API and adds it to the BE class
* Creates a `checkOfferings` method
* Pushes local changes
* Moved viewmodels to separate files
* Prepared some basic UI structure
* Initial shell of the new method for testing
* Initial implementation of `HealthReportOperation` from the SDK
* Passes `appUserId` through to the internal API
* Adds a new path called `appUserID`
* Removes 'old' `appHealth` endpoint
* Creates a new model for the network response
* Report should be the response type
* Updates backend request
* Updates types and documentation for the new internal request
* Moves validation into its own file
* Replaces method for DebugViewModel
* Updates error messages
* Updates the `Status` section
* Adds logic to show failure reason
* Removes Sample App from PR
* Resets `Package.resolved`
* Availability checks
* Check if device is authorized to make payments
* Fixes all SwiftLint errors
* Updates `ProductStatus` to not have a raw value of String
* Minor style fixes
* Removes warning
* Adds more availability checks
* Fixes comments
Co-authored-by: Antonio Pallares <ajpallares@users.noreply.github.com>
* Simplifies logic
* Updates comment
* Updates the comments to denote that this method is not intended for production use
* Removes android-only invalid SDK version error
* Adds an action button that the user can use to open the dashboard
* Updates copy about non-actionable item
* Prefers `Your RevenueCat Configuration` to `The Dashboard`
* Removes `Sendable`-related warnings
* Fixes unit tests on CI/CD
* Fixes tests
* Adds unit test for offering configuration error
* Adds unit test for no packages in default offering
* Adds unit test for generic offering configuration
* Removes periods from the end of the error messages
* Adds unit tests for all new errors
* Fixes linter errors
* Wrap in a `DEBUG` compiler directive
* Includes all products in the healthy check status to be used in the Sample App
* Updates report to include product and offering information
* Moves logic over to the report rather than being exclusive to the Debug View
* Fixes CI/CD failures
* Updates the asset for the health check status
---------
Co-authored-by: Hidde van der Ploeg <hiddevanderploeg@me.com>
Co-authored-by: Antonio Pallares <ajpallares@users.noreply.github.com>
* Add X-Is-Backgrounded header
* Add unit test for presence of new header
* [skip ci] Generating new test snapshots (#4939)
* [skip ci] Generating new test snapshots (#4940)
* [skip ci] Generating new test snapshots (#4941)
* [skip ci] Generating new test snapshots (#4942)
* [skip ci] Generating new test snapshots (#4943)
* [skip ci] Generating new test snapshots (#4944)
* [skip ci] Generating new test snapshots (#4945)
* Lock isAppBackgrounded state to false during tests
* one more update
* Revert "Lock isAppBackgrounded state to false during tests"
This reverts commit 6a915a756a.
* Lock isAppBackgrounded state to false during tests
* Update tests
* Fix iOS 15 snapshot tests
* Remove unused isApplicationBackgrounded async method
---------
Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com>
* refactor: create `DiagnosticsEvent.Properties` struct with all possible fields in a diagnostics event
* chore: remove unnecessary `CodingKeys` and values as `JSONEncoder.KeyEncodingStrategy.convertToSnakeCase` is used in the diagnostics requests
* tests: WIP: adapt unit tests to new `DiagnosticsEvent.Properties`
* fix: have values in Diagnostics events be snake case
* tests: adapt unit tests to Diagnostics events changes
* fix: `name` parameter in DiagnosticsEvent
* tests: fix snapshot testing of JSON to use `.iso8601` date format
* tests: have `JSONEncoder` of snapshot tests be a copy of the encoder user in the SDK
* tests: update the dates in the `CustomerInfo` snapshots for decoding tests to have ISO 8601 format
* fix: remove duplicated import
* refactor: centralize some info transformations in `DiagnosticsEvent.Properties`' init
* tests: add snapshot tests for `DiagnosticsEvents` object
* feat: add `is_retry` parameter to Diagnostics `http_request_performed` event
* tests: consider new `isRetry` parameter in existing `DiagnosticsEvent` tests
* fix: make sure that the `http_request_performed` event is always called
The previous implementation would skip sending the event in the case of getting a `networkError`
<!-- Thank you for contributing to Purchases! Before pressing the
"Create Pull Request" button, please provide the following: -->
### Checklist
- [ ] If applicable, unit tests
- [ ] If applicable, create follow-up issues for `purchases-android` and
hybrids
### Motivation
<!-- Why is this change required? What problem does it solve? -->
<!-- Please link to issues following this format: Resolves#999999 -->
### Description
This adds the `backend_error_code` property to diagnostics
`http_request_performed` events.
### Motivation
Better implementation of
https://github.com/RevenueCat/purchases-ios/pull/3909 and what was just
commited to `5.0-dev`
### Description
- Only install `swiftlint` on Xcode 15.3 jobs
- Also moved Ruby 3.2.2 install into `install-bundle-dependencies` which
was also done in `5.0-dev`
### 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.
### Motivation
Allow backend to determine Storefront of customer
### Description
- Adds `X-Storefront` as a default header
- Uses `StoreKit 1` implementation since its not `async`
- `StoreKit 2` implementation is `async` and would require a some
restructuring that we don't need right now
---------
Co-authored-by: NachoSoto <ignaciosoto90@gmail.com>
Fixes#3343.
`SKPaymentTransaction.error` docs say:
> The error property is undefined except when `transactionState` is set
to `SKPaymentTransactionState.failed`. Your application can read the
error property to determine why the transaction failed. For a list of
error constants, see `SKErrorDomain` in StoreKit Constants.
Which is why [`PurchasesOrchestrator` only considered that
domain](https://github.com/RevenueCat/purchases-ios/blob/4.28.1/Sources/Purchasing/Purchases/PurchasesOrchestrator.swift#L792).
This expands this handling to consider any other network error,
therefore providing more precise errors.
Since offline connection error detection was only in `HTTPClient`, I
also moved that out and removed `NetworkError.offlineConnection`, so
that we detect this when converting `NetworkError.networkError` instead.
See https://github.com/RevenueCat/khepri/pull/6798.
This can help debug issues as it helps us cross-reference requests on
our end.
### Changes:
- Logging `X-Request-ID` and `X-Amzn-Trace-ID` headers if present (only
in verbose mode)
- Logging these even for failed requests
- Also logging `request_handled_by_load_shedder` for failed requests
- To accomplish that. `HTTPURLResponse` now conforms to our
`HTTPResponseType`, this allows us to extract headers in an uniform way
### Example:
```
[network] DEBUG: ℹ️ API request completed: GET '/v1/subscribers/$RCAnonymousID%3Ad9dc4f3b33054cf28c0f2ec9da0f48d5' (304)
Request-ID: 'be534c50-5231-403b-be2f-7c077861751d'; Amzn-Trace-ID: 'Root=1-6532c6ca-7ef80f961ec9c4145484df13'
```
We get a lot of flaky failures on `OfflineStoreKitIntegrationTests`
(example:
https://app.circleci.com/pipelines/github/RevenueCat/purchases-ios/14843/workflows/a3cffa7c-da25-4811-931d-fc241befee0f/jobs/118214/tests).
I managed to reproduce locally running some of these 100+ times on a
loop until they failed.
I traced the issue to this sequence:
- SK2 purchase
- `StoreKit.Transaction.unfinished` is empty
This is likely due to a race condition. In practice, when computing
offline `CustomerInfo`, we never check it right away, since we need to
wait for the server to return a 500.
I filed a Radar for this: `FB13133387`.
To make tests more realistic, I introduced a delay in `HTTPClient`
returning fake 5xx errors. I haven't been able to reproduce this issue
again, so this should make `OfflineStoreKitIntegrationTests` more
reliable.
I've also added a new debug log that could help debug similar issues,
because `Strings.offline.computed_offline_customer_info` was not very
complete.
This paves the way to add a second set of paths with a separate server
URL to be able to shed requests to offerings and product entitlement
mapping to a separate server.
### Changes:
- New `HTTPRequestPath` with the same properties as `HTTPRequest.Path` +
a new `serverHostURL`
- Moved proxy logic from `SystemInfo`/`HTTPClient` to `HTTPRequestPath`
- Simplified `HTTPRequest` implementation
This is a simple example, but on a larger JSON it becomes easier for us
to debug decoding the entire JSON rather than seeing only the part that
failed:
```
[codable] DEBUG: ℹ️ Encountered error when decoding JSON: {"e": "e3"}
[codable] ERROR: 😿‼️ Couldn't decode data from json, it was corrupted: Context(codingPath: [CodingKeys(stringValue: "e", intValue: nil)], debugDescription: "Cannot initialize E from invalid String value e3", underlyingError: nil)
```
### Changes:
- `HTTPClient` has a new `X-Post-Params-Hash` request header
- Replaced `HTTPRequest.Method.post`'s `Encodable` value with a more
specific `HTTPRequestBody` (like `HTTPResponseBody`)
- `HTTPRequestBody` allows overriding `contentForSignature` (it defaults
to `[]`) which then `Signing` uses for the hash
- Fixed `LogInOperation` not passing the `VerificationResult` to the
result `CustomerInfo`. This is captured in unit and integration tests
now.
- Add support for signing `POST` requests in `Path.logIn` and
`Path.postReceiptData`
Depends on https://github.com/RevenueCat/khepri/pull/6246
Example (the first `warn` log is `debug` and when running RC tests
only):
```
[signing] WARN: ⚠️ INVALID SIGNATURE DETECTED:
Request: GET /v1/subscribers/identify
Response: 200
Headers: ["X-Signature: signature", "X-RevenueCat-Request-Time: 1658749988564", "Content-Length: 0", "X-RevenueCat-ETag: etag"]
Body (length: 0): e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
[signing] ERROR: 😿‼️ Request to subscribers/identify failed verification. This is likely due to a malicious user intercepting and modifying requests.
```
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
We were escaping users for every (hopefully) request. This refactor
moves that responsibility to the path creation in `HTTPRequest.Path` to
ensure it's done consistently.
Additionally, this is required so that `SigningTests` produce a
consistent path (see #2746).
### Changes:
- `ETagManager` no longer stores the verification mode
- Created new `VerifiedHTTPResponse`, which has the
`VerificationResult`, extracted from `HTTPResponse`
- Removed `VerificationResult.from(cache:response:)`
- Changed `SignatureVerificationHTTPClientTests` to test using the real
`ETagManager`, so they become more "end to end" unit tests. A lot of
them were relying on implementation details of the mock instead of the
real `ETagManager`.
- Removed several `HTTPClient` tests that were checking a behavior that
was impossible (for example, no verification result despite it being
enabled), or that checked behavior based on the cached
`VerificationResult`