Skip to content

feat(workflows): fetch workflows list with offerings and clear it on identity changes#6883

Merged
facumenzella merged 2 commits into
mainfrom
port/3508-workflows-lifecycle-pr3
Jun 4, 2026
Merged

feat(workflows): fetch workflows list with offerings and clear it on identity changes#6883
facumenzella merged 2 commits into
mainfrom
port/3508-workflows-lifecycle-pr3

Conversation

@facumenzella

@facumenzella facumenzella commented Jun 2, 2026

Copy link
Copy Markdown
Member

Port of RevenueCat/purchases-android#3508. Final piece of the workflows port. #6881 (cache) and #6882 (WorkflowManager) are merged, so this targets main directly: it wires the workflows pipeline into the offerings + identity lifecycle, behind a runtime gate.

What Changed

  • OfferingsManager takes an optional WorkflowManager. When offerings are delivered fresh (fresh in-memory cache, network success, disk fallback after a backend failure) it fetches the workflows list and prefetches its workflows before delivering, so workflowId(forOfferingId:) resolves as soon as getOfferings succeeds, with no race where a concurrent call delivers before the map is ready. A stale cached read still returns immediately and the workflows list refreshes in the background, so cached delivery is never blocked. A network refresh also calls forceWorkflowsListCacheStale() so the list refreshes alongside offerings. getWorkflowsList always calls its completion (even on failure), so delivery can never hang. When the manager is nil (gate off), the offerings path is unchanged.
  • IdentityManager clears the WorkflowsCache on login/alias, logout, and user switch, so a user switch never serves the previous user's workflows.
  • New WorkflowsCache.forceWorkflowsListCacheStale(): marks the list stale so the next fetch refetches, while workflowId(forOfferingId:) keeps resolving the current map until then.
  • Gating via SystemInfo.workflowsEndpointEnabled (the -EnableWorkflowsEndpoint launch arg). configure() only wires WorkflowManager / WorkflowsCache into offerings and identity when enabled, so it's off by default and production timing is untouched.

