posthog-ruby 3.19.0 → 3.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b23e0da0723e7582825d0888d8c6ffd9b3ad0a77e5eec513a40ab3de1faaa306
4
- data.tar.gz: 1fc203c912147dc865cb342213ef8ccd3604e4d84f0b0005932c559aa30c8017
3
+ metadata.gz: 4ae3a78450df91e2e4cb88cd69a58e167cdb291dcc02f8ab446e3b0975c270eb
4
+ data.tar.gz: b912b023ed02a37004cfbe22511437ee4df2a5ec63799d6d47e6f6aa9fc4f164
5
5
  SHA512:
6
- metadata.gz: 8409ba6d5fb0801643cbd6556a1dabf41441ff522b85d612601ac8547482c5eb139ac68f21250f2f240654f08c03b3ca6cdc0409f57f1c6af9cdd880c677805f
7
- data.tar.gz: c7a146c293985480777e6f5139588ca0d897170b8fe15412e9d60561711cb57bec53e70225b8b209916a50835f249b9816bece364be754a56e6f1118454feb52
6
+ metadata.gz: 42b8b2587ee825e9a5446def45d11940b52a3a2203828b4506b2a4e1c28e2deefd61406df6ab33800bf1055c1475130554d6edef55a1498b478c43a30591f7b0
7
+ data.tar.gz: 4eec6bdd11abbeee85720d2a68872ad366f39b5c9c28ce72fd96aaf54f3098218578ccac954e35fe01099975d6f5a2afcfe5016b4460520a6341e465f026ed99
@@ -22,6 +22,31 @@ module PostHog
22
22
  include PostHog::Utils
23
23
  include PostHog::Logging
24
24
 
25
+ # Strict allowlist of properties kept on minimal `$feature_flag_called`
26
+ # events (server-gated, non-experiment flags only). Everything else —
27
+ # context properties, `$feature/<key>`, payloads, system metadata — is
28
+ # stripped. Includes symbol forms so allowlisted properties supplied
29
+ # through context with symbol keys survive.
30
+ MINIMAL_FLAG_CALLED_EVENT_PROPERTIES = %w[
31
+ $feature_flag
32
+ $feature_flag_response
33
+ $feature_flag_has_experiment
34
+ $feature_flag_id
35
+ $feature_flag_version
36
+ $feature_flag_reason
37
+ $feature_flag_request_id
38
+ $feature_flag_evaluated_at
39
+ $feature_flag_error
40
+ locally_evaluated
41
+ $groups
42
+ $process_person_profile
43
+ $session_id
44
+ $is_server
45
+ $lib
46
+ $lib_version
47
+ ].flat_map { |key| [key, key.to_sym] }.freeze
48
+ private_constant :MINIMAL_FLAG_CALLED_EVENT_PROPERTIES
49
+
25
50
  # Thread-safe tracking of client instances per API key for singleton warnings
26
51
  @instances_by_api_key = {}
27
52
  @instances_mutex = Mutex.new
@@ -76,6 +101,13 @@ module PostHog
76
101
  # @option opts [Integer] :feature_flag_request_max_retries How many times to retry a flag request after a
77
102
  # transient network error. Each retry sleeps on the calling thread before retrying, so this adds to
78
103
  # worst-case latency. Defaults to 1. Set to 0 to disable retrying.
104
+ # @option opts [Boolean] :feature_flags_async_load +true+ to fetch feature flag definitions for local
105
+ # evaluation only on the poller's background thread instead of the calling thread. The constructor
106
+ # returns without waiting for definitions: the poller fetches immediately on boot and, if that fails,
107
+ # keeps retrying on its regular polling interval until a load succeeds. Until then local evaluation
108
+ # treats definitions as absent (check {#feature_flags_loaded?}), so evaluations return nil with
109
+ # +only_evaluate_locally: true+, or fall back to the remote flags endpoint (which still runs on the
110
+ # calling thread) without it. Defaults to +false+.
79
111
  # @option opts [Proc] :before_send A callback that receives the event hash and should return either a modified
80
112
  # hash to be sent to PostHog or nil to prevent the event from being sent. e.g. `before_send: ->(event) { event }`.
81
113
  # @option opts [Boolean] :disable_singleton_warning +true+ to suppress the warning when multiple clients share
@@ -162,7 +194,8 @@ module PostHog
162
194
  opts[:feature_flag_request_timeout_seconds] || Defaults::FeatureFlags::FLAG_REQUEST_TIMEOUT_SECONDS,
163
195
  opts[:on_error],
164
196
  flag_definition_cache_provider: opts[:flag_definition_cache_provider],
165
- feature_flag_request_max_retries: opts[:feature_flag_request_max_retries]
197
+ feature_flag_request_max_retries: opts[:feature_flag_request_max_retries],
198
+ async_load: opts[:feature_flags_async_load] == true
166
199
  )
167
200
  end
168
201
 
@@ -245,6 +278,7 @@ module PostHog
245
278
  return false if @disabled
246
279
 
247
280
  symbolize_keys! attrs
281
+ minimal_flag_called_event = attrs.delete(:_minimal_flag_called_event) == true
248
282
  enrich_capture_attrs_with_context(attrs)
249
283
 
250
284
  # Precedence: an explicit `flags` snapshot always wins, regardless of
@@ -313,7 +347,13 @@ module PostHog
313
347
  end
314
348
 
315
349
  attrs[:is_server] = @is_server
316
- enqueue(FieldParser.parse_for_capture(attrs))
350
+ message = FieldParser.parse_for_capture(attrs)
351
+ # Minimal events are built from the allowlist after full assembly so
352
+ # context properties and parser-added metadata can never leak in.
353
+ if minimal_flag_called_event
354
+ message[:properties] = message[:properties].slice(*MINIMAL_FLAG_CALLED_EVENT_PROPERTIES)
355
+ end
356
+ enqueue(message)
317
357
  end
318
358
 
319
359
  # Captures an exception as an event
@@ -619,6 +659,11 @@ module PostHog
619
659
  evaluated_at = nil
620
660
  errors_while_computing = false
621
661
  quota_limited = false
662
+ # Server-controlled gate for minimal `$feature_flag_called` events. When
663
+ # the snapshot uses a remote /flags response, the response's top-level
664
+ # `minimalFlagCalledEvents` field governs; a local-only snapshot reads
665
+ # the gate polled with the flag definitions.
666
+ minimal_flag_called_events = @feature_flags_poller.minimal_flag_called_events
622
667
 
623
668
  # Skip the remote `/flags` round-trip when the caller scoped the request
624
669
  # to a fixed set of `flag_keys` and we've already resolved every one of
@@ -627,10 +672,16 @@ module PostHog
627
672
  all_requested_flags_resolved_locally = flag_keys_set && (flag_keys_set - locally_evaluated_keys).empty?
628
673
 
629
674
  if !only_evaluate_locally && !all_requested_flags_resolved_locally
675
+ # The gate is team-level, so the /flags response gate supersedes the
676
+ # poller gate for mixed snapshots — both signals come from the same
677
+ # server and agree in steady state. When the response omits the gate,
678
+ # the whole snapshot fails safe to full events.
679
+ minimal_flag_called_events = false
630
680
  begin
631
681
  flags_response = @feature_flags_poller.get_flags(
632
682
  distinct_id, groups, person_properties, group_properties, flag_keys, disable_geoip
633
683
  )
684
+ minimal_flag_called_events = flags_response[:minimalFlagCalledEvents] == true
634
685
  request_id = flags_response[:requestId]
635
686
  evaluated_at = flags_response[:evaluatedAt]
636
687
  errors_while_computing = flags_response[:errorsWhileComputingFlags] == true
@@ -669,7 +720,8 @@ module PostHog
669
720
  evaluated_at: evaluated_at,
670
721
  flag_definitions_loaded_at: @feature_flags_poller.flag_definitions_loaded_at,
671
722
  errors_while_computing: errors_while_computing,
672
- quota_limited: quota_limited
723
+ quota_limited: quota_limited,
724
+ minimal_flag_called_events: minimal_flag_called_events
673
725
  )
674
726
  end
675
727
 
@@ -769,10 +821,12 @@ module PostHog
769
821
  response.delete(:requestId)
770
822
  response.delete(:evaluatedAt)
771
823
  response.delete(:flagDetails)
824
+ response.delete(:minimalFlagCalledEvents)
772
825
  response
773
826
  end
774
827
 
775
- # Reload locally cached feature flag definitions.
828
+ # Reload locally cached feature flag definitions synchronously on the
829
+ # calling thread.
776
830
  #
777
831
  # @return [void]
778
832
  def reload_feature_flags
@@ -787,6 +841,17 @@ module PostHog
787
841
  @feature_flags_poller.load_feature_flags(true)
788
842
  end
789
843
 
844
+ # Whether feature flag definitions for local evaluation are currently loaded.
845
+ # False until the first successful load, and false again if a quota-limited
846
+ # (402) response discards the definitions.
847
+ #
848
+ # @return [Boolean]
849
+ def feature_flags_loaded?
850
+ return false if @disabled
851
+
852
+ @feature_flags_poller.definitions_loaded?
853
+ end
854
+
790
855
  # Whether the client will actually send events. It is disabled when the
791
856
  # api_key is missing or blank, in which case every capture call no-ops.
792
857
  #
@@ -865,7 +930,7 @@ module PostHog
865
930
  # separate event for each group a user is evaluated under.
866
931
  def _capture_feature_flag_called_if_needed(
867
932
  distinct_id: nil, key: nil, response: nil, properties: nil,
868
- groups: nil, disable_geoip: nil
933
+ groups: nil, disable_geoip: nil, minimal: false
869
934
  )
870
935
  response_repr = response.nil? ? '::null::' : response
871
936
  groups_repr =
@@ -895,6 +960,7 @@ module PostHog
895
960
  }
896
961
  msg[:groups] = groups if groups
897
962
  msg[:disable_geoip] = disable_geoip unless disable_geoip.nil?
963
+ msg[:_minimal_flag_called_event] = true if minimal
898
964
 
899
965
  capture(msg)
900
966
  end
@@ -925,7 +991,7 @@ module PostHog
925
991
  groups, person_properties, group_properties
926
992
  )
927
993
  feature_flag_response, flag_was_locally_evaluated, request_id, evaluated_at, feature_flag_error, payload,
928
- has_experiment =
994
+ has_experiment, minimal_flag_called_events =
929
995
  @feature_flags_poller.get_feature_flag(
930
996
  key, distinct_id, groups, person_properties, group_properties, only_evaluate_locally
931
997
  )
@@ -940,9 +1006,13 @@ module PostHog
940
1006
  properties['$feature_flag_evaluated_at'] = evaluated_at if evaluated_at
941
1007
  properties['$feature_flag_error'] = feature_flag_error if feature_flag_error
942
1008
 
1009
+ # Emit a minimal event only when the server gate is on and the flag is
1010
+ # known to have no linked experiment. Any missing signal fails safe to
1011
+ # the full event.
1012
+ minimal = minimal_flag_called_events == true && has_experiment == false
943
1013
  _capture_feature_flag_called_if_needed(
944
1014
  distinct_id: distinct_id, key: key, response: feature_flag_response,
945
- properties: properties, groups: groups
1015
+ properties: properties, groups: groups, minimal: minimal
946
1016
  )
947
1017
  end
948
1018
 
@@ -19,6 +19,7 @@ module PostHog
19
19
 
20
20
  module FeatureFlags
21
21
  FLAG_REQUEST_TIMEOUT_SECONDS = 3
22
+ POLLING_INTERVAL_SECONDS = 30
22
23
  # Number of retries for a flag request after a transient network error.
23
24
  # Flag requests are stateless and cause no server-side mutation, so
24
25
  # retrying is safe.
@@ -44,6 +44,8 @@ module PostHog
44
44
  # @param flag_definitions_loaded_at [Time, nil] When local flag definitions were loaded.
45
45
  # @param errors_while_computing [Boolean] Whether the server reported errors while computing flags.
46
46
  # @param quota_limited [Boolean] Whether feature flag evaluation was quota limited.
47
+ # @param minimal_flag_called_events [Boolean] Server-controlled gate for minimal
48
+ # `$feature_flag_called` events.
47
49
  # @param accessed [Array<String>, Set<String>, nil] Flag keys already accessed by this snapshot.
48
50
  def initialize(
49
51
  host: nil,
@@ -56,6 +58,7 @@ module PostHog
56
58
  flag_definitions_loaded_at: nil,
57
59
  errors_while_computing: false,
58
60
  quota_limited: false,
61
+ minimal_flag_called_events: false,
59
62
  accessed: nil
60
63
  )
61
64
  @host = host
@@ -68,6 +71,7 @@ module PostHog
68
71
  @flag_definitions_loaded_at = flag_definitions_loaded_at
69
72
  @errors_while_computing = errors_while_computing
70
73
  @quota_limited = quota_limited
