docs(kmp,web): threading guidance and React-first configure samples - #270
Merged
Conversation
Per Ian's review: the which-hook-lands-on-which-thread split is an implementation detail, not a contract, and may change between releases. Documenting it as a table invites people to build on it. Replaced with the guarantee that actually holds: delegate callbacks are not guaranteed to arrive on any particular thread, so treat every one as potentially background, hop to main for UI, stay thread-safe, and keep them short. Applied consistently across the four pages that repeated the old split (platform-differences, using-superwall-delegate, 3rd-party-analytics, handling-deep-links) so the docs do not contradict themselves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Per Ian's review: most Web SDK users are on React, so the configure page should show React first, in tabbed code blocks alongside plain JavaScript, rather than making React readers translate from createSuperwall. Every step now has a React / JavaScript CodeGroup with React as the default tab: SuperwallProvider vs createSuperwall, use(sw.ready) vs await sw.ready, useSignal(sw.configurationStatus) vs .value, and provider props vs the options object. Verified against packages/paywalls-react/src: provider props are CreateSuperwallOptions 1:1, and useSuperwall / useSignal are the exported names. The React deep-dive (Suspense boundary, read-once config) stays on web/react/provider; the configure page links there instead of repeating it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The threading rewrite asserted "the KMP layer adds no dispatching of its own," which is only true on Android. On iOS every delegate callback goes through scope.launch on Dispatchers.Main.immediate (iosMain/.../DelegateAdapter.kt:43-51), so the callbacks are dispatched and serialized on main there. Two dependent claims fell with it: "not serialized against each other" and "slows the SDK, not the frame budget" were Android-only reasoning stated as universal. The guidance is unchanged (treat every callback as possibly background, hop for UI, stay thread-safe, keep it short); the text now stops asserting how that comes about. Both samples also referenced an undefined `scope`; they now show a delegate class that receives one. Web: typed the ConfigGuard prop so the tsx sample passes noImplicitAny. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
superwall-docs | 491c82d | Commit Preview URL Branch Preview URL |
Aug 18 2026, 07:27 PM |
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.
Two touch-ups from Ian's review of the KMP and Web SDK docs. Closes SW-5749.
KMP: drop the per-hook delegate threading table
Ian: "I'd just remove this table because tbh its not guaranteed and might be subject to change, I'd rather tell them its not guaranteed and to make sure they properly manage their threading here."
kmp/guides/platform-differences#delegate-threadingno longer lists whichSuperwallDelegatehooks land on main vs background per platform. It now says the guarantee that actually holds: callbacks are not guaranteed to arrive on any particular thread, so treat every one as potentially background, hop to main for UI, stay thread-safe, keep them short.Applied the same principle to the three other pages that repeated the old split so nothing contradicts:
using-superwall-delegate,3rd-party-analytics,handling-deep-links. Kept the one guarantee that does hold and is deliberate:PaywallPresentationHandlerclosures and theregisterfeatureclosure are main-thread on both platforms (verified:androidMain/.../PresentationHandlerAdapter.kt:138-149,iosMain/.../PresentationHandlerAdapter.kt:46-54).Web: React and JavaScript side by side on the configure page
Ian: "I'd also have toggle code blocks for react/js, esp since like 80% of ppl use it, so maybe we should make it prioritized."
Every sample on
web/quickstart/configureis now a React / JavaScriptCodeGroupwith React as the default tab. The React tabs use the real idioms rather than translating the JS:SuperwallProvidervscreateSuperwall,use(sw.ready)vsawait sw.ready,useSignal(sw.configurationStatus)vs.value, provider props vs the options object. Verified againstpackages/paywalls-react/src:SuperwallProviderProps extends CreateSuperwallOptions(provider.tsx:63), anduseSuperwall/useSignal/usePlacementare the exported names (index.ts:13-14). The React deep-dive stays onweb/react/provider; configure links there.The JS samples are byte-identical to what was on main; only the fence labels changed.
Claim audit
A clean-context reviewer audited the diff against all three repos at
origin/mainHEAD (Superwall-KMP8727bcf, Superwall-Webedaf79a, superwall-android2f32966). One real finding, fixed in2dc5ea6: my first pass at the threading rewrite claimed "the KMP layer adds no dispatching of its own," which is Android-only. On iOS every delegate callback goes throughscope.launchonDispatchers.Main.immediate(iosMain/.../DelegateAdapter.kt:43-51). The guidance was fine; the mechanism claim is now gone. Both code samples also referenced an undefinedscopeand now show a delegate that receives one.The web page came back clean: every React sample type-checks, all anchors resolve.
Verification
bun run build:cfexit 0,bun test64/0,git diff --checkcleancontent/docs/{kmp,web}For Ian
The SDK's shipping KDoc on
commonMain/.../SuperwallDelegate.kt(~lines 19-42) still documents the per-hook split this PR removes from the docs. Worth aligning so the IDE and the docs say the same thing.🤖 Generated with Claude Code