Notes

  • Mirrors the latest in the Android PR (Paywalls: open footer links on Safari on Catalyst #3508), which gates both the cached and network offerings paths (not just the network fetch) and force-stales the list on refresh.
  • One diff that looks unrelated: trialOrIntroPriceChecker + paywallCache construction moved up in configure() (above OfferingsManager) so the gated WorkflowManager can be passed in. No behavior change, just ordering.
  • When the gate is on, delivering fresh offerings waits on the workflows list fetch + prefetch CDN fetches. Intentional (the offeringId → workflowId map is ready when offerings succeed) and bounded, the completion always fires even on failure. Stale cached reads don't wait, they deliver immediately and refresh the list in the background.

Note

Medium Risk
When the launch-arg gate is enabled, fresh offerings completion waits on workflows list fetch/prefetch (bounded by always calling completion on failure); identity and offerings coordination are user-scoped but affect paywall timing.

Overview
Wires the paywall workflows pipeline into offerings and identity, behind SystemInfo.workflowsEndpointEnabled (-EnableWorkflowsEndpoint). When the gate is off, behavior is unchanged.

With the gate on, OfferingsManager optionally waits on WorkflowManager.getWorkflowsList (and prefetches) before delivering offerings on fresh in-memory, network, and disk-fallback paths, so workflowId(forOfferingId:) is ready when getOfferings succeeds. Stale in-memory offerings still return immediately; background refresh forceWorkflowsListCacheStale() and refetches the list. IdentityManager clears WorkflowsCache on login, logout, and user switch.

Adds WorkflowsCache.forceWorkflowsListCacheStale(), test mocks, and reorders configure() so WorkflowManager can be injected into offerings (no intended behavior change there).

Reviewed by Cursor Bugbot for commit 204fb5b. Bugbot is set up for automated code reviews on this repo. Configure here.

@facumenzella facumenzella added the pr:feat A new feature label Jun 2, 2026
@emerge-tools

emerge-tools Bot commented Jun 2, 2026

Copy link
Copy Markdown

4 builds increased size

Name Version Download Change Install Change Approval
RevenueCat
com.revenuecat.PaywallsTester
1.0 (1) 18.5 MB ⬆️ 1.4 kB 66.9 MB ⬆️ 18.5 kB (0.03%) N/A
BinarySizeTest
com.revenuecat.binary-size-test.local-source
1.0 (1) 4.3 MB ⬆️ 8.0 kB (0.19%) 12.8 MB ⬆️ 18.5 kB (0.15%) N/A
BinarySizeTest
com.revenuecat.binary-size-test.cocoapods
1.0 (1) 6.4 MB ⬆️ 9.2 kB (0.14%) 28.3 MB ⬆️ 35.0 kB (0.12%) ⏳ Needs approval
BinarySizeTest
com.revenuecat.binary-size-test.spm
1.0 (1) 4.4 MB ⬆️ 9.3 kB (0.21%) 11.1 MB ⬆️ 18.4 kB (0.17%) N/A

RevenueCat 1.0 (1)
com.revenuecat.PaywallsTester

⚖️ Compare build
⏱️ Analyze build performance

Total install size change: ⬆️ 18.5 kB (0.03%)
Total download size change: ⬆️ 1.4 kB

Largest size changes

Item Install Size Change
DYLD.String Table ⬆️ 6.7 kB
RevenueCat.WorkflowManager.WorkflowManager ⬆️ 1.6 kB
RCPaywallViewController.Objc Metadata ⬇️ -952 B
📝 RCPaywallViewController.viewDidDisappear: ⬆️ 952 B
📝 RCCustomerCenterViewController.viewDidDisappear: ⬆️ 832 B
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.local-source

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 18.5 kB (0.15%)
Total download size change: ⬆️ 8.0 kB (0.19%)

Largest size changes

Item Install Size Change
📝 RevenueCat.WorkflowManager.prefetchWorkflows(appUserID,isAppBackg... ⬆️ 2.7 kB
📝 RevenueCat.IdentityManager.init(deviceCache,systemInfo,backend,cu... ⬆️ 2.4 kB
🗑 RevenueCat.IdentityManager.init(deviceCache,systemInfo,backend,cu... ⬇️ -2.3 kB
📝 RevenueCat.WorkflowsCache.clearCache ⬆️ 800 B
📝 RevenueCat.WorkflowsCache.offeringIdToWorkflowId(from) ⬆️ 688 B
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.cocoapods

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 35.0 kB (0.12%)
Total download size change: ⬆️ 9.2 kB (0.14%)

Largest size changes

Item Install Size Change
DYLD.String Table ⬆️ 9.9 kB
📝 RevenueCat.WorkflowManager.prefetchWorkflows(appUserID,isAppBackg... ⬆️ 2.7 kB
📝 RevenueCat.IdentityManager.init(deviceCache,systemInfo,backend,cu... ⬆️ 2.4 kB
🗑 RevenueCat.IdentityManager.init(deviceCache,systemInfo,backend,cu... ⬇️ -2.3 kB
📝 RevenueCat.WorkflowsCache.offeringIdToWorkflowId(from) ⬆️ 936 B
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.spm

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 18.4 kB (0.17%)
Total download size change: ⬆️ 9.3 kB (0.21%)

Largest size changes

Item Install Size Change
📝 RevenueCat.WorkflowManager.prefetchWorkflows(appUserID,isAppBackg... ⬆️ 2.7 kB
📝 RevenueCat.IdentityManager.init(deviceCache,systemInfo,backend,cu... ⬆️ 2.4 kB
🗑 RevenueCat.IdentityManager.init(deviceCache,systemInfo,backend,cu... ⬇️ -2.3 kB
📝 RevenueCat.WorkflowsCache.clearCache ⬆️ 800 B
📝 RevenueCat.WorkflowsCache.offeringIdToWorkflowId(from) ⬆️ 688 B
View Treemap

Image of diff


🛸 Powered by Emerge Tools

@facumenzella facumenzella force-pushed the port/3508-workflows-manager-pr2 branch from bfae745 to e5d1332 Compare June 2, 2026 10:00
@facumenzella facumenzella force-pushed the port/3508-workflows-lifecycle-pr3 branch from 1a1ec09 to 4b77cec Compare June 2, 2026 10:00
@facumenzella facumenzella force-pushed the port/3508-workflows-manager-pr2 branch from e5d1332 to 08dcac9 Compare June 2, 2026 10:11
@facumenzella facumenzella force-pushed the port/3508-workflows-lifecycle-pr3 branch from 4b77cec to f72350d Compare June 2, 2026 10:11
@facumenzella facumenzella force-pushed the port/3508-workflows-lifecycle-pr3 branch from f72350d to 56aa749 Compare June 2, 2026 15:49
@facumenzella facumenzella force-pushed the port/3508-workflows-manager-pr2 branch 2 times, most recently from ee563d5 to 1f1480e Compare June 2, 2026 16:20
@facumenzella facumenzella force-pushed the port/3508-workflows-lifecycle-pr3 branch from 56aa749 to 8dea00c Compare June 2, 2026 21:02
Base automatically changed from port/3508-workflows-manager-pr2 to main June 3, 2026 10:54
@facumenzella facumenzella force-pushed the port/3508-workflows-lifecycle-pr3 branch from 8dea00c to 5a4a1bb Compare June 3, 2026 11:03
@facumenzella facumenzella marked this pull request as ready for review June 3, 2026 11:03
@facumenzella facumenzella requested a review from a team as a code owner June 3, 2026 11:03
Comment thread Sources/Identity/IdentityManager.swift

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5a4a1bb. Configure here.

Comment thread Sources/Purchasing/OfferingsManager.swift Outdated
@facumenzella facumenzella force-pushed the port/3508-workflows-lifecycle-pr3 branch from 5a4a1bb to 1dcfd49 Compare June 3, 2026 11:18
@facumenzella facumenzella requested a review from vegaro June 3, 2026 11:26
Comment thread Sources/Purchasing/OfferingsManager.swift
@facumenzella facumenzella force-pushed the port/3508-workflows-lifecycle-pr3 branch from 1dcfd49 to ebeaacb Compare June 3, 2026 13:36
@facumenzella facumenzella requested a review from vegaro June 3, 2026 14:24

@vegaro vegaro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I have a question on a particular case

Comment thread Sources/Purchasing/OfferingsManager.swift
…identity changes

Third of three stacked PRs porting purchases-android#3508 to iOS. Wires the
workflows pipeline into the offerings + identity lifecycle, behind a gate.

- `OfferingsManager` takes an optional `WorkflowManager`. After offerings are
  fetched from the network and cached, it fetches the workflows list (and
  prefetches its workflows) before delivering offerings, so
  `workflowId(forOfferingId:)` is resolvable as soon as offerings succeed.
  `getWorkflowsList` always calls its completion (even on error), so offerings
  delivery can never hang. When the manager is nil the offerings path is unchanged.
- `IdentityManager` clears the `WorkflowsCache` on login/alias, logout and user
  switch, alongside the offerings cache, so a user switch never serves the
  previous user's workflows.
- Gating: `SystemInfo.workflowsEndpointEnabled` (driven by the
  `-EnableWorkflowsEndpoint` launch argument). `configure()` passes the
  `WorkflowManager` to `OfferingsManager` only when enabled, so the endpoint is
  off by default and offerings timing is untouched in production.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@facumenzella facumenzella force-pushed the port/3508-workflows-lifecycle-pr3 branch from ebeaacb to dec076c Compare June 4, 2026 07:17
@facumenzella facumenzella enabled auto-merge (squash) June 4, 2026 07:21
@facumenzella facumenzella merged commit 1917097 into main Jun 4, 2026
17 of 20 checks passed
@facumenzella facumenzella deleted the port/3508-workflows-lifecycle-pr3 branch June 4, 2026 07:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:feat A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants