split_openfeature_provider_dart_client 0.1.0
split_openfeature_provider_dart_client: ^0.1.0 copied to clipboard
Split OpenFeature provider for Dart (client-side / static-context) — adapts splitio_client_side to the OpenFeature FeatureProvider contract.
Split OpenFeature Provider for Dart #
Adapts the Split Dart client SDK (splitio_client_side) to the OpenFeature
FeatureProvider
contract defined by openfeature_dart_client_sdk.
Overview #
This provider lets you evaluate Split feature flags through OpenFeature's standard client-side (static-context) API.
Getting started #
Add the dependency #
Both openfeature_dart_client_sdk and splitio_client_side are peer packages
and must be declared alongside this provider.
dependencies:
split_openfeature_provider_dart_client: ^0.1.0
openfeature_dart_client_sdk: ^0.0.1-beta.1
splitio_client_side: ^1.1.0
Register the Split provider with OpenFeature #
Construct a SplitFactory, pass it to OpenFeatureSplitProvider, and register
the provider with the OpenFeature API. The provider never constructs its own
factory — the SDK key, config, and initial matching key are the caller's
responsibility.
import 'package:openfeature_dart_client_sdk/openfeature_dart_client_sdk.dart';
import 'package:split_openfeature_provider_dart_client/split_openfeature_provider_dart_client.dart';
import 'package:splitio_client_side/splitio_client_side.dart'
show SplitFactory, SplitClientConfig;
Future<void> main() async {
final splitFactory = SplitFactory.create(
'CLIENT_SIDE_SDK_KEY',
SplitClientConfig(),
'TARGETING_KEY',
);
final provider = OpenFeatureSplitProvider(splitFactory);
// Waits for the Split SDK to become ready or errors on timeout.
await OpenFeatureAPI.instance.setProviderAndWait(provider);
final client = OpenFeatureAPI.instance.getClient();
}
Evaluating flags #
After registration you use OpenFeature's evaluation API as documented on openfeature.dev.
The provider uses one field on every EvaluationContext used for
evaluation:
targetingKey— identifies the subject of evaluation.
trafficType is optional on the evaluation context for flag lookups (Split's
client-side evaluation ignores it). It is required only when calling
track.
await OpenFeatureAPI.instance.setEvaluationContextAndWait(
EvaluationContext(
targetingKey: 'TARGETING_KEY',
),
);
final showBanner = client.getBooleanValue('show_banner', false);
Evaluate with details #
Use the get*Details variants to retrieve the value alongside variant,
reason, error code, and flag metadata. This provider exposes the raw Split
treatment config JSON string under flagMetadata['config'].
final details = client.getBooleanDetails('bool_flag', false);
final config = details.flagMetadata['config']; // raw JSON string, or ''
Evaluate with attributes #
Attributes on the EvaluationContext (other than trafficType) are forwarded
to Split as evaluation attributes.
await OpenFeatureAPI.instance.setEvaluationContextAndWait(
EvaluationContext(
targetingKey: 'TARGETING_KEY',
attributes: {
'plan': 'premium',
'coupon': 'WELCOME10',
},
),
);
final details = client.getBooleanDetails('bool_flag', false);
Treatment parsing #
The provider maps Split's string treatments to typed OpenFeature values:
| OpenFeature method | Accepted treatments |
|---|---|
getBooleanValue / Details |
'on', 'true' → true; 'off', 'false' → false |
getStringValue / Details |
Any Split treatment string |
getIntegerValue / Details |
Any string parseable by int.tryParse |
getDoubleValue / Details |
Any string parseable by double.tryParse (NaN rejected) |
getStructureValue / Details |
Any JSON object literal (arrays, scalars, null rejected) |
Boolean matching is case-insensitive. Numeric parsing accepts 'Infinity' and
'-Infinity' but rejects 'NaN'. Any treatment that fails to parse surfaces
as an OpenFeature evaluation error with ErrorCode.parseError. A Split
'control' treatment surfaces as ErrorCode.flagNotFound.
Provider events #
The provider emits OpenFeature ProviderEvents driven by the Split SDK
lifecycle:
SDK_READY→ProviderEventType.ready.- Split flag/segment updates →
ProviderEventType.configurationChangedwith the changed flag names inflagsChanged.
final client = OpenFeatureAPI.instance.getClient();
client.addHandler(ProviderEventType.configurationChanged, (details) {
print('Flags changed: ${details.flagsChanged}');
});
Tracking #
track forwards to Split's event tracker. The event name must be non-empty
and the current EvaluationContext MUST carry a non-empty String
trafficType attribute — call setEvaluationContext with a valid
trafficType before invoking track().
await OpenFeatureAPI.instance.setEvaluationContextAndWait(
EvaluationContext(
targetingKey: 'user-123',
// trafficType is REQUIRED for track(); must be a non-empty String.
attributes: {'trafficType': 'account'},
),
);
client.track(
'checkout.completed',
details: TrackingEventDetails(
value: 19.99,
attributes: {'plan': 'pro', 'coupon': 'WELCOME10'},
),
);
TrackingEventDetails.value is a num?; integer values are forwarded to
Split as doubles. attributes on the details is forwarded as Split event
properties.
If trafficType is missing when track() is called, the provider throws
OpenFeatureException(ErrorCode.invalidContext, ...). Note that the
OpenFeature client's track() is fire-and-forget per spec, so it swallows the
exception; the provider also emits a print diagnostic tagged
[split_openfeature_provider] so the refusal is observable in the console.
Reconciling context changes #
Calling OpenFeatureAPI.instance.setEvaluationContextAndWait(newContext) with
a different targetingKey triggers the provider's onContextChanged. The provider
rebinds to a new Split client for the new key, cancels the previous flag
update subscription, waits for the new client to become ready, and emits
ProviderEventType.configurationChanged.
If the new client times out before becoming ready, the future returned by
setEvaluationContextAndWait completes with an OpenFeatureException
(ErrorCode.general, 'Split SDK ready timed out').
Shutting down #
Call shutdown when you're done with the provider (typically only in tests
or in short-lived programs). It cancels the flag update subscription, destroys
the Split factory, and closes the event stream.
await provider.shutdown();
Behavior notes #
trafficTypeis required attrack()time, not evaluation time. Split's client-side evaluation ignorestrafficType, so it is optional on theEvaluationContextforresolve*Valuecalls. Callingtrack()without atrafficTypethrowsOpenFeatureException(ErrorCode.invalidContext, ...)rather than silently defaulting, which would misattribute tracking events across traffic types. Present-but-invalid values (non-String, empty String, whitespace-only String) are rejected at context transform time.- No
ready-from-cache/ no updatetypemetadata. The Split Dart client SDK does not currently expose anSDK_READY_FROM_CACHEequivalent or an update-typefield on flag-change events, so the provider never emitsProviderEventType.staleand theconfigurationChangedevent carries onlyflagsChanged(nometadata['type']).
Platform support #
Pure Dart. Runs everywhere splitio_client_side runs: Dart VM (server, CLI),
Flutter (Android, iOS, Web, Desktop), and browser-compiled Dart. The provider
package contains no dart:html, dart:io, or dart:ffi imports.
OpenFeature specification compliance #
This provider targets the OpenFeature specification v0.9.0. Section 2 (Provider) conformance:
| Clause | Status | Notes |
|---|---|---|
| 2.1.1 metadata name | Yes | metadata.name returns "split". |
| 2.2 flag resolution (all types) | Yes | Boolean / string / integer / double / structure supported. |
| 2.2.5 reason | Yes | Populated as "TARGETING_MATCH" for successful evaluations. |
| 2.2.9 flag metadata | Yes | Raw Split treatment config JSON exposed under flagMetadata['config']. |
| 2.3.1 provider hooks mechanism | Yes | Empty hook list; no provider-managed hooks. |
2.4.1 initialize with domain |
Yes | Signature accepts domain; provider is not domain-scoped. |
| 2.5.1–2.5.3 shutdown | Yes | Idempotent; provider rejects initialize after shutdown. |
2.6.1 onContextChanged |
Yes | Reconciles by rebinding to a new Split client for the new targeting key. |
| 2.7.1 tracking | Yes | track forwards to Split, requires a trafficType attribute. |
| 2.8.1–2.8.4 provider events | Yes | Emits PROVIDER_READY, PROVIDER_ERROR, PROVIDER_CONFIGURATION_CHANGED, and PROVIDER_CONTEXT_CHANGED. |
PROVIDER_STALE |
Not emitted | The Split Dart client SDK does not expose a SDK_READY_FROM_CACHE signal today. |
License #
Licensed under the Apache License, Version 2.0. See Apache License.