Skip to content

fix(purchases): fail open only for Pro when feature-access config fails - #2625

Closed
mikib0 wants to merge 2 commits into
feat/revenuecat-paywall-v2from
fix/fail-open-pro-only
Closed

fix(purchases): fail open only for Pro when feature-access config fails#2625
mikib0 wants to merge 2 commits into
feat/revenuecat-paywall-v2from
fix/fail-open-pro-only

Conversation

@mikib0

@mikib0 mikib0 commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Problem

Two related bugs in the early-access gate when the feature-access config can't be fetched:

  1. Fail-open too broad. A failed config query returned config = undefined; hasFeatureAccess(undefined, …) treats an absent feature as 'not in early access' → true, so any fetch failure handed paid early-access features to everyone for free.

  2. Infinite spinner offline. Neither the config nor customer-info query sets networkMode, so React Query's default 'online' mode parks a data-less query in fetchStatus: 'paused' when the device is offline. It never runs, never errors, and stays pending — so isLoading was true forever and EarlyAccessGate spun indefinitely with no connection.

Fix

  • Treat a pending-but-paused query as settled, not loading (isPending && fetchStatus !== 'paused'), so the gate stops spinning offline.
  • Treat a config query that is errored or paused as 'config unavailable' and fail open only for Pro members; non-Pro users are gated and see the paywall. A successfully loaded config that merely omits a feature is still the graduated/unconfigured case and fails open for everyone via hasFeatureAccess.
  • Surfaces isPending/fetchStatus through useEntitlement.

Files: useFeatureAccess.ts, useEntitlement.ts.

Notes

  • Offline + non-Pro now attempts the paywall; RevenueCat can't load offerings offline and returns PAYWALL_RESULT.ERROR, which the gate already handles with router.back(), so the user isn't trapped.
  • RevenueCat's SDK serves CustomerInfo from local cache offline, so the entitlement query generally resolves rather than pausing; the config (API) query is the one that pauses.
  • No unit test added: the expo test harness is pure-TS/Node only and can't render these RevenueCat/React Query hooks; the pure resolver in packages/config is unchanged.

Previously a failed feature-access config query returned undefined config,
which hasFeatureAccess treats as 'not in early access' -> allowed for
everyone, handing paid early-access features out for free on any fetch
failure. Now on config error we fail open only for Pro members; non-Pro
users are gated and see the paywall. A successfully-loaded config that
omits a feature is still the graduated/unconfigured case and fails open
for all.
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 984705ec-3cab-4bd5-b42f-3e1d08bf4fcf

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/fail-open-pro-only

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

Copy link
Copy Markdown
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
packrat-admin 6bffe7f Commit Preview URL

Branch Preview URL
Jul 15 2026, 11:12 AM

React Query's default networkMode 'online' parks a data-less query in
fetchStatus 'paused' while offline: it never runs, never errors, and
stays 'pending', so isLoading was true forever and EarlyAccessGate spun
indefinitely with no connection.

Treat a pending-but-paused query as settled (not loading), and treat a
paused config query the same as an errored one: fail open for Pro,
gate non-Pro. Surfaces isPending/fetchStatus through useEntitlement.
@mikib0
mikib0 force-pushed the feat/revenuecat-paywall-v2 branch from ea9cd68 to df7bfe2 Compare July 15, 2026 18:50
@mikib0 mikib0 closed this Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant