Conversation
The precomputed API returns all variation values as base64-encoded strings, regardless of type. Previously, only STRING and JSON types were decoded, causing BOOLEAN, INTEGER, and NUMERIC flags to always return defaultValue. - Extend decodeFlag to base64-decode and parse all variation types - Fix test helper to properly encode all types in wire format - Add tests for boolean, integer, and numeric flag assignments
Add custom decoder to default extraLogging to empty dictionary when the field is absent in the API response.
leoromanovsky
approved these changes
Mar 12, 2026
Comment on lines
-238
to
261
| if flag.variationType == .string || flag.variationType == .json { | ||
| do { | ||
| let encodedString = try flag.variationValue.getStringValue() | ||
| let decodedString = try base64DecodeOrThrow(encodedString) | ||
| do { | ||
| let encodedString = try flag.variationValue.getStringValue() | ||
| let decodedString = try base64DecodeOrThrow(encodedString) | ||
|
|
||
| switch flag.variationType { | ||
| case .string, .json: | ||
| decodedVariationValue = EppoValue(value: decodedString) | ||
| } catch { | ||
| print("Warning: Failed to decode variationValue, skipping flag - error: \(error.localizedDescription)") | ||
| return nil | ||
| case .boolean: | ||
| guard let boolValue = Bool(decodedString.lowercased()) else { | ||
| print("Warning: Failed to parse boolean value '\(decodedString)', skipping flag") | ||
| return nil | ||
| } | ||
| decodedVariationValue = EppoValue(value: boolValue) | ||
| case .integer, .numeric: | ||
| guard let doubleValue = Double(decodedString) else { | ||
| print("Warning: Failed to parse numeric value '\(decodedString)', skipping flag") | ||
| return nil | ||
| } | ||
| decodedVariationValue = EppoValue(value: doubleValue) | ||
| } | ||
| } else { | ||
| decodedVariationValue = flag.variationValue | ||
| } catch { | ||
| print("Warning: Failed to decode variationValue, skipping flag - error: \(error.localizedDescription)") | ||
| return nil | ||
| } |
Member
There was a problem hiding this comment.
Does this already exist for local-evaluation decoding?
Extract duplicate variation value decoding logic into a shared function in Obfuscation.swift. This is used by both local evaluation (FlagEvaluation) and precomputed flags (PrecomputedConfiguration). The shared function uses case-insensitive boolean comparison, aligning with Android SDK behavior. This is an edge case since the server always sends lowercase "true"/"false" values.
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.
🎟️ Fixes FFL-1916
📜 Design Doc: N/A
Motivation and Context
When using
EppoPrecomputedClient, all flags of type BOOLEAN, INTEGER, and NUMERIC always return thedefaultValueinstead of the actual assigned value.The precomputed API endpoint returns all variation values as base64-encoded strings, regardless of type. For example:
truearrives as"dHJ1ZQ=="(base64 of "true")42arrives as"NDI="(base64 of "42")3.14arrives as"My4xNA=="(base64 of "3.14")However, the
decodeFlagmethod inPrecomputedConfiguration.swiftonly applied base64 decoding for.stringand.jsonvariation types. For other types, the raw base64-encoded string was used as-is, causing type conversion to fail silently and return the default value.Description
Extended
decodeFlagto handle all variation types:Bool(decodedString.lowercased())Double(decodedString)Fixed test helper to properly encode all types:
createTestFlaginPrecomputedTestHelpers.swiftto base64-encode boolean, integer, and numeric values (matching the actual wire format)Added custom decoder for
PrecomputedFlag:extraLoggingfield gracefully (defaults to empty dictionary)How has this been documented?
No documentation changes required - this is a bug fix that makes the SDK behave as expected.
How has this been tested?
PrecomputedConfigurationWireTests.swift:testBooleanFlagAssignmentWithBase64EncodedValuetestIntegerFlagAssignmentWithBase64EncodedValuetestNumericFlagAssignmentWithBase64EncodedValuetestAllFlagTypesWithBase64EncodedValuesdart-test-flag-<type>flags with defaults ("DEFAULT",false,-1,-1.0, and{}) and observed that the precomputed client returned values configured for the flags instead