Conversation
And renamed `getAllActiveTreatmentPaywallIds` to `getActiveTreatmentPaywallIds`, and removed the old `getActiveTreatmentPaywallIds`. This means that when someone calls `preloadPaywalls(forPlacements:)`
Add CodingKeys for snake_case decoding since Web2App decoder doesn't auto-convert from snake case. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Maps V2Product API response data into a StoreProductType for use as a test store product backed by the Superwall API. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TestModeManager for detecting test mode users via config - Add TestStoreUser model parsed from config testStoreUsers - Add TestModeColdLaunchAlert for showing test mode status on launch - Add TestModePurchaseDrawer for simulating purchases (purchase/abandon/fail) - Add TestModeTransactionHandler to intercept purchase and restore flows - Override StoreKitManager.getProducts to use cached test products - Override TransactionManager.purchase to show test mode drawer - Override TransactionManager.tryToRestore to show entitlement picker - Override DeviceHelper.isSandbox to return true in test mode - Rename V2Product to SuperwallProduct across codebase - Fetch products from /v1/products endpoint on config load when test mode Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…tsById Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add bundleId to config endpoint application query - Include bundle_id_config in config JSON response - Decode bundleIdConfig in Swift Config model - Check bundle ID mismatch in evaluateTestMode — activates test mode when app bundle ID doesn't match config Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… detection - Rename DebugModeBehavior -> TestModeBehavior, debugModeBehavior -> testModeBehavior - Rename SWKDebugModeBehavior -> SWKTestModeBehavior (ObjC) - Rename debugOption -> testModeOption - Rename isUITestEnvironment -> isTestEnvironment - Skip test mode in test environments unless SUPERWALL_UNIT_TESTS launch arg is set - Update tests to work correctly with the new environment detection Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use where clause instead of if inside for loop - Remove superfluous swiftlint disable commands - Remove extra blank line before closing brace Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add testModeBehavior option to SuperwallOptions
feat: Test Mode — test store products, purchase/restore overrides, dark mode UI
…om/superwall/Superwall-iOS into christo/new-stripe-redemption-flow
Replaces the preloading schedule model with a simple prioritizedCampaignId on the config. When set, the SDK preloads the prioritized campaign's paywalls first (with a 5s delay), then preloads the rest. - Remove PaywallPreloading, PreloadingStep, PreloadablePlacement models - Add prioritizedCampaignId to Config - Update ConfigManager.preloadAllPaywalls() to use prioritized campaign - Update tests for new approach Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Now if we're in an extension, we won't start test mode
…flow feat: add new app2web polling flow
When switching API keys, the cached config from the old key persists and can cause incorrect test mode activation due to bundleIdConfig mismatch. Store the last-used API key and clear config, enrichment, and test mode caches when it changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Feature/preloading schedule
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes in this pull request
Enhancements
stripe_checkout_start,stripe_checkout_submit,stripe_checkout_complete,stripe_checkout_fail, andstripe_checkout_abandon.start,submit,complete,fail) withstoreandproduct_identifierpayload fields.Fixes
Checklist
CHANGELOG.mdfor any breaking changes, enhancements, or bug fixes.swiftlintin the main directory and fixed any issues.Greptile Summary
This release adds two major features: Test Mode for simulating in-app purchases without StoreKit, and Stripe checkout lifecycle tracking with automatic recovery polling.
Major changes:
hasActiveStripePollflag to prevent race conditionsWebEntitlementRedeemerTests.swift, 323 lines inTestModeManagerTests.swift)Key implementation notes:
unownedreferences appropriately to avoid retain cycles while maintaining safe access patternsConstants.swift,SuperwallKit.podspec, andCHANGELOG.mdConfidence Score: 5/5
Important Files Changed
Sequence Diagram
sequenceDiagram participant User participant Paywall participant MessageHandler participant WebEntitlementRedeemer participant StripeAPI User->>Paywall: Click Stripe checkout Paywall->>MessageHandler: stripe_checkout_start MessageHandler->>MessageHandler: Track start event User->>Paywall: Submit payment Paywall->>MessageHandler: stripe_checkout_submit MessageHandler->>WebEntitlementRedeemer: registerStripeCheckoutSubmit(contextId, productId) WebEntitlementRedeemer->>WebEntitlementRedeemer: Save pending state MessageHandler->>MessageHandler: Track submit event alt Checkout succeeds Paywall->>MessageHandler: stripe_checkout_complete MessageHandler->>WebEntitlementRedeemer: handleStripeCheckoutComplete(contextId, productId) MessageHandler->>MessageHandler: Track complete event WebEntitlementRedeemer->>WebEntitlementRedeemer: Set hasActiveStripePoll = true loop Poll until success/timeout WebEntitlementRedeemer->>StripeAPI: Poll redemption result alt Result ready StripeAPI-->>WebEntitlementRedeemer: Redemption code WebEntitlementRedeemer->>WebEntitlementRedeemer: Handle redemption success WebEntitlementRedeemer->>WebEntitlementRedeemer: Clear pending state else Still pending StripeAPI-->>WebEntitlementRedeemer: Status: pending WebEntitlementRedeemer->>WebEntitlementRedeemer: Sleep 1.5s, continue end end WebEntitlementRedeemer->>WebEntitlementRedeemer: Set hasActiveStripePoll = false WebEntitlementRedeemer->>Paywall: Update loading state else Checkout abandoned Paywall->>MessageHandler: stripe_checkout_abandon MessageHandler->>WebEntitlementRedeemer: handleStripeCheckoutAbandon(productId) WebEntitlementRedeemer->>WebEntitlementRedeemer: Track abandon event WebEntitlementRedeemer->>WebEntitlementRedeemer: Clear awaitingCheckoutComplete else Checkout fails Paywall->>MessageHandler: stripe_checkout_fail MessageHandler->>MessageHandler: Track fail event end alt App backgrounded then foregrounded User->>Paywall: Return to app WebEntitlementRedeemer->>WebEntitlementRedeemer: pollPendingStripeCheckoutOnForeground WebEntitlementRedeemer->>WebEntitlementRedeemer: Decrement foreground attempts WebEntitlementRedeemer->>StripeAPI: Poll for pending checkout end alt Paywall reopened with pending checkout User->>Paywall: Open paywall Paywall->>WebEntitlementRedeemer: pollOrWaitForActiveStripePoll() alt Poll already in-flight WebEntitlementRedeemer->>WebEntitlementRedeemer: Wait for existing poll (100ms checks) else No active poll WebEntitlementRedeemer->>StripeAPI: Start new poll end endLast reviewed commit: 7ab22d3
Context used:
dashboard- CLAUDE.md (source)