featureflip 2.10.0 → 2.11.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: 33b15e24100b214989443fd146e3b5a4ef29c92ee28f457419c4ef0816e01efa
4
- data.tar.gz: f638de9e949664b629c35771bce31f2dff71eb018133eeecc3a1d952ba037992
3
+ metadata.gz: 7dbbc4e1eefae9adf8a818fc31905e674ee68369be22f6d558f1838604a34fba
4
+ data.tar.gz: 91ddda08b1eb8015d297c4a6206d8df48704cde620908634bdc7c5415b6e3cb4
5
5
  SHA512:
6
- metadata.gz: 0c3da771ddf9cb78f4a73f890d03d178047f78dfdf0a1347a52ca82dd1e3721f79b3249856ea1413068aa924b1f5d9acf9a8c2449b79731134508b9f4701714f
7
- data.tar.gz: f73db84108ad650e6812868b217fc3b981ba0cdbc2985de312ef94d2fc88d8fdb2d24cc638a5c24837b3598271f7a49005ed5ba1b9f428778099909042b5457b
6
+ metadata.gz: 1c77f14b1245ebd4453d878c41fbadbea5051cee8b86eb5a9aed6fb210714b71275792b19cf571e62ccacce985babf303db5eeb81875fd6a18009bb169ef5506
7
+ data.tar.gz: 0ea6aba2d012d330c976e2fee16be73aee7d3ec1392a7bc0677147b2e1d7bac1a33b7048b59afaad82fd72339e984421ddb358339bedb220bacb66b8fa572e55
@@ -4,6 +4,15 @@ module Featureflip
4
4
  :flush_batch_size, :init_timeout, :connect_timeout, :read_timeout,
5
5
  :max_stream_retries, :send_events, :logger
6
6
 
7
+ # Identifies a library that wraps this SDK, such as the OpenFeature provider. Its
8
+ # token is sent after the SDK's own in the User-Agent
9
+ # (`featureflip-ruby/<version> my-wrapper/1.0.0`) so usage through the wrapper can be
10
+ # counted. Both parts must be valid HTTP tokens; an invalid wrapper is ignored with a
11
+ # logged warning. wrapper_version may be nil. Leave unset when calling the SDK
12
+ # directly. Excluded from SharedCore._configs_equal: it identifies the caller rather
13
+ # than changing behavior.
14
+ attr_accessor :wrapper_name, :wrapper_version
15
+
7
16
  # Evaluation inspectors -- callables invoked once per variation call with a
8
17
  # Models::EvaluationEvent. Always an Array; non-callable entries are dropped
9
18
  # on assignment rather than blowing up on the evaluation hot path.
@@ -22,7 +31,9 @@ module Featureflip
22
31
  max_stream_retries: 5,
23
32
  send_events: true,
24
33
  logger: nil,
25
- inspectors: nil
34
+ inspectors: nil,
35
+ wrapper_name: nil,
36
+ wrapper_version: nil
26
37
  )
27
38
  @sdk_key = sdk_key
28
39
  @base_url = base_url
@@ -37,6 +48,8 @@ module Featureflip
37
48
  @send_events = send_events
38
49
  @logger = logger || default_logger
39
50
  self.inspectors = inspectors
51
+ @wrapper_name = wrapper_name
52
+ @wrapper_version = wrapper_version
40
53
 
41
54
  validate!
42
55
  end
@@ -53,6 +66,13 @@ module Featureflip
53
66
  @inspectors = list.select { |i| i.respond_to?(:call) }.freeze
54
67
  end
55
68
 
69
+ # The User-Agent for every request: the SDK token, then the wrapper's (#4154). Built
70
+ # on first use and memoized, so the HTTP client and the stream share one value and an
71
+ # invalid wrapper is warned about once.
72
+ def user_agent
73
+ @user_agent ||= SdkIdentity.user_agent(self)
74
+ end
75
+
56
76
  def validate!
57
77
  finalize!
58
78
  validate_positive_fields!