74
+ @minimal_flag_called_events = minimal_flag_called_events == true
71
75
  @accessed = Set.new(accessed || [])
72
76
  end
73
77
 
@@ -188,13 +192,19 @@ module PostHog
188
192
  errors << 'flag_missing' if flag.nil?
189
193
  properties['$feature_flag_error'] = errors.join(',') unless errors.empty?
190
194
 
195
+ # Emit a minimal event only when the server gate is on and the flag is
196
+ # known to have no linked experiment. Any missing signal (unknown flag,
197
+ # has_experiment absent) fails safe to the full event.
198
+ minimal = @minimal_flag_called_events && !flag.nil? && flag.has_experiment == false
199
+
191
200
  @host.capture_flag_called_event_if_needed.call(
192
201
  distinct_id: @distinct_id,
193
202
  key: key,
194
203
  response: response,
195
204
  properties: properties,
196
205
  groups: @groups,
197
- disable_geoip: @disable_geoip
206
+ disable_geoip: @disable_geoip,
207
+ minimal: minimal
198
208
  )
199
209
  end
200
210
 
@@ -210,6 +220,7 @@ module PostHog
210
220
  flag_definitions_loaded_at: @flag_definitions_loaded_at,
211
221
  errors_while_computing: @errors_while_computing,
212
222
  quota_limited: @quota_limited,
223
+ minimal_flag_called_events: @minimal_flag_called_events,
213
224
  accessed: @accessed.dup
214
225
  )
215
226
  end
@@ -30,6 +30,7 @@ module PostHog
30
30
  include PostHog::Utils
31
31
 
32
32
  # @param polling_interval [Integer, nil] Seconds between local feature flag definition polls.
33
+ # Defaults to {Defaults::FeatureFlags::POLLING_INTERVAL_SECONDS}.
33
34
  # @param secret_key [String, nil] Credential used to fetch local evaluation definitions. Accepts either a
34
35
  # Personal API Key (`phx_...`) or a Project Secret API Key (`phs_...`).
35
36
  # @param project_api_key [String] Project API key.
@@ -40,6 +41,9 @@ module PostHog
40
41
  # @param feature_flag_request_max_retries [Integer, nil] Retries after a transient network error or retryable
41
42
  # HTTP response status on a flag request. Defaults to {Defaults::FeatureFlags::FLAG_REQUEST_MAX_RETRIES}.
42
43
  # Set to 0 to disable retrying.
44
+ # @param async_load [Boolean] When true, flag definitions are fetched only on the poller thread: an
45
+ # immediate first tick at construction, then the regular polling cadence, which keeps retrying until a
46
+ # load succeeds.
43
47
  def initialize(
44
48
  polling_interval,
45
49
  secret_key,
@@ -48,9 +52,10 @@ module PostHog
48
52
  feature_flag_request_timeout_seconds,
49
53
  on_error = nil,
50
54
  flag_definition_cache_provider: nil,
51
- feature_flag_request_max_retries: nil
55
+ feature_flag_request_max_retries: nil,
56
+ async_load: false
52
57
  )
53
- @polling_interval = polling_interval || 30
58
+ @polling_interval = polling_interval || Defaults::FeatureFlags::POLLING_INTERVAL_SECONDS
54
59
  @secret_key = secret_key
55
60
  @project_api_key = project_api_key
56
61
  @host = host
@@ -65,14 +70,19 @@ module PostHog
65
70
  @on_error = on_error || proc { |status, error| }
66
71
  @quota_limited = Concurrent::AtomicBoolean.new(false)
67
72
  @flags_etag = Concurrent::AtomicReference.new(nil)
68
- @flag_definitions_loaded_at = nil
69
-
73
+ @flag_definitions_loaded_at = Concurrent::AtomicReference.new(nil)
74
+ @async_load = async_load
75
+ # Server-controlled gate for minimal `$feature_flag_called` events, read
76
+ # from the top-level `minimal_flag_called_events` key of the local
77
+ # evaluation definitions payload. false when the server does not send it.
78
+ @minimal_flag_called_events = false
70
79
  @flag_definition_cache_provider = flag_definition_cache_provider
71
80
  FlagDefinitionCacheProvider.validate!(@flag_definition_cache_provider) if @flag_definition_cache_provider
72
81
 
73
82
  @task =
74
83
  Concurrent::TimerTask.new(
75
- execution_interval: polling_interval
84
+ execution_interval: @polling_interval,
85
+ run_now: @async_load
76
86
  ) { _load_feature_flags }
77
87
 
78
88
  # If no secret_key, disable local evaluation & thus polling for definitions
@@ -80,19 +90,31 @@ module PostHog
80
90
  logger.info 'No secret_key provided, disabling local evaluation'
81
91
  @loaded_flags_successfully_once.make_true
82
92
  else
83
- # load once before timer
84
- load_feature_flags
93
+ # load once synchronously before timer, unless @async_load
94
+ load_feature_flags unless @async_load
85
95
  @task.execute
86
96
  end
87
97
  end
88
98
 
89
99
  def load_feature_flags(force_reload = false)
90
- return unless @loaded_flags_successfully_once.false? || force_reload
100
+ return if (@loaded_flags_successfully_once.true? || @async_load) && !force_reload
91
101
 
92
102
  _load_feature_flags
93
103
  end
94
104
 
95
- attr_reader :flag_definitions_loaded_at, :feature_flags_by_key
105
+ # Whether flag definitions are currently loaded. False until the first
106
+ # successful load, and false again if a quota-limited (402) response
107
+ # discards them.
108
+ def definitions_loaded?
109
+ !@flag_definitions_loaded_at.value.nil?
110
+ end
111
+
112
+ # Epoch milliseconds of the last successful definitions load, or nil.
113
+ def flag_definitions_loaded_at
114
+ @flag_definitions_loaded_at.value
115
+ end
116
+
117
+ attr_reader :feature_flags_by_key, :minimal_flag_called_events
96
118
 
