5958 Commits
Author SHA1 Message Date
Facundo Menzella f0ee44df93 Reduce fixture UI test time in CI (#8244)
* Reduce fixture UI test time in CI

* Check fixture UI conditions before waits

* Reuse the app across carousel close checks

* Run fixture UI tests on release branches
2026-11-09 16:37:35 +01:00
Facundo Menzella 3d8461686f ONC-34: Fix tab-button discount package context (#8187)
* Fix tab button discount context

* Fix tab discount tests in hostless CI

* Test shared discount comparison updates for empty tabs

* test: remove diagnostic output from tab discount tests
2026-11-09 15:24:00 +00:00
Antonio Pallares e59cb4e68a Revert CocoaPods migration warning (#8203) (#8239)
* Fix CocoaPods trunk compatibility for migration warning

* Revert CocoaPods migration warning
2026-11-09 15:12:46 +00:00
Peter Porfy b5530243e1 feat(ads): cache customer info from verified reward polls instead of refetching (#8166)
* feat(ads): cache customer info from verified reward polls instead of refetching

* fix(ads): cache reward poll customer info under the user it was polled for

* refactor(ads): require customerInfo on Outcome.Verified

* refactor(ads): require customerInfo on RewardVerificationPollStatus.Verified

* refactor(ads): require customerInfo on RewardVerificationStatusResponse.init

* docs(ads): describe pollRewardVerification as updating state from the response

* fix(ads): poll reward verification for the user captured before polling

* fix(ads): reword malformed customer info log now that the poll no longer refetches

* fix(ads): treat a null subscriber in the reward poll as no customer info

* refactor(ads): pass appUserID through the poll run instead of storing it in the poller

* refactor(ads): drop async from rewardVerificationResult

* test(ads): assert the null subscriber guard skips the malformed customer info warning

* test(ads): assert the polled appUserID stays fixed across attempts

* docs(ads): fix the fetchRewardVerificationStatus reference in the poller doc comment
2026-11-09 14:51:33 +01:00
Rick 0dfc773979 Stabilize pending purchase and renewal integration test (#8224)
* test: stabilize offline pending renewal integration test

* ci: run offline integration tests ten times

* ci: disable danger during offline test stress run

* test: extend pending renewal finish timeout

* ci: remove offline integration stress workflow

* test: verify pending transactions by state

* ci: rerun offline integration stress test

* ci: remove offline integration stress workflow

* test: verify exact unfinished transaction IDs

* ci: rerun exact transaction stress test

* ci: remove exact transaction stress workflow
2026-11-09 14:46:22 +01:00
Antonio PallaresandCursor 4d354891d1 Restrict GitHub tokens to the jobs that need them (#8242)
* Restrict GitHub write tokens to the jobs that need them

Co-authored-by: Cursor <cursoragent@cursor.com>

* Use the danger-bot context for jobs that use the Danger token

Co-authored-by: Cursor <cursoragent@cursor.com>

* Give snapshot workflows the write token to open snapshot PRs

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-09 13:16:38 +01:00
RevenueCat Git BotandRenovate 532f8b66c8 [RENOVATE] Update dependency revenuecat to v4.8.0 (#8240)
Co-authored-by: Renovate <renovate@whitesourcesoftware.com>
2026-11-09 06:55:02 +01:00
RevenueCat Git Bot c9c4ede1da Preparing for next version (#8237) 2026-11-06 10:05:31 -06:00
RevenueCat Git BotandAntonio Pallares 56b2ebff25 Version bump for 5.102.3 (#8233)
Co-authored-by: Antonio Pallares <ajpallares@users.noreply.github.com>
2026-11-06 16:48:54 +01:00
Álvaro Brey 87417b48b2 ci: merge gate that tightens once the full suite is approved (#8235)
* ci: post a merge gate status that tightens once the full suite is approved

Adds a ci/all-tests-gate commit status driven from CircleCI. A no-requires
job posts success at pipeline start, approving the full-suite hold flips
it to pending, and all-tasks-passed posts success again once every full
job is green. Release pipelines post it from all-tests-succeeded so
release PRs are not blocked once the context is required.

The reduced suite needs no gate of its own: its jobs are already required
individually.

* test: find the merge gate by its instance name

all-tasks-passed is now an instance of the parameterized post-gate-status
job, so the workflow entry is keyed by the job name and carries name:.

* ci: never post the default gate success once the full suite is requested

full-suite-not-requested waits for the reduced suite and checks the
hold first: approved means halt without posting, so the gate goes from
unreported straight to pending; anything but on_hold fails the job
rather than posting success. all-tasks-passed reaches the reduced suite
through full-suite-started, so it keeps a single list, and the test
guards the list that gates normal PRs.

* ci: retry the gate status post

A failed POST leaves the gate at its previous value: green if the pending
post fails, stuck if the final success post fails. Retrying transient
errors narrows both. --retry-all-errors is not used: the cimg/base curl
predates it.

* ci: mark the merge gate pending when the bot approves the full suite

The bare @RCGitBot please test comment is the usual way to request the
full suite. Posting pending from the action right after a successful
approval closes the window on that path; a re-comment on an already
approved hold posts nothing. Manual approvals in the CircleCI UI keep
the window of one container start.

* ci: pin the gate's ordering in a test and trim the fan-in list

Asserts the state of each gate instance and the requires edges that
keep pending after the default success and the final success last.
Drops the two reduced-suite jobs all-tasks-passed still listed directly,
and lets the hold check log a curl failure instead of a bare exit code.
2026-11-06 15:32:43 +00:00
Peter Porfy 0ab6c0f032 feat(checkpoints): gate rewarded ad steps on an earned reward (#8232)
* feat(checkpoints): gate rewarded ad steps on an earned reward

* docs(checkpoints): clarify a rewarded ad passes on verified viewing, not a grant
2026-11-06 15:42:29 +01:00
RevenueCat Git BotandFacundo Menzella 95962326a5 Preparing for next version (#8231)
Co-authored-by: Facundo Menzella <facumenzella@users.noreply.github.com>
2026-11-06 10:45:51 +00:00
cd2ea7ef76 fix(paywalls): stop nested Fill stacks from hanging on iOS 17 (#8230)
* fix(paywalls): stop nested Fill stacks from hanging on iOS 17

On iOS 17, SwiftUI places a frame's content three times per placement
whenever an ancestor proposes an unbounded size, as the paywall's root
ScrollView or ViewThatFits does. Each nested Fill stack multiplies that,
so a paywall about a dozen stacks deep keeps the main thread busy for
minutes and never appears.

Fill sizing now goes through a single-child Layout on iOS 17 that sizes
like the frame did and aligns by size, placing its content once.



* refactor(paywalls): trim FillLayout to its essentials

Drops the negative-proposal clamp, which SwiftUI never needs, and folds
the alignment fractions inline. Behavior and test coverage are unchanged.



* refactor(paywalls): move Layout conformances into extensions

Follows the style guide: stored properties in the declaration, protocol
conformance in an extension.



---------

Co-authored-by: Nevyn Bengtsson <nevyn.jpg@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-05 15:29:18 -06:00
dependabot[bot] f9e18cbf7f Chore(deps): Bump nokogiri from 1.19.4 to 1.19.6 (#8216)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.19.4 to 1.19.6.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.19.4...v1.19.6)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-version: 1.19.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-05 18:36:05 +01:00
RevenueCat Git Bot 94746e3949 Version bump for 5.102.2 (#8228) 2026-11-05 11:30:29 -06:00
Rosie Watson b7f4c61059 ONC-46 | Close open paywall sheet after in-app purchase (#8220)
* fix(paywalls): close open sheet after in-app purchase

A purchase made from inside a V2 paywall sheet only requested a dismissal of
the whole paywall, which does nothing when the paywall is embedded (e.g. the
Flutter PaywallView in a persistent tab), so the sheet stayed open. Close it
when the purchase completes.

ONC-46

* fix(paywalls): close the sheet after every purchase, not just the first

hasPurchasedInSession stays true after the first purchase in an embedded paywall,
so key the sheet close on the session purchase result instead.

* Read PurchaseHandler directly in the sheet modifier instead of a new environment value

* Restore nil-default sessionPurchaseResult environment value

Reading PurchaseHandler as an environment object crashes hosts that render RootView without one (layout fixtures, previews).

* Test that the sheet closes after every purchase
2026-11-05 16:50:56 +00:00
Jacob Rakidzich 05faffdd81 fix(Paywalls) Package selection resolution on older OSes (#8226) 2026-11-05 16:25:06 +01:00
Facundo MenzellaandRCGitBot 3cc82762f7 Add workflow prewarming performance benchmark (#8206)
* Add workflow prewarming performance benchmark

* Add performance baseline recording and comparison

* Move performance baseline recording and checks into XCTest

* Declare performance tolerance in tests and exclude legacy project checks

* Simplify memory benchmark and run it on each PR

* Use published workflow for performance benchmark

* Add PR job to record and push performance baselines

* Update performance baselines

* Run baseline automation tests on PRs and use Fastlane with Xcode 27

* Update performance baselines

* Require performance benchmark in PR merge gate

---------

Co-authored-by: RCGitBot <dev+RCGitBot@revenuecat.com>
2026-11-05 14:16:45 +00:00
Rick 4e1c604b30 test(events): isolate feature event flush assertions (#8219) 2026-11-05 14:56:25 +01:00
Rick 3fe45f530b refactor(paywalls): remove internal paywall components prewarming (#8207)
* Remove internal paywall component prewarming

* Remove redundant workflow publication state

* Clarify workflow publication comment

* Harden V1 paywall asset prewarming test

* Assert workflow deduplication using screen batches

* refactor(paywalls): clarify asset prewarming state
2026-11-05 14:18:03 +01:00
Rick 33d2211a36 fix: present Test Store UI in the passed presentationContext (#7978)
* fix: respect presentation context in Test Store

* refactor: keep default presentation context internal

* refactor: use generalized presentation context

* refactor: simplify presentation platform branches

* refactor: group simulated store purchase context

* docs: clarify purchase presentation context support

* fix: cancel dismissed test store sheets

* refactor: unify presentation context declaration

* refactor: require simulated store presentation context argument

* fix: handle unavailable macOS presentation windows

* fix: preserve explicit presentation context failures

* docs: clarify scene purchase presentation behavior

* docs: clarify window purchase presentation behavior

* fix: resolve macOS sheet window from presentation context
2026-11-05 12:10:56 +01:00
Rick f4bfee9f68 fix: centralize presentation context resolution (#7977)
* refactor: generalize purchase presentation context

* fix: ignore non-window presentation scenes

* test: cover non-window scene filtering

* refactor: generalize presentation context naming

* fix: mark presentation context initializers as SPI

* refactor: use checked Sendable conformance
2026-11-05 12:10:56 +01:00
Rick d084b2fe23 test(storekit): work around iOS 27 active repurchase hang (#8214)
* test(storekit): work around iOS 27 active repurchase hang

* test(storekit): preserve JWS in iOS 27 workaround
2026-11-05 11:40:42 +01:00
Rick ea3596122d test: fix flaky StoreKit 1 receipt retry test (#8213)
* Fix flaky StoreKit 1 retry integration test

* test: assert retries for purchase receipt request
2026-11-05 11:03:23 +01:00
RevenueCat Git Bot 10f8893a62 Preparing for next version (#8215) 2026-11-05 09:54:14 +00:00
RevenueCat Git Bot 8c5774300e Version bump for 5.102.1 (#8212) 2026-11-05 03:36:28 -06:00
Rosie Watson 28e209aa0e WFL-822 | Add Maestro tests for workflow branch routing (#8210)
* test(workflows): add Maestro tests for workflow branch routing

Covers the default route (Testimonials 1 to paywall) and an es-ES locale audience routing to Testimonials 3.

* test(workflows): trim branch test comments
2026-11-05 09:09:05 +00:00
Facundo Menzella 5b6d89db79 Fix video controls intercepting taps outside the video (#8182)
* Fix video controls intercepting taps outside the video

* Fix video touch area for masked shapes
2026-11-05 08:41:17 +00:00
Antonio PallaresandCursor d1d09c178b Warn CocoaPods users to migrate to Swift Package Manager (#8203)
* Warn CocoaPods users about Swift Package Manager migration

* Avoid redundant Xcode warning for CocoaPods migration phase

* Say "the CocoaPods trunk" in the migration warning

Co-authored-by: Cursor <cursoragent@cursor.com>

* Use rev.cat short link in the migration warning

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-05 09:03:19 +01:00
Jacob RakidzichandJosh Holtz 3a4779279b Fix(Paywalls) Package Selection/Resolution (#8145)
* sheet resolution

* pass resolver around in buttons

* tab memory

* finish sheet resolution

* tests

* add missing file

* move tests to fixture tests for ci

* Reconcile manual package selection when its containing stack is hidden

* Respect tabs visibility when resolving package selection

---------

Co-authored-by: Josh Holtz <me@joshholtz.com>
2026-11-04 17:05:52 +00:00
Antonio PallaresandCursor 28723a87e7 Let the testing apps simulate API source outages (#8196)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-04 17:00:12 +00:00
Antonio PallaresandCursor 7c12636671 Enable API sources for everyone by removing the usesRemoteConfigAPISources dangerous setting (#8195)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-04 17:42:52 +01:00
dependabot[bot] 71277d6188 Chore(deps): Bump fastlane-plugin-revenuecat_internal (#8201)
Bumps [fastlane-plugin-revenuecat_internal](https://github.com/RevenueCat/fastlane-plugin-revenuecat_internal) from `996879c` to `1e7875c`.
- [Release notes](https://github.com/RevenueCat/fastlane-plugin-revenuecat_internal/releases)
- [Commits](https://github.com/RevenueCat/fastlane-plugin-revenuecat_internal/compare/996879cd7f55483edc1ffb9e0cf10a45985abd66...1e7875ca4a57b940cb6182dd3fa125c2faa66128)

---
updated-dependencies:
- dependency-name: fastlane-plugin-revenuecat_internal
  dependency-version: 1e7875ca4a57b940cb6182dd3fa125c2faa66128
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-04 16:37:24 +01:00
Jacob Rakidzich 05e1c4138b Fix(Paywalls) correctly identify tab content (#8198)
Switching between tabs with web views and nested billing tabs could show the previous tab’s web content and hide purchase controls. Now we set explicit identities so the index no longer identifies the content
2026-11-04 07:47:16 -06:00
Rick f812926c2b Fix thread-safe sandbox environment detection (#8202) 2026-11-04 12:44:11 +01:00
Josh Holtz a8a5a0a308 Prefetch paywall images only for the displayed localization (#8188)
* Prefetch localized paywall images only for the displayed language

* Scope asset prewarming deduplication to locale preferences
2026-11-03 23:48:48 -06:00
Facundo MenzellaandClaude Opus 5.5 afd06bf825 Move rc-maestro to Projects and rename it AutomatedSDKTestsApp (#8190)
* other: move PurchaseTester to Projects

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* other(ci): add a PurchaseTester smoke build with Tuist

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* other: move rc-maestro to Projects

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* other: rename rc-maestro to AutomatedSDKTestsApp

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 15:21:45 +00:00
RevenueCat Git Bot 735b5e5d6b Preparing for next version (#8193) 2026-11-03 15:06:24 +00:00
RevenueCat Git Bot 3b54af8f8a [AUTOMATIC] Release/5.102.0 (#8191)
* Version bump for 5.102.0

* Update RevenueCat-Swift.h for version 5.102.0
2026-11-03 15:50:43 +01:00
Rick 0efd41b2ce fix: Reduce CPU usage when downloading large assets (#8177)
* fix: Reduce CPU usage when downloading large assets

* fix: Release checksum buffers while hashing files

* test: Remove duplicate file repository tests
2026-11-03 13:49:58 +01:00
Cesar de la VegaandClaude Sonnet 5.5 c8aa5951ce feat(checkpoints): Add internal error dialog factory for checkpoints (#8134)
* Add internal error dialog factory for checkpoints

Lets a hybrid bridge supply the content of the checkpoint error dialog while the SDK keeps presenting it. Internal only (`@_spi(Internal)`).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix: address error dialog factory review feedback

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* refactor: Drop error dialog factory timeout

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* refactor: Reuse DefaultErrorPresenter.makeAlert for dialog factory content

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Add explicit checkpoint error dialog outcomes

* fix(checkpoints): Require explicit error dialog factory in call params

* fix(checkpoints): Address error dialog factory review feedback

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-03 13:02:47 +01:00
Facundo MenzellaandClaude Opus 5.5 e59f0f3251 Move PurchaseTester to Projects (#8189)
* other: move PurchaseTester to Projects

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* other(ci): add a PurchaseTester smoke build with Tuist

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 12:02:57 +01:00
Facundo MenzellaandClaude Opus 5.5 8205ba615f other: move the checkpoint samples to SampleCat and delete CheckpointTester (#8162)
* other(samplecat): add a Checkpoints tab with 4 samples

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* other: delete CheckpointTester

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* other: point agents to SampleCat for integration examples

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* other(samplecat): use result.hasEntitlement in checkpoint callbacks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* other(ci): add a SampleCat smoke build with Tuist (#8163)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 10:34:19 +00:00
Álvaro MarcoandÁlvaro Marco 2ebc74ec40 fix: preserve workflow attribution in custom paywall impressions (#8183)
* fix(paywalls): preserve workflow context in custom impressions

* refactor: simplify offering context copies

---------

Co-authored-by: Álvaro Marco <alvaro.marco@revenuecat.com>
2026-11-03 09:27:56 +01:00
Jacob Rakidzich 25e72ed413 Fix(Paywalls) Prioritize app locale - opt in via remote configuration (#8165)
* bundle locale > device setting

* use remote flag

* preserve region
2026-11-02 13:19:57 -06:00
Peter Porfy 6d64d3c8de feat(ads): dispatch checkpoint ad presentation by format (#7786)
* feat(ads): dispatch checkpoint ad presentation by format

Ad units are format-locked, so the SDK needs to know which AdMob loader a
checkpoint ad step's unit belongs to. The backend now requires ad_format
on the step; core surfaces it on ResolvedAdStep, RevenueCatUI threads it
through AdPresentationParams, and the AdMob adapter replaces its three
per-format presenters with one AdMobPresenter that dispatches on it and
fails fast on formats it does not implement.

* refactor: presenter composition

* fix: use renamed InviteOnlyCheckpointsApi SPI

* test(ads): assert on shown and failed ad executions

The ad outcome classes are gone, so the format-aware presenter reports
shown for every format and the tests match the execution cases.

* test(ads): match failed ad executions and the ad format param

Claude-Session: https://claude.ai/code/session_01Gj5NLpaCp45dfxDVR5rScP

* fix(ads): keep the ad params initializer internal-only

The adapter tests are the only external caller, so the init is SPI
rather than public, as the no_new_public_inits rule requires. Also
passes the ad format in the missing-presenter behavior test.

Claude-Session: https://claude.ai/code/session_01Gj5NLpaCp45dfxDVR5rScP

* fix(ads): mark AdMob presenter inits as SPI for lint

Claude-Session: https://claude.ai/code/session_01Gj5NLpaCp45dfxDVR5rScP

* test(api): cover AdPresentationParams.adFormat in the RevenueCatUI API tester
2026-11-02 17:49:58 +01:00
Will Taylor 50444c22d9 lint: add SwiftLint rule against Int for epoch milliseconds (#8181) 2026-11-02 09:43:05 -06:00
Peter Porfy cd9357a08a feat(ads): extend admob presenter with rewarded support (#7785)
* feat(ads): AdMob rewarded checkpoint presenter

* feat(ads): AdMob rewarded interstitial checkpoint presenter

* refactor: common base for both rewarded presenter

* fix: drop weak self in rewarded presentation task

* fix: use renamed InviteOnlyCheckpointsApi SPI

* fix(ads): report rewarded outcomes as shown

AdPresentationResult no longer carries reward cases: a verified reward
reaches the app through the checkpoint result, and a reward that failed
verification is logged while the checkpoint still passes.

* refactor(ads): carry the verification result in the rewarded outcome

* fix: linter

* refactor: use the internal helper

* refactor(ads): drop the verification result from the rewarded outcome
2026-11-02 16:27:01 +01:00
Álvaro Brey d48d4f85aa ci: limit the Lock Threads token to issues: write (#8178) 2026-11-02 13:17:35 +01:00
Álvaro Brey 30b1b1c74a ci: run actionlint from the shared workflow (#8159)
* ci: run actionlint from the shared workflow

Replaces `docker://rhysd/actionlint:latest` with the reusable workflow in `sdk-github-workflows`, which runs a checksum-pinned release binary. GitHub rejects `docker://` references under a selected-actions policy.

* ci: repin shared actionlint workflow

* ci: pin shared actionlint workflow to v10
2026-11-02 11:31:15 +01:00