Repository navigation
fix(browser): run tracking hooks in finally - #406
Conversation
OpenFeature Browser Entrypoint Bundle SizesMeasured from the Vite production output after installing packed
Default and precomputed entrypoints are expected to keep Protobuf-ES out of their bundles. Rules-based entrypoints are expected to include protobuf markers as a positive control. The marker check is a packed-artifact backstop; the source import boundary is enforced by OpenFeature Browser Tracking Hook Bundle SizesSynthetic entrypoints import and call tracking hook factories from the packed
This report shows current PR artifact sizes only; it does not compare against the base branch. |
addeb3a to
2ee684d
Compare
37a235f to
163b1af
Compare
Motivation
The browser tracking hooks run in OpenFeature's
afterstage. OpenFeature skips that stage when evaluation fails, so calls that return the application's fallback (for example,FLAG_NOT_FOUNDorTYPE_MISMATCH) are missing from evaluation events.Tracking in
aftercan also record an assignment that a laterafterhook rejects. A tracking callback that throws can turn a successful evaluation into a fallback. Running tracking infinallylets it observe the final result and keeps tracking failures from changing that result.Identified while reviewing the React Native hooks implementation.
Changes
finally, which receives the final details returned to the application, for bothDatadogProviderand manually registered hooks onDatadogCoreProvider.finallythrough the tracking lifecycle controller and the online provider's effective-context wrapper. Initialization, shutdown, and RUM-enriched context behavior stay intact.error.messagewith the OpenFeature error code only. Do not upload free-form provider or hook error messages, which can contain application data.afterhook. A throwing RUM callback no longer changes the flag result or prevents otherfinallyhooks from running.Server SDK comparison
Checked the server evaluation-event implementations directly. All use the terminal hook stage to include successful and failed evaluations:
Finallyfinally_afterfinallyAfterfinallyfinallyError text is not uniform across these implementations. Python and Ruby use error codes, and Node.js captures the error code rather than the raw message. Java allows raw messages only with full-data consent and otherwise uses the code. This PR uses code-only errors for the browser; unlike the linked RN fix, it does not prefer
errorMessage.This does not mean every server tracking hook uses
finally: the Go exposure hook usesAfter. Moving all browser tracking tofinallyis a deliberate choice to observe the final result and isolate tracking errors, consistent with the OpenFeature hook lifecycle.This change aligns evaluation coverage with the server hooks. It does not adopt their separate consent, buffering, or delivery implementations.
Test instructions
Run the browser suite:
Local results: 23 suites passed; the full run had 353 passing tests and three failures in the unchanged
fetchRetry.spec.ts, with stack overflows in thesource-mapdependency. All 46 fetch-retry tests passed when that suite was run separately. All tracking tests passed.The regression tests use real OpenFeature clients with mocked HTTP transport for both providers. They cover missing flags, type mismatches, throwing
beforeandafterhooks, successful counts, mixed success/error aggregation, error-message exclusion, RUM-enriched context, and shutdown/reinitialization. They also verify that discarded assignments do not fill the exposure cache and that a throwing RUM callback preserves the result and other tracking. The regression cases failed before the corresponding fixes.Direct hook tests verify that exposure and RUM tracking skip error results even when a variant is present, and skip results without a variant.
Also passed browser source type checking, test type checking with
--rootDir .(the test suite imports core source files), changed-file Biome and Prettier checks, andgit diff --check.Checklist