openfeature-sdk 0.6.6 → 0.6.7
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 +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +1 -1
- data/README.md +17 -5
- data/lib/open_feature/sdk/client.rb +15 -15
- data/lib/open_feature/sdk/configuration.rb +94 -24
- data/lib/open_feature/sdk/version.rb +1 -1
- data/sig/open_feature/sdk/configuration.rbs +7 -1
- data/sig/open_feature/sdk/provider.rbs +5 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 93f85fdb9eb64b634a3267d0987415f3e4b9033a9d864e80478dfde83074fa7d
|
|
4
|
+
data.tar.gz: 14e94971fdae29a56d31db9d8ee44716b805b6783e0d381ac04e6348168ccf67
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c1e726bae4617d91ed82f676270bb51b7355e8694fac68a76af5f8ea046ed60c33d4c31b0a716827ad61edffe2849c3eb444c614975ac8a09707dcf620286c03
|
|
7
|
+
data.tar.gz: 47d740d86cac2c493058c0f35aa6c2489d89f0502e8df3eb9ba850585777934478fe2dcf500b7eac9b71c96cfb2c857bc6026e9d1214e7876bc385788fcf6f18
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.7](https://github.com/open-feature/ruby-sdk/compare/v0.6.6...v0.6.7) (2026-10-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* pass the bound domain to provider init and support domain-scoped providers ([#345](https://github.com/open-feature/ruby-sdk/issues/345)) ([f3cf6b7](https://github.com/open-feature/ruby-sdk/commit/f3cf6b76c06297aa4c0a2a95ea1055f816269e3b))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* return defaults instead of raising from client calls ([#346](https://github.com/open-feature/ruby-sdk/issues/346)) ([481f21c](https://github.com/open-feature/ruby-sdk/commit/481f21cfe70365de92c6ece3eb92c40117a7e1c5))
|
|
14
|
+
|
|
3
15
|
## [0.6.6](https://github.com/open-feature/ruby-sdk/compare/v0.6.5...v0.6.6) (2026-10-22)
|
|
4
16
|
|
|
5
17
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
</a>
|
|
18
18
|
<!-- x-release-please-start-version -->
|
|
19
19
|
|
|
20
|
-
<a href="https://github.com/open-feature/ruby-sdk/releases/tag/v0.6.
|
|
21
|
-
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.6.
|
|
20
|
+
<a href="https://github.com/open-feature/ruby-sdk/releases/tag/v0.6.7">
|
|
21
|
+
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.6.7&color=blue&style=for-the-badge" />
|
|
22
22
|
</a>
|
|
23
23
|
|
|
24
24
|
<!-- x-release-please-end -->
|
|
@@ -301,14 +301,15 @@ legacy_flag_client = OpenFeature::SDK.build_client(domain: "legacy_flags")
|
|
|
301
301
|
|
|
302
302
|
Events allow you to react to state changes in the provider or underlying flag management system, such as flag definition changes, provider readiness, or error conditions.
|
|
303
303
|
Initialization events (`PROVIDER_READY` on success, `PROVIDER_ERROR` on failure) are dispatched for every provider.
|
|
304
|
-
Some providers
|
|
304
|
+
Some providers emit additional events: `PROVIDER_CONFIGURATION_CHANGED`, `PROVIDER_STALE`, `PROVIDER_RECONCILING` and `PROVIDER_CONTEXT_CHANGED`.
|
|
305
|
+
Handlers receive a hash with the `provider_name` and any details the provider sent, such as `message` or `error_code`.
|
|
305
306
|
|
|
306
307
|
Please refer to the documentation of the provider you're using to see what events are supported.
|
|
307
308
|
|
|
308
309
|
```ruby
|
|
309
310
|
# Register event handlers at the API (global) level
|
|
310
311
|
ready_handler = ->(event_details) do
|
|
311
|
-
puts "Provider #{event_details[:
|
|
312
|
+
puts "Provider #{event_details[:provider_name]} is ready!"
|
|
312
313
|
end
|
|
313
314
|
|
|
314
315
|
OpenFeature::SDK.add_handler(OpenFeature::SDK::ProviderEvent::PROVIDER_READY, ready_handler)
|
|
@@ -351,6 +352,9 @@ This should only be called when your application is in the process of shutting d
|
|
|
351
352
|
OpenFeature::SDK.shutdown
|
|
352
353
|
```
|
|
353
354
|
|
|
355
|
+
The SDK also shuts down a replaced provider once no domain uses it.
|
|
356
|
+
Events from shut-down providers are ignored.
|
|
357
|
+
|
|
354
358
|
Individual providers can implement a `shutdown` method to perform cleanup:
|
|
355
359
|
|
|
356
360
|
```ruby
|
|
@@ -442,13 +446,21 @@ You’ll then need to write the provider by implementing the `Provider` duck.
|
|
|
442
446
|
|
|
443
447
|
```ruby
|
|
444
448
|
class MyProvider
|
|
445
|
-
|
|
449
|
+
# Both arguments are optional; declare only the ones you need.
|
|
450
|
+
# `domain` is the domain the provider was bound to, or nil for the default provider.
|
|
451
|
+
def init(evaluation_context = nil, domain: nil)
|
|
446
452
|
# Perform any initialization steps with flag management system here
|
|
447
453
|
# Return value is ignored
|
|
448
454
|
# **Note** The OpenFeature spec defines a lifecycle method called `initialize` to be called when a new provider is set.
|
|
449
455
|
# To avoid conflicting with the Ruby `initialize` method, this method should be named `init` when creating a provider.
|
|
450
456
|
end
|
|
451
457
|
|
|
458
|
+
# Optional: return true if this provider keeps state for a single domain.
|
|
459
|
+
# The SDK then raises ArgumentError if the same instance is bound to a second domain.
|
|
460
|
+
def domain_scoped?
|
|
461
|
+
false
|
|
462
|
+
end
|
|
463
|
+
|
|
452
464
|
def shutdown
|
|
453
465
|
# Perform any shutdown/reclamation steps with flag management system here
|
|
454
466
|
# Return value is ignored
|
|
@@ -56,12 +56,15 @@ module OpenFeature
|
|
|
56
56
|
built_context = build_evaluation_context(evaluation_context)
|
|
57
57
|
|
|
58
58
|
@provider.track(tracking_event_name, evaluation_context: built_context, tracking_event_details: tracking_event_details)
|
|
59
|
+
rescue
|
|
60
|
+
nil
|
|
59
61
|
end
|
|
60
62
|
|
|
61
63
|
RESULT_TYPE.each do |result_type|
|
|
62
64
|
SUFFIXES.each do |suffix|
|
|
63
65
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
64
66
|
def fetch_#{result_type}_#{suffix}(flag_key:, default_value:, evaluation_context: nil, hooks: [], hook_hints: nil)
|
|
67
|
+
validate_default_value_type(:#{result_type}, default_value)
|
|
65
68
|
evaluation_details = fetch_details(type: :#{result_type}, flag_key:, default_value:, evaluation_context:, invocation_hooks: hooks, hook_hints: hook_hints)
|
|
66
69
|
#{"evaluation_details.value" if suffix == :value}
|
|
67
70
|
end
|
|
@@ -72,8 +75,6 @@ module OpenFeature
|
|
|
72
75
|
private
|
|
73
76
|
|
|
74
77
|
def fetch_details(type:, flag_key:, default_value:, evaluation_context: nil, invocation_hooks: [], hook_hints: nil)
|
|
75
|
-
validate_default_value_type(type, default_value)
|
|
76
|
-
|
|
77
78
|
built_context = build_evaluation_context(evaluation_context)
|
|
78
79
|
|
|
79
80
|
# Assemble ordered hooks: API → Client → Invocation → Provider (spec 4.4.2)
|
|
@@ -97,17 +98,7 @@ module OpenFeature
|
|
|
97
98
|
return EvaluationDetails.new(flag_key: flag_key, resolution_details: resolution)
|
|
98
99
|
end
|
|
99
100
|
|
|
100
|
-
|
|
101
|
-
return evaluate_flag(type: type, flag_key: flag_key, default_value: default_value, evaluation_context: built_context)
|
|
102
|
-
rescue => e
|
|
103
|
-
resolution = Provider::ResolutionDetails.new(
|
|
104
|
-
value: default_value,
|
|
105
|
-
error_code: EvaluationError.code_for(e),
|
|
106
|
-
reason: Provider::Reason::ERROR,
|
|
107
|
-
error_message: e.message
|
|
108
|
-
)
|
|
109
|
-
return EvaluationDetails.new(flag_key: flag_key, resolution_details: resolution)
|
|
110
|
-
end
|
|
101
|
+
return evaluate_flag(type: type, flag_key: flag_key, default_value: default_value, evaluation_context: built_context)
|
|
111
102
|
end
|
|
112
103
|
|
|
113
104
|
hook_context = Hooks::HookContext.new(
|
|
@@ -143,6 +134,15 @@ module OpenFeature
|
|
|
143
134
|
evaluate_flag(type: type, flag_key: flag_key, default_value: default_value, evaluation_context: hctx.evaluation_context)
|
|
144
135
|
end
|
|
145
136
|
end
|
|
137
|
+
rescue StandardError, NotImplementedError => e
|
|
138
|
+
# Spec 1.4.10 and 1.4.11: report through the details, never raise or log. NotImplementedError is the abstract-method idiom.
|
|
139
|
+
resolution = Provider::ResolutionDetails.new(
|
|
140
|
+
value: default_value,
|
|
141
|
+
error_code: EvaluationError.code_for(e),
|
|
142
|
+
reason: Provider::Reason::ERROR,
|
|
143
|
+
error_message: e.message
|
|
144
|
+
)
|
|
145
|
+
EvaluationDetails.new(flag_key: flag_key, resolution_details: resolution)
|
|
146
146
|
end
|
|
147
147
|
|
|
148
148
|
def evaluate_flag(type:, flag_key:, default_value:, evaluation_context:)
|
|
@@ -153,9 +153,9 @@ module OpenFeature
|
|
|
153
153
|
evaluation_context: evaluation_context
|
|
154
154
|
)
|
|
155
155
|
|
|
156
|
-
if TYPE_CLASS_MAP[type].none? { |klass| resolution_details.value.is_a?(klass) }
|
|
156
|
+
if resolution_details.error_code || TYPE_CLASS_MAP[type].none? { |klass| resolution_details.value.is_a?(klass) }
|
|
157
157
|
resolution_details.value = default_value
|
|
158
|
-
resolution_details.error_code
|
|
158
|
+
resolution_details.error_code ||= Provider::ErrorCode::TYPE_MISMATCH
|
|
159
159
|
resolution_details.reason = Provider::Reason::ERROR
|
|
160
160
|
resolution_details.variant = nil
|
|
161
161
|
end
|
|
@@ -20,9 +20,14 @@ module OpenFeature
|
|
|
20
20
|
attr_accessor :evaluation_context, :hooks, :transaction_context_propagator
|
|
21
21
|
attr_reader :logger
|
|
22
22
|
|
|
23
|
+
# One per registration; +done+ is closed once init finishes, so waiters can pop on it
|
|
24
|
+
InitAttempt = Struct.new(:state, :error, :done)
|
|
25
|
+
private_constant :InitAttempt
|
|
26
|
+
|
|
23
27
|
def initialize
|
|
24
28
|
@hooks = []
|
|
25
29
|
@providers = {}
|
|
30
|
+
@init_attempts = {}.compare_by_identity
|
|
26
31
|
@provider_mutex = Mutex.new
|
|
27
32
|
@logger = nil
|
|
28
33
|
@event_dispatcher = EventDispatcher.new(@logger)
|
|
@@ -118,6 +123,9 @@ module OpenFeature
|
|
|
118
123
|
@provider_state_registry.clear
|
|
119
124
|
@provider_mutex.synchronize do
|
|
120
125
|
@providers.clear
|
|
126
|
+
# Release anyone waiting on an init that shutdown cut short
|
|
127
|
+
@init_attempts.each_value { |attempt| attempt.done.close }
|
|
128
|
+
@init_attempts.clear
|
|
121
129
|
end
|
|
122
130
|
@hooks.clear
|
|
123
131
|
@evaluation_context = nil
|
|
@@ -129,22 +137,29 @@ module OpenFeature
|
|
|
129
137
|
context_for_init = @evaluation_context
|
|
130
138
|
|
|
131
139
|
old_provider = nil
|
|
140
|
+
attempt = nil
|
|
132
141
|
needs_init = false
|
|
142
|
+
init_thread = nil
|
|
133
143
|
needs_shutdown = false
|
|
134
144
|
|
|
145
|
+
# Provider code runs before taking the lock: it may call back into the SDK
|
|
146
|
+
scoped = domain_scoped?(provider)
|
|
147
|
+
|
|
135
148
|
@provider_mutex.synchronize do
|
|
149
|
+
validate_domain_scoped_binding!(provider, domain, scoped)
|
|
150
|
+
|
|
136
151
|
old_provider = @providers[domain]
|
|
137
152
|
|
|
138
153
|
new_providers = @providers.dup
|
|
139
154
|
new_providers[domain] = provider
|
|
140
155
|
@providers = new_providers
|
|
141
156
|
|
|
142
|
-
# Spec 1.1.2.2:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
needs_init = !already_active
|
|
157
|
+
# Spec 1.1.2.2: initialize once per registration; a failed init is retried on the next set
|
|
158
|
+
attempt = @init_attempts[provider]
|
|
159
|
+
needs_init = attempt.nil? || attempt.state == :failed
|
|
146
160
|
|
|
147
161
|
if needs_init
|
|
162
|
+
attempt = @init_attempts[provider] = InitAttempt.new(:running, nil, Thread::Queue.new)
|
|
148
163
|
@provider_state_registry.set_initial_state(provider)
|
|
149
164
|
provider.send(:attach, self) if provider.is_a?(Provider::EventEmitter)
|
|
150
165
|
end
|
|
@@ -153,6 +168,7 @@ module OpenFeature
|
|
|
153
168
|
if old_provider && !old_provider.equal?(provider)
|
|
154
169
|
needs_shutdown = !provider_bound?(old_provider)
|
|
155
170
|
if needs_shutdown
|
|
171
|
+
@init_attempts.delete(old_provider)
|
|
156
172
|
@provider_state_registry.remove_provider(old_provider)
|
|
157
173
|
old_provider.send(:detach) if old_provider.is_a?(Provider::EventEmitter)
|
|
158
174
|
end
|
|
@@ -171,45 +187,65 @@ module OpenFeature
|
|
|
171
187
|
# Initialize provider outside the mutex to avoid blocking other operations
|
|
172
188
|
if needs_init
|
|
173
189
|
if wait_for_init
|
|
174
|
-
init_provider(provider, context_for_init, raise_on_error: true)
|
|
190
|
+
init_provider(provider, context_for_init, domain:, attempt:, raise_on_error: true)
|
|
175
191
|
else
|
|
176
|
-
Thread.new do
|
|
177
|
-
init_provider(provider, context_for_init, raise_on_error: false)
|
|
192
|
+
init_thread = Thread.new do
|
|
193
|
+
init_provider(provider, context_for_init, domain:, attempt:, raise_on_error: false)
|
|
178
194
|
end
|
|
179
195
|
end
|
|
180
196
|
elsif wait_for_init
|
|
181
|
-
#
|
|
197
|
+
# Already registered: wait for an init still in flight, then report its outcome
|
|
198
|
+
attempt.done.pop
|
|
199
|
+
unless attempt.state == :succeeded
|
|
200
|
+
raise attempt.error || ProviderInitializationError.new(
|
|
201
|
+
"Provider #{provider.class.name} initialization did not complete",
|
|
202
|
+
provider:,
|
|
203
|
+
error_code: Provider::ErrorCode::GENERAL
|
|
204
|
+
)
|
|
205
|
+
end
|
|
206
|
+
|
|
182
207
|
dispatch_provider_event(provider, ProviderEvent::PROVIDER_READY)
|
|
183
208
|
end
|
|
209
|
+
ensure
|
|
210
|
+
# Fail an attempt no init took over (e.g. a Timeout hit first), or it would stay running forever
|
|
211
|
+
finish_init_attempt(attempt, :failed) if needs_init && !init_thread
|
|
184
212
|
end
|
|
185
213
|
|
|
186
|
-
def init_provider(provider, context, raise_on_error: false)
|
|
187
|
-
|
|
188
|
-
init_method = provider.method(:init)
|
|
189
|
-
if init_method.parameters.empty?
|
|
190
|
-
provider.init
|
|
191
|
-
else
|
|
192
|
-
provider.init(context)
|
|
193
|
-
end
|
|
194
|
-
end
|
|
214
|
+
def init_provider(provider, context, domain:, attempt:, raise_on_error: false)
|
|
215
|
+
call_init(provider, context, domain)
|
|
195
216
|
|
|
217
|
+
# Settle the attempt before handlers run, so a handler can register this provider again
|
|
218
|
+
finish_init_attempt(attempt, :succeeded)
|
|
196
219
|
dispatch_provider_event(provider, ProviderEvent::PROVIDER_READY)
|
|
197
220
|
rescue => e
|
|
198
221
|
# Spec 1.7.5: PROVIDER_FATAL from init makes the provider FATAL
|
|
199
222
|
error_code = EvaluationError.code_for(e)
|
|
223
|
+
error = ProviderInitializationError.new(
|
|
224
|
+
"Provider #{provider.class.name} initialization failed: #{e.message}",
|
|
225
|
+
provider:,
|
|
226
|
+
error_code: error_code,
|
|
227
|
+
original_error: e
|
|
228
|
+
)
|
|
229
|
+
finish_init_attempt(attempt, :failed, error)
|
|
200
230
|
|
|
201
231
|
dispatch_provider_event(provider, ProviderEvent::PROVIDER_ERROR,
|
|
202
232
|
error_code: error_code,
|
|
203
233
|
message: e.message)
|
|
204
234
|
|
|
205
|
-
if raise_on_error
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
235
|
+
raise error if raise_on_error
|
|
236
|
+
ensure
|
|
237
|
+
# Reached unsettled only when init raised something other than a StandardError
|
|
238
|
+
finish_init_attempt(attempt, :failed)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def finish_init_attempt(attempt, state, error = nil)
|
|
242
|
+
@provider_mutex.synchronize do
|
|
243
|
+
return unless attempt.state == :running
|
|
244
|
+
|
|
245
|
+
attempt.state = state
|
|
246
|
+
attempt.error = error
|
|
212
247
|
end
|
|
248
|
+
attempt.done.close
|
|
213
249
|
end
|
|
214
250
|
|
|
215
251
|
def dispatch_provider_event(provider, event_type, details = {})
|
|
@@ -239,6 +275,40 @@ module OpenFeature
|
|
|
239
275
|
provider.respond_to?(:metadata) ? provider.metadata.name : provider.class.name
|
|
240
276
|
end
|
|
241
277
|
|
|
278
|
+
def domain_scoped?(provider)
|
|
279
|
+
provider.respond_to?(:domain_scoped?) && provider.domain_scoped?
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def validate_domain_scoped_binding!(provider, domain, scoped)
|
|
283
|
+
return unless scoped && provider_bound?(provider) && !@providers[domain].equal?(provider)
|
|
284
|
+
|
|
285
|
+
raise ArgumentError, "Cannot bind domain-scoped provider to more than one domain"
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def call_init(provider, context, domain)
|
|
289
|
+
return unless provider.respond_to?(:init)
|
|
290
|
+
|
|
291
|
+
parameters = provider.method(:init).parameters
|
|
292
|
+
takes_domain = init_accepts_domain?(parameters)
|
|
293
|
+
if !takes_domain && domain_scoped?(provider)
|
|
294
|
+
@logger&.warn("Provider #{extract_provider_name(provider)} is domain-scoped but its init doesn't accept domain:")
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
args = init_accepts_evaluation_context?(parameters) ? [context] : []
|
|
298
|
+
provider.init(*args, **(takes_domain ? {domain:} : {}))
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Anonymous `**` (from `...`) and delegators' bare `*` can't be trusted to accept `domain:`
|
|
302
|
+
def init_accepts_domain?(parameters)
|
|
303
|
+
parameters.any? do |kind, name|
|
|
304
|
+
((kind == :key || kind == :keyreq) && name == :domain) || (kind == :keyrest && name && name != :**)
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def init_accepts_evaluation_context?(parameters)
|
|
309
|
+
parameters.any? { |kind, _| kind == :req || kind == :opt || kind == :rest }
|
|
310
|
+
end
|
|
311
|
+
|
|
242
312
|
def run_handlers_for_provider(provider, event_type, event_details)
|
|
243
313
|
# Run global handlers (API-level, no domain filtering)
|
|
244
314
|
@event_dispatcher.trigger_event(event_type, event_details)
|
|
@@ -32,9 +32,15 @@ module OpenFeature
|
|
|
32
32
|
|
|
33
33
|
def reset: () -> void
|
|
34
34
|
def set_provider_internal: (untyped provider, domain: String?, wait_for_init: bool) -> void
|
|
35
|
-
def init_provider: (untyped provider, EvaluationContext? context, ?raise_on_error: bool) -> void
|
|
35
|
+
def init_provider: (untyped provider, EvaluationContext? context, domain: String?, attempt: untyped, ?raise_on_error: bool) -> void
|
|
36
|
+
def finish_init_attempt: (untyped attempt, Symbol state, ?ProviderInitializationError? error) -> void
|
|
36
37
|
def dispatch_provider_event: (untyped provider, String event_type, ?Hash[Symbol, untyped] details) -> void
|
|
37
38
|
def provider_bound?: (untyped provider) -> bool
|
|
39
|
+
def domain_scoped?: (untyped provider) -> bool
|
|
40
|
+
def validate_domain_scoped_binding!: (untyped provider, String? domain, bool scoped) -> void
|
|
41
|
+
def call_init: (untyped provider, EvaluationContext? context, String? domain) -> void
|
|
42
|
+
def init_accepts_domain?: (Array[[Symbol, Symbol?]] parameters) -> bool
|
|
43
|
+
def init_accepts_evaluation_context?: (Array[[Symbol, Symbol?]] parameters) -> bool
|
|
38
44
|
def extract_provider_name: (untyped provider) -> String
|
|
39
45
|
def run_handlers_for_provider: (untyped provider, String event_type, Hash[Symbol, untyped] event_details) -> void
|
|
40
46
|
def run_immediate_handler: (String event_type, _ToProc handler, Client? client) -> void
|
|
@@ -11,11 +11,15 @@ module OpenFeature
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
interface _LifecycleProvider
|
|
14
|
-
def init: (?EvaluationContext? evaluation_context) -> void
|
|
14
|
+
def init: (?EvaluationContext? evaluation_context, ?domain: String?) -> void
|
|
15
15
|
def shutdown: () -> void
|
|
16
16
|
def metadata: () -> ProviderMetadata
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
interface _DomainScopedProvider
|
|
20
|
+
def domain_scoped?: () -> bool
|
|
21
|
+
end
|
|
22
|
+
|
|
19
23
|
interface _TrackableProvider
|
|
20
24
|
def track: (String tracking_event_name, ?evaluation_context: EvaluationContext?, ?tracking_event_details: TrackingEventDetails?) -> void
|
|
21
25
|
end
|