97
119
  def get_feature_variants(
98
120
  distinct_id,
@@ -226,6 +248,11 @@ module PostHog
226
248
  # evaluated flags carry it in the response metadata. nil when the server
227
249
  # (an older deployment) does not report it.
228
250
  has_experiment = feature_flag[:has_experiment] if flag_was_locally_evaluated
251
+ # Server-controlled gate for minimal `$feature_flag_called` events.
252
+ # Locally-evaluated flags read it from the definitions payload; remotely
253
+ # evaluated flags read it from the /flags response. nil when the signal
254
+ # is unavailable, which fails safe to the full event.
255
+ minimal_flag_called_events = @minimal_flag_called_events if flag_was_locally_evaluated
229
256
 
230
257
  request_id = nil
231
258
  evaluated_at = nil
@@ -260,6 +287,7 @@ module PostHog
260
287
 
261
288
  flag_detail = flags_data[:flagDetails]&.[](key.to_sym)
262
289
  has_experiment = flag_detail&.metadata&.has_experiment
290
+ minimal_flag_called_events = flags_data[:minimalFlagCalledEvents]
263
291
 
264
292
  logger.debug "Successfully computed flag remotely: #{key} -> #{response}"
265
293
  rescue Timeout::Error => e
@@ -274,7 +302,8 @@ module PostHog
274
302
  end
275
303
  end
276
304
 
277
- [response, flag_was_locally_evaluated, request_id, evaluated_at, feature_flag_error, payload, has_experiment]
305
+ [response, flag_was_locally_evaluated, request_id, evaluated_at, feature_flag_error, payload, has_experiment,
306
+ minimal_flag_called_events]
278
307
  end
279
308
 
280
309
  def get_all_flags(
@@ -333,6 +362,7 @@ module PostHog
333
362
  quota_limited = nil
334
363
  status_code = nil
335
364
  flag_details = nil
365
+ minimal_flag_called_events = nil
336
366
 
337
367
  if fallback_to_server && !only_evaluate_locally
338
368
  begin
@@ -348,6 +378,7 @@ module PostHog
348
378
 
349
379
  request_id = flags_and_payloads[:requestId]
350
380
  evaluated_at = flags_and_payloads[:evaluatedAt]
381
+ minimal_flag_called_events = flags_and_payloads[:minimalFlagCalledEvents]
351
382
 
352
383
  # Check if feature_flags are quota limited
353
384
  if quota_limited&.include?('feature_flags')
@@ -383,7 +414,8 @@ module PostHog
383
414
  evaluatedAt: evaluated_at,
384
415
  errorsWhileComputingFlags: errors_while_computing,
385
416
  quotaLimited: quota_limited,
386
- status: status_code
417
+ status: status_code,
418
+ minimalFlagCalledEvents: minimal_flag_called_events
387
419
  }
388
420
  end
389
421
 
@@ -1183,6 +1215,8 @@ module PostHog
1183
1215
  @feature_flags_by_key = {}
1184
1216
  @group_type_mapping = Concurrent::Hash.new
1185
1217
  @cohorts = Concurrent::Hash.new
1218
+ @flag_definitions_loaded_at.value = nil
1219
+ @minimal_flag_called_events = false
1186
1220
  @loaded_flags_successfully_once.make_false
1187
1221
  @quota_limited.make_true
1188
1222
  return
@@ -1206,7 +1240,8 @@ module PostHog
1206
1240
  data = {
1207
1241
  flags: @feature_flags.to_a,
1208
1242
  group_type_mapping: @group_type_mapping.to_h,
1209
- cohorts: @cohorts.to_h
1243
+ cohorts: @cohorts.to_h,
1244
+ minimal_flag_called_events: @minimal_flag_called_events
1210
1245
  }
1211
1246
  @flag_definition_cache_provider.on_flag_definitions_received(data)
1212
1247
  rescue StandardError => e
@@ -1218,6 +1253,7 @@ module PostHog
1218
1253
  flags = get_by_symbol_or_string_key(data, 'flags') || []
1219
1254
  group_type_mapping = get_by_symbol_or_string_key(data, 'group_type_mapping') || {}
1220
1255
  cohorts = get_by_symbol_or_string_key(data, 'cohorts') || {}
1256
+ minimal_flag_called_events = get_by_symbol_or_string_key(data, 'minimal_flag_called_events')
1221
1257
 
1222
1258
  @feature_flags = Concurrent::Array.new(flags.map { |f| deep_symbolize_keys(f) })
1223
1259
 
@@ -1229,9 +1265,10 @@ module PostHog
1229
1265
 
1230
1266
  @group_type_mapping = Concurrent::Hash[deep_symbolize_keys(group_type_mapping)]
1231
1267
  @cohorts = Concurrent::Hash[deep_symbolize_keys(cohorts)]
1268
+ @minimal_flag_called_events = minimal_flag_called_events == true
1232
1269
 
1233
1270
  logger.debug "Loaded #{@feature_flags.length} feature flags and #{@cohorts.length} cohorts"
1234
- @flag_definitions_loaded_at = (Time.now.to_f * 1000).to_i
1271
+ @flag_definitions_loaded_at.value = (Time.now.to_f * 1000).to_i
1235
1272
  @loaded_flags_successfully_once.make_true if @loaded_flags_successfully_once.false?
1236
1273
  end
1237
1274
 
@@ -14,9 +14,11 @@ module PostHog
14
14
  #
15
15
  # @!method flag_definitions
16
16
  # Retrieve cached flag definitions. Return a Hash with +:flags+,
17
- # +:group_type_mapping+, and +:cohorts+ keys, or +nil+ if the cache
18
- # is empty. Returning +nil+ triggers an API fetch when no flags are
19
- # loaded yet (emergency fallback).
17
+ # +:group_type_mapping+, +:cohorts+, and +:minimal_flag_called_events+
18
+ # keys, or +nil+ if the cache is empty. Returning +nil+ triggers an API
19
+ # fetch when no flags are loaded yet (emergency fallback). Providers
20
+ # written before +:minimal_flag_called_events+ existed continue to work;
21
+ # a missing key is treated as +false+.
20
22
  # @return [Hash, nil]
21
23
  #
22
24
  # @!method should_fetch_flag_definitions?
@@ -27,9 +29,9 @@ module PostHog
27
29
  #
28
30
  # @!method on_flag_definitions_received(data)
29
31
  # Called after successfully fetching new definitions from the API.
30
- # +data+ is a Hash with +:flags+, +:group_type_mapping+, and +:cohorts+
31
- # keys (plain Ruby types, not Concurrent:: wrappers). Store it in your
32
- # external cache.
32
+ # +data+ is a Hash with +:flags+, +:group_type_mapping+, +:cohorts+, and
33
+ # +:minimal_flag_called_events+ keys (plain Ruby types, not Concurrent::
34
+ # wrappers). Store it in your external cache.
33
35
  # @param data [Hash]
34
36
  # @return [void]
35
37
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PostHog
4
- VERSION = '3.19.0'
4
+ VERSION = '3.21.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: posthog-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.19.0
4
+ version: 3.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''