@@ -160,7 +160,9 @@ module Featureflip
160
160
  req = Net::HTTP::Get.new(uri.request_uri)
161
161
  req["Authorization"] = @sdk_key
162
162
  req["Accept"] = "text/event-stream"
163
- req["User-Agent"] = "featureflip-ruby/#{Featureflip::VERSION}"
163
+ # Same memoized value as the HTTP client, so an invalid wrapper is warned about
164
+ # once rather than on every reconnect.
165
+ req["User-Agent"] = @config.user_agent
164
166
 
165
167
  http.request(req) do |response|
166
168
  unless response.is_a?(Net::HTTPSuccess)
@@ -83,7 +83,7 @@ module Featureflip
83
83
 
84
84
  req["Authorization"] = @sdk_key
85
85
  req["Content-Type"] = "application/json"
86
- req["User-Agent"] = "featureflip-ruby/#{Featureflip::VERSION}"
86
+ req["User-Agent"] = @config.user_agent
87
87
 
88
88
  response = http.request(req)
89
89
 
@@ -0,0 +1,27 @@
1
+ module Featureflip
2
+ # The User-Agent every request carries so the Evaluation API can count SDK usage by
3
+ # name and version (#4154, contract in #4138): `featureflip-ruby/<version>`, then the
4
+ # configured wrapper's token. VERSION is the constant the publish workflow rewrites,
5
+ # never a second literal (#2141).
6
+ module SdkIdentity
7
+ # RFC 9110 product token: tchars.
8
+ TOKEN = /\A[!#$%&'*+.^_`|~0-9A-Za-z-]+\z/
9
+
10
+ def self.user_agent(config)
11
+ sdk = "featureflip-ruby/#{Featureflip::VERSION}"
12
+ name = config.wrapper_name
13
+ return sdk if name.nil? || name.to_s.empty?
14
+
15
+ version = config.wrapper_version
16
+ unless TOKEN.match?(name.to_s) && (version.nil? || TOKEN.match?(version.to_s))
17
+ # Dropped rather than raised: identity metadata must never stop the client starting.
18
+ config.logger.warn(
19
+ "Featureflip: ignoring wrapper '#{name}/#{version}': not a valid User-Agent product token"
20
+ )
21
+ return sdk
22
+ end
23
+
24
+ version.nil? ? "#{sdk} #{name}" : "#{sdk} #{name}/#{version}"
25
+ end
26
+ end
27
+ end
@@ -595,6 +595,8 @@ module Featureflip
595
595
  @update_listeners_mutex = Mutex.new
596
596
  end
597
597
 
598
+ # wrapper_name/wrapper_version are deliberately excluded: they identify the caller
599
+ # rather than change behavior (see Config).
598
600
  def self._configs_equal(a, b)
599
601
  a.base_url == b.base_url &&
600
602
  a.streaming == b.streaming &&
@@ -1,3 +1,3 @@
1
1
  module Featureflip
2
- VERSION = "2.10.0"
2
+ VERSION = "2.11.0"
3
3
  end
data/lib/featureflip.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require_relative "featureflip/version"
2
2
  require_relative "featureflip/errors"
3
3
  require_relative "featureflip/config"
4
+ require_relative "featureflip/sdk_identity"
4
5
  require_relative "featureflip/models/flag"
5
6
  require_relative "featureflip/models/segment"
6
7
  require_relative "featureflip/models/evaluation_detail"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: featureflip
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.10.0
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Featureflip
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-10 00:00:00.000000000 Z
11
+ date: 2026-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logger
@@ -88,6 +88,7 @@ files:
88
88
  - lib/featureflip/models/evaluation_event.rb
89
89
  - lib/featureflip/models/flag.rb
90
90
  - lib/featureflip/models/segment.rb
91
+ - lib/featureflip/sdk_identity.rb
91
92
  - lib/featureflip/shared_core.rb
92
93
  - lib/featureflip/store/flag_store.rb
93
94
  - lib/featureflip/store/update_diff.rb