* Rename paywallsEventsManager to eventsManager
* Rename PaywallEventsManagerType to EventsManagerType
* Rename PaywallEventsManager to EventsManager
* Rename PaywallEventStore to FeatureEventStore
* Rename InternalAPI.postPaywallEvents to postFeatureEvents
* Rename StoredEventSerializer to StoredFeatureEventSerializer
* Rename createStoredEvent to createFeatureStoredEvent
* Rename StoredEvent to StoredFeatureEvent
* Rename HTTPRequest.PaywallPath to HTTPRequest.FeatureEventsPath
* Rearrange events files
* Rename event related files
* Extract shared events endpoint configuration to EventsHTTPRequestPath
Both FeatureEventsPath and AdPath share the same /v1/events endpoint
configuration, differing only in domain (api-paywalls.revenuecat.com vs
a.revenue.cat) and name. Extract common logic to EventsHTTPRequestPath
protocol in Sources/Events/Networking.
* Move Sources/FeatureEvents to Sources/Events/FeatureEvents
* Rename EventsRequest to FeatureEventsRequest
- Rename EventsRequest.swift to FeatureEventsRequest.swift
- Move file to Sources/Events/FeatureEvents/Networking/
- Update all references in source and test files
- Update Xcode project file references
This makes it clear that this request type is specifically for the
feature events endpoint, not a generic events request.
* Remove ad events from feature events system
Ad events should not be sent through the feature events system as they
require their own separate infrastructure with a different API endpoint.
Changes:
- Remove FeatureEvent conformance from AdEvent
- Remove .ads case from Feature enum
- Remove ad events handling from FeatureEventsRequest
- Add no-op track(adEvent:) method to EventsManager with comment
- Update AdTracker to call the new track(adEvent:) method
Ad events tracking now becomes a no-op until proper implementation with:
- StoredAdEvent structure
- AdEventStore for persistence
- InternalAPI.postAdEvents() using HTTPRequest.AdPath.postEvents
* Rename PostEventsOperation to PostFeatureEventsOperation
- Rename PostEventsOperation.swift to PostFeatureEventsOperation.swift
- Move file to Sources/Events/FeatureEvents/Networking/
- Update class name and remove misleading "generic" comment
- Update references in InternalAPI.swift
- Update Xcode project file references
This makes it clear that this operation is specifically for posting
feature events, not a generic operation for various event types.
* Add RC Ads event tracking infrastructure
Implements event tracking for RevenueCat Ads following the Paywalls Events pattern.
- Adds three event types: ad displayed, ad opened, and ad revenue
- Uses actor-based concurrency with file-based event storage
- Posts events to e.revenue.cat/v1/events endpoint
- Marks track(adEvent:) method as @_spi(Internal) for internal use
- Includes comprehensive unit tests with snapshot testing
- Available on iOS 15.0+, tvOS 15.0+, macOS 12.0+, watchOS 8.0+
Event schema follows khepri RC Ads input events specification with
app_session_id field matching backend expectations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Avoid mapping in EventsRequest+Ad
* Consolidate ad events into PaywallEventsManager
Eliminates duplication between AdEventsManager and PaywallEventsManager by:
- Making PaywallEventsManager handle all event types (ads, paywalls, customerCenter)
- Adding feature-aware routing in flushEvents() to send events to correct domains
- Ad events → https://e.revenue.cat/v1/events
- Other events → https://api-paywalls.revenuecat.com/v1/events
- Removing AdEventsManager, AdEventStore, and their tests (~500 lines)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove AdsStrings and use PaywallsStrings instead
AdsStrings only had 2 strings in use, both of which already exist in PaywallsStrings. Consolidates logging strings to eliminate duplication.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Namespace Precision enum inside AdEvent.RevenueData
Moves Precision from a top-level public enum to AdEvent.RevenueData.Precision to avoid polluting the global namespace and reduce autocomplete noise.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Move Precision conformances to end of file
Follows the pattern of other types by declaring protocol conformances at the end of the file rather than inline with the type definition.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove redundant sessionIdentifier from AdImpressionData
The sessionIdentifier field in AdImpressionData was redundant since
StoredEvent already tracks appSessionID. This change:
- Removes sessionIdentifier from AdImpressionData struct
- Uses storedEvent.appSessionID directly when building requests
- Renames sessionId to appSessionId to match backend field app_session_id
- Updates documentation examples to remove sessionIdentifier parameter
- Adds guard statement for optional appSessionID
- Updates all test fixtures and regenerates snapshots
- Removes iOS26 snapshot references from project
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove unneeded SessionId
* Add proper assertions to PurchasesAdEventsTests
Enhanced test coverage for public ad tracking APIs:
- Verify events are tracked via mockPaywallEventsManager
- Assert correct event types (displayed, opened, revenue)
- Validate all impression data fields
- Verify revenue-specific fields (revenueMicros, currency, precision)
All 3 tests now pass with proper verification.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add ENABLE_AD_EVENTS_TRACKING compiler flag
* Simplify track ad events APIs
* Fix ENABLE_AD_EVENTS_TRACKING scope and refactor Precision to struct
Compiler flag fixes:
- Move ENABLE_AD_EVENTS_TRACKING #endif to wrap all ad event code including internal enum
- Add compiler flag guards to all three test files
Precision API refactor:
- Change AdRevenue.Precision from enum to struct following Apple's API patterns (like Message.Reason)
- Use internal init(rawValue:) to prevent custom precision values
- Convert enum cases to static properties maintaining same public API
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Refactor mediatorName from String to MediatorName struct
Replace string-based mediator names with a type-safe struct following Apple's API patterns:
- Add MediatorName struct with public init(rawValue:) to support custom values
- Include predefined static properties for .adMob and .appLovin
- Update AdEventData protocol to require MediatorName type
- Update all event types (AdDisplayed, AdOpened, AdRevenue) to use MediatorName
- Use .rawValue when serializing to network requests
- Update all tests and documentation examples to use .appLovin
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove RawRepresentable conformance from Precision and update test snapshots
- Remove RawRepresentable conformance from AdRevenue.Precision to allow internal init
- Update test assertions to use .appLovin instead of string comparison
- Update all snapshot test files to use "AppLovin" instead of "MAX"
- All ad event tests now passing (11/11)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix PaywallDataDecodingTests locale check for region overrides
The test was failing when the system locale included region overrides
(e.g., "en_US@rg=eszzzz" instead of just "en_US").
Changes:
- Use beginWith("en_US") instead of exact equality check
- Compare against enConfig directly instead of fetching via Locale.current
This makes the test more robust while maintaining the same behavior validation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Rename timestampMs to timestamp but keep serialized timestamp_ms
* Use different serverHostURL
* Simplify and paralelize postEvents
* Adjust usage of ENABLE_AD_EVENTS_TRACKING flag
* Move track ad event methods to AdTracker
* Remove PaywallEventsManager implementation
* Improving naming overlapping naming AdEvent->AdEventRequest
* Simplify compiler flag usage
* Use Experimental
* Remove duplicate with PostPaywallEventsOperation and PostAdEventsOperation
* Remove postAdEvents methods assuming reuse of event storage
* Make Precision rawValue internal
* Remove runtime checks
* Trigger build
* Move Public Types MARK comment after internal protocol
* Add documentation for AdDisplayed, AdOpened, and AdRevenue properties
* Remove redundant smoke tests
The "DoesNotCrash" tests were completely redundant with the
comprehensive "StoresEvent" tests. The comprehensive tests already:
1. Verify methods don't crash (implicitly)
2. Verify events are stored
3. Verify event data is correct
Removed 3 redundant tests, keeping only the 3 comprehensive tests.
* Fix bug not tracking initialized events
---------
Co-authored-by: Claude <noreply@anthropic.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
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
### 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
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).
Instead of manually choosing when to include `nonce` in requests, this
data-driven approach ensures that all requests to endpoints that support
signature verification will make `HTTPClient` do the right thing.
See also #2277 for how `CustomerInfo` and `EntitlementInfo` will use
this.
Fixes [CSDK-634].
## Changes:
- Created `HTTPResponseValidationResult`
- Added `HTTPResponseValidationResult` and `HTTPClient.ResponseHeaders`
to `HTTPResponse`
- Added new `ErrorCode.signatureVerificationFailed`
- Extracted `SigningType` to create `MockSigning` to test `HTTPClient`
without bothering with signatures
- Refactored `ETagManager` to use `HTTPResponse`, making it easier to
pass through response headers and verification results
- Stored `HTTPResponseValidationResult` in `ETagManager` cache
- `HTTPClient` handles signatures from response based on
`SystemInfo.responseVerificationLevel`
- Renamed `HTTPRequest.createIntegrityEnforcedRequestRequest` to
`HTTPRequest.createWithResponseVerification`
- Added lots of tests for this new behavior in `HTTPClient`
- Added lots of new tests for `ETagManager`
[CSDK-634]:
https://revenuecats.atlassian.net/browse/CSDK-634?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
This breaks signature validation in #2267 because `PurchasesDiagnostics`
uses that endpoint with and without signature validation, so the first
time it makes a request, it stores the cached response without a
validated signature.
The best solution is to simply not send etags for this endpoint, since
it's used precisely to make sure that requests can be made with no
errors, and we wouldn't want false positives.
* [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>