@@ -104,4 +104,140 @@ defmodule Posthog.FeatureFlag do
104
104
"""
105
105
@ spec boolean? ( t ( ) ) :: boolean ( )
106
106
def boolean? ( % __MODULE__ { enabled: value } ) , do: is_boolean ( value )
107
+
108
+ @ doc """
109
+ Processes a feature flag response from the PostHog API.
110
+ Handles both v3 and v4 API response formats.
111
+
112
+ ## Parameters
113
+
114
+ * `response` - The raw response from the API
115
+
116
+ ## Examples
117
+
118
+ # v4 API response
119
+ response = %{
120
+ "flags" => %{
121
+ "my-flag" => %{
122
+ "enabled" => true,
123
+ "variant" => nil,
124
+ "metadata" => %{"payload" => "{\" color\" : \" blue\" }"}
125
+ }
126
+ },
127
+ "requestId" => "123"
128
+ }
129
+ Posthog.FeatureFlag.process_response(response)
130
+ # Returns: %{
131
+ # flags: %{"my-flag" => %{"enabled" => true, "variant" => nil, "metadata" => %{"payload" => "{\" color\" : \" blue\" }"}}},
132
+ # feature_flags: %{"my-flag" => true},
133
+ # feature_flag_payloads: %{"my-flag" => %{"color" => "blue"}},
134
+ # request_id: "123"
135
+ # }
136
+
137
+ # v3 API response
138
+ response = %{
139
+ "featureFlags" => %{"my-flag" => true},
140
+ "featureFlagPayloads" => %{"my-flag" => "{\" color\" : \" blue\" }"},
141
+ "requestId" => "123"
142
+ }
143
+ Posthog.FeatureFlag.process_response(response)
144
+ # Returns: %{
145
+ # feature_flags: %{"my-flag" => true},
146
+ # feature_flag_payloads: %{"my-flag" => %{"color" => "blue"}},
147
+ # request_id: "123"
148
+ # }
149
+ """
150
+ @ spec process_response ( map ( ) ) :: % {
151
+ flags: map ( ) | nil ,
152
+ feature_flags: % { optional ( binary ( ) ) => variant ( ) } ,
153
+ feature_flag_payloads: % { optional ( binary ( ) ) => term ( ) } ,
154
+ request_id: binary ( ) | nil
155
+ }
156
+ def process_response ( % { "flags" => flags } = response ) do
157
+ feature_flags =
158
+ Map . new ( flags , fn { k , v } ->
159
+ { k , if ( v [ "variant" ] , do: v [ "variant" ] , else: v [ "enabled" ] ) }
160
+ end )
161
+
162
+ feature_flag_payloads =
163
+ Map . new ( flags , fn { k , v } ->
164
+ { k ,
165
+ if ( v [ "metadata" ] [ "payload" ] ,
166
+ do: decode_payload ( v [ "metadata" ] [ "payload" ] ) ,
167
+ else: nil
168
+ ) }
169
+ end )
170
+
171
+ % {
172
+ flags: flags ,
173
+ feature_flags: feature_flags ,
174
+ feature_flag_payloads: feature_flag_payloads ,
175
+ request_id: response [ "requestId" ]
176
+ }
177
+ end
178
+
179
+ def process_response ( response ) do
180
+ % {
181
+ flags: nil ,
182
+ feature_flags: Map . get ( response , "featureFlags" , % { } ) ,
183
+ feature_flag_payloads: decode_payloads ( Map . get ( response , "featureFlagPayloads" , % { } ) ) ,
184
+ request_id: response [ "requestId" ]
185
+ }
186
+ end
187
+
188
+ @ doc """
189
+ Decodes a map of feature flag payloads.
190
+
191
+ ## Parameters
192
+
193
+ * `payloads` - Map of feature flag names to their payload values
194
+
195
+ ## Examples
196
+
197
+ payloads = %{
198
+ "my-flag" => "{\" color\" : \" blue\" }",
199
+ "other-flag" => "plain-text"
200
+ }
201
+ Posthog.FeatureFlag.decode_payloads(payloads)
202
+ # Returns: %{
203
+ # "my-flag" => %{"color" => "blue"},
204
+ # "other-flag" => "plain-text"
205
+ # }
206
+ """
207
+ @ spec decode_payloads ( % { optional ( binary ( ) ) => term ( ) } ) :: % { optional ( binary ( ) ) => term ( ) }
208
+ def decode_payloads ( payloads ) do
209
+ Enum . reduce ( payloads , % { } , fn { k , v } , map ->
210
+ Map . put ( map , k , decode_payload ( v ) )
211
+ end )
212
+ end
213
+
214
+ @ doc """
215
+ Decodes a feature flag payload from JSON string to Elixir term.
216
+ Returns the original payload if it's not a valid JSON string.
217
+
218
+ ## Examples
219
+
220
+ # JSON string payload
221
+ Posthog.FeatureFlag.decode_payload("{\" color\" : \" blue\" }")
222
+ # Returns: %{"color" => "blue"}
223
+
224
+ # Non-JSON string payload
225
+ Posthog.FeatureFlag.decode_payload("plain-text")
226
+ # Returns: "plain-text"
227
+
228
+ # Nil payload
229
+ Posthog.FeatureFlag.decode_payload(nil)
230
+ # Returns: nil
231
+ """
232
+ @ spec decode_payload ( term ( ) ) :: term ( )
233
+ def decode_payload ( nil ) , do: nil
234
+
235
+ def decode_payload ( payload ) when is_binary ( payload ) do
236
+ case Posthog.Config . json_library ( ) . decode ( payload ) do
237
+ { :ok , decoded } -> decoded
238
+ { :error , _ } -> payload
239
+ end
240
+ end
241
+
242
+ def decode_payload ( payload ) , do: payload
107
243
end
0 commit comments