Repository navigation
chore!: pass the load result to the feature flags callback - #877
turnipdabeets wants to merge 2 commits into
Conversation
PostHogConfig.onFeatureFlags and reloadFeatureFlags() now take a PostHogFeatureFlagsCallback, whose loaded() receives a PostHogFeatureFlagsLoaded with the enabled flags, their values, and errorsLoading, matching posthog-ios 4.0. Every path that invoked the callback passes an accurate result, including failures, a disabled SDK, and bootstrap. PostHogOnFeatureFlags moves to posthog-server under the same name, so the server's API is unchanged and it can drop the type in its own major.
There was a problem hiding this comment.
PostHog Review · Standard · reviewed 90beca5: 2 Should fix.
See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.
| onFeatureFlags?.runSafely() | ||
| internalOnFeatureFlags?.let { runSafely(it) } | ||
| onFeatureFlags?.let { callback -> | ||
| runSafely { callback.loaded(PostHogFeatureFlagsLoaded(getFeatureFlags() ?: emptyMap(), errorsLoading)) } |
There was a problem hiding this comment.
P2 · Hydrate cached flags before constructing the callback result
On a fresh SDK instance with persisted flags, an offline or failed first load returns empty variants: getFeatureFlags() only copies the in-memory field, while getFeatureFlagResult() hydrates the cache lazily. The new completion therefore omits the promised last known flags until a getter runs; hydrate the cache before constructing the result.
| if (remoteConfig?.hasBootstrapFlags() == true) { | ||
| notifyFeatureFlagsCallback(internalOnFeatureFlagsLoaded) | ||
| notifyFeatureFlagsCallback(config.onFeatureFlags) | ||
| internalOnFeatureFlagsLoaded() |
There was a problem hiding this comment.
P2 · Restore exception isolation for the bootstrap internal callback
With bootstrap flags and session replay enabled, an exception from the replay handler now escapes internalOnFeatureFlagsLoaded() into setup's outer catch. This skips the user callback, initial config/flags request, and bootstrap identity reconciliation, leaving setup incomplete. The previous helper isolated this failure; catch and log the internal callback exception before continuing.
posthog-server calls its own PostHogOnFeatureFlags directly, and the core stateless client never calls config.onFeatureFlags. Bump posthog-server to minor since it now depends on core 7.0, and document that a bootstrapped onFeatureFlags runs on the setup() thread.
Note
Stacked on the 4.0 integration PR #871. Merges into
chore/v4-remove-deprecated, notmain.💡 Motivation and Context
Brings the Android flags callback to parity with posthog-ios 4.0 (
PostHogFeatureFlagsLoaded) and Flutter 6.PostHogConfig.onFeatureFlagsandreloadFeatureFlags()now take a newPostHogFeatureFlagsCallback. Itsloaded()receives aPostHogFeatureFlagsLoadedwith:flags: the keys of the enabled flagsvariants: their values (trueor the variant string)errorsLoading: whether the latest load failed (the values are then the last known ones)Every path that invoked the old callback now passes an accurate result, including failed requests, a disabled SDK, and bootstrap.
Why a new type instead of changing
PostHogOnFeatureFlags: core's public types are also part ofposthog-server's API. ChangingPostHogOnFeatureFlags.loaded()would force a server major for a callback the server can only fill with empty data (it evaluates flags per call). So:PostHogOnFeatureFlagsmoves from core intoposthog-server, same package and shape, so server users' source and binaries keep working. Android no longer sees it.posthog-servergets a minor bump, since it now depends on core 7.0.The other core types the server exposes (
FeatureFlagResult,PostHogBeforeSend,PostHogEncryption,PostHogIntegration) are unchanged.For reviewers: a blank
distinctIdreportserrorsLoading = true, since no request is made.💚 How did you test it?
./gradlew spotlessCheck apiCheck :posthog:test :posthog-server:test :posthog-android:testDebugUnitTestpass, and the Android sample compiles.PostHogRemoteConfigTestandPostHogBootstrapTestassert the result passed on success, failure, and bootstrap.asCoreConfigno longer setting the core callback.posthog-server.apionly gainsPostHogOnFeatureFlags(moved in, unchanged).📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Claude Code (Claude Opus 5.5) implemented the change after a cross-SDK flags API review (iOS, Android, Flutter, React Native). A first version changed
PostHogOnFeatureFlagsin place and bumped the server to a major; it was reworked to move the old type intoposthog-serverso the server stays untouched until its own major.🤖 Generated with Claude Code