Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ jobs:
run: cd splitio_android/; flutter test
- name: Run flutter splitio_ios test
run: cd splitio_ios/; flutter test
- name: Run flutter splitio_web test
run: cd splitio_web/; flutter test --platform=chrome
8 changes: 4 additions & 4 deletions splitio_platform_interface/lib/split_configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ class SplitConfiguration {
///
/// [eventFlushInterval] When using .track, how often the events queue is flushed to Split servers.
///
/// [eventsPerPush] Maximum size of the batch to push events.
/// [eventsPerPush] Maximum size of the batch to push events. Not supported in Web.
///
/// [trafficType] The default traffic type for events tracked using the track method. If not specified, every track call should specify a traffic type.
///
/// [enableDebug] (Deprecated; use logLevel instead) If true, the SDK will log debug messages to the console.
///
/// [streamingEnabled] Boolean flag to enable the streaming service as default synchronization mechanism when in foreground. In the event of an issue with streaming, the SDK will fallback to the polling mechanism. If false, the SDK will poll for changes as usual without attempting to use streaming.
///
/// [persistentAttributesEnabled] Enables saving attributes on persistent cache which is loaded as part of the SDK_READY_FROM_CACHE flow. All functions that mutate the stored attributes map affect the persistent cache.
/// [persistentAttributesEnabled] Enables saving attributes on persistent cache which is loaded as part of the SDK_READY_FROM_CACHE flow. All functions that mutate the stored attributes map affect the persistent cache. Not supported in Web.
///
/// [impressionListener] Enables impression listener. If true, generated impressions will be streamed in the impressionsStream() method of Splitio.
///
Expand All @@ -41,13 +41,13 @@ class SplitConfiguration {
///
/// [userConsent] User consent status used to control the tracking of events and impressions. Possible values are [UserConsent.granted], [UserConsent.declined], and [UserConsent.unknown].
///
/// [encryptionEnabled] If set to true, the local database contents is encrypted. Defaults to false.
/// [encryptionEnabled] If set to true, the local database contents is encrypted. Defaults to false. Not supported in Web.
///
/// [logLevel] Enables logging according to the level specified. Options are [SplitLogLevel.verbose], [SplitLogLevel.none], [SplitLogLevel.debug], [SplitLogLevel.info], [SplitLogLevel.warning], and [SplitLogLevel.error].
///
/// [readyTimeout] Maximum amount of time in seconds to wait before firing the SDK_READY_TIMED_OUT event. Defaults to 10 seconds.
///
/// [certificatePinningConfiguration] Certificate pinning configuration. Pins need to have the format of a base64 SHA-256 or base64 SHA-1 hashes of the SPKI (ex.: "sha256/7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=").
/// [certificatePinningConfiguration] Certificate pinning configuration. Pins need to have the format of a base64 SHA-256 or base64 SHA-1 hashes of the SPKI (ex.: "sha256/7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y="). Not supported in Web.
SplitConfiguration({
int? featuresRefreshRate,
int? segmentsRefreshRate,
Expand Down
215 changes: 206 additions & 9 deletions splitio_web/lib/splitio_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class SplitioWeb extends SplitioPlatform {
Future<void>? _initFuture;

late JS_IBrowserSDK _factory;
String? _trafficType;
bool _impressionListener = false;

@override
Future<void> init({
Expand All @@ -31,7 +33,11 @@ class SplitioWeb extends SplitioPlatform {
SplitConfiguration? sdkConfiguration,
}) async {
if (_initFuture == null) {
_initFuture = this._init(apiKey: apiKey, matchingKey: matchingKey, bucketingKey: bucketingKey, sdkConfiguration: sdkConfiguration);
_initFuture = this._init(
apiKey: apiKey,
matchingKey: matchingKey,
bucketingKey: bucketingKey,
sdkConfiguration: sdkConfiguration);
}
return _initFuture;
}
Expand All @@ -44,10 +50,23 @@ class SplitioWeb extends SplitioPlatform {
}) async {
await _loadSplitSdk();

final config = _buildConfig(apiKey, matchingKey, bucketingKey, sdkConfiguration);
final config =
_buildConfig(apiKey, matchingKey, bucketingKey, sdkConfiguration);

// Create factory instance
this._factory = window.splitio!.SplitFactory.callAsFunction(null, config) as JS_IBrowserSDK;
this._factory = window.splitio!.SplitFactory.callAsFunction(null, config)
as JS_IBrowserSDK;

if (sdkConfiguration != null) {
if (sdkConfiguration.configurationMap['trafficType'] is String) {
this._trafficType = sdkConfiguration.configurationMap['trafficType'];
}

if (sdkConfiguration.configurationMap['impressionListener'] is bool) {
this._impressionListener =
sdkConfiguration.configurationMap['impressionListener'];
}
}

return;
}
Expand Down Expand Up @@ -85,17 +104,195 @@ class SplitioWeb extends SplitioPlatform {
}

// Map SplitConfiguration to JS equivalent object
JSObject _buildConfig(String apiKey, String matchingKey, String? bucketingKey, SplitConfiguration? configuration) {
static JSObject _buildConfig(String apiKey, String matchingKey,
String? bucketingKey, SplitConfiguration? configuration) {
final config = JSObject();

final core = JSObject();
core.setProperty('authorizationKey'.toJS, apiKey.toJS);
// @TODO: set bucketingKey if provided
core.setProperty('key'.toJS, matchingKey.toJS);

final config = JSObject();
core.setProperty('key'.toJS, _buildKey(matchingKey, bucketingKey));
config.setProperty('core'.toJS, core);

// @TODO: complete config
if (configuration != null) {
final scheduler = JSObject();
if (configuration.configurationMap.containsKey('featuresRefreshRate'))
scheduler.setProperty(
'featuresRefreshRate'.toJS,
(configuration.configurationMap['featuresRefreshRate'] as int)
.toJS);
if (configuration.configurationMap.containsKey('segmentsRefreshRate'))
scheduler.setProperty(
'segmentsRefreshRate'.toJS,
(configuration.configurationMap['segmentsRefreshRate'] as int)
.toJS);
if (configuration.configurationMap.containsKey('impressionsRefreshRate'))
scheduler.setProperty(
'impressionsRefreshRate'.toJS,
(configuration.configurationMap['impressionsRefreshRate'] as int)
.toJS);
if (configuration.configurationMap.containsKey('telemetryRefreshRate'))
scheduler.setProperty(
'telemetryRefreshRate'.toJS,
(configuration.configurationMap['telemetryRefreshRate'] as int)
.toJS);
if (configuration.configurationMap.containsKey('eventsQueueSize'))
scheduler.setProperty('eventsQueueSize'.toJS,
(configuration.configurationMap['eventsQueueSize'] as int).toJS);
if (configuration.configurationMap.containsKey('impressionsQueueSize'))
scheduler.setProperty(
'impressionsQueueSize'.toJS,
(configuration.configurationMap['impressionsQueueSize'] as int)
.toJS);
if (configuration.configurationMap.containsKey('eventFlushInterval'))
scheduler.setProperty('eventsPushRate'.toJS,
(configuration.configurationMap['eventFlushInterval'] as int).toJS);
config.setProperty('scheduler'.toJS, scheduler);

if (configuration.configurationMap.containsKey('streamingEnabled'))
config.setProperty('streamingEnabled'.toJS,
(configuration.configurationMap['streamingEnabled'] as bool).toJS);

final urls = JSObject();
if (configuration.configurationMap.containsKey('sdkEndpoint'))
urls.setProperty('sdk'.toJS,
(configuration.configurationMap['sdkEndpoint'] as String).toJS);
if (configuration.configurationMap.containsKey('eventsEndpoint'))
urls.setProperty('events'.toJS,
(configuration.configurationMap['eventsEndpoint'] as String).toJS);
if (configuration.configurationMap.containsKey('authServiceEndpoint'))
urls.setProperty(
'auth'.toJS,
(configuration.configurationMap['authServiceEndpoint'] as String)
.toJS);
if (configuration.configurationMap
.containsKey('streamingServiceEndpoint'))
urls.setProperty(
'streaming'.toJS,
(configuration.configurationMap['streamingServiceEndpoint']
as String)
.toJS);
if (configuration.configurationMap
.containsKey('telemetryServiceEndpoint'))
urls.setProperty(
'telemetry'.toJS,
(configuration.configurationMap['telemetryServiceEndpoint']
as String)
.toJS);
config.setProperty('urls'.toJS, urls);

final sync = JSObject();
if (configuration.configurationMap['impressionsMode'] != null) {
sync.setProperty(
'impressionsMode'.toJS,
(configuration.configurationMap['impressionsMode'] as String)
.toUpperCase()
.toJS);
}

if (configuration.configurationMap['syncEnabled'] != null) {
sync.setProperty('enabled'.toJS,
(configuration.configurationMap['syncEnabled'] as bool).toJS);
}

if (configuration.configurationMap['syncConfig'] != null) {
final syncConfig = configuration.configurationMap['syncConfig']
as Map<String, List<String>>;
final List<Map<String, dynamic>> splitFilters = [];

if (syncConfig['syncConfigNames'] != null &&
syncConfig['syncConfigNames']!.isNotEmpty) {
splitFilters
.add({'type': 'byName', 'values': syncConfig['syncConfigNames']});
}

if (syncConfig['syncConfigPrefixes'] != null &&
syncConfig['syncConfigPrefixes']!.isNotEmpty) {
splitFilters.add(
{'type': 'byPrefix', 'values': syncConfig['syncConfigPrefixes']});
}

if (syncConfig['syncConfigFlagSets'] != null &&
syncConfig['syncConfigFlagSets']!.isNotEmpty) {
splitFilters.add(
{'type': 'bySet', 'values': syncConfig['syncConfigFlagSets']});
}
sync.setProperty('splitFilters'.toJS, splitFilters.jsify());
}
config.setProperty('sync'.toJS, sync);

if (configuration.configurationMap['userConsent'] != null) {
config.setProperty(
'userConsent'.toJS,
(configuration.configurationMap['userConsent'] as String)
.toUpperCase()
.toJS);
}

final logLevel = configuration.configurationMap['logLevel'];
if (logLevel is String) {
final logger = logLevel == SplitLogLevel.verbose.toString() ||
logLevel == SplitLogLevel.debug.toString()
? window.splitio!.DebugLogger?.callAsFunction(null)
: logLevel == SplitLogLevel.info.toString()
? window.splitio!.InfoLogger?.callAsFunction(null)
: logLevel == SplitLogLevel.warning.toString()
? window.splitio!.WarnLogger?.callAsFunction(null)
: logLevel == SplitLogLevel.error.toString()
? window.splitio!.ErrorLogger?.callAsFunction(null)
: null;
if (logger != null) {
config.setProperty('debug'.toJS, logger); // Browser SDK
} else {
config.setProperty(
'debug'.toJS, logLevel.toUpperCase().toJS); // JS SDK
}
} else if (configuration.configurationMap['enableDebug'] == true) {
config.setProperty(
'debug'.toJS, window.splitio!.DebugLogger?.callAsFunction(null));
}

if (configuration.configurationMap['readyTimeout'] != null) {
final startup = JSObject();
startup.setProperty('readyTimeout'.toJS,
(configuration.configurationMap['readyTimeout'] as int).toJS);
config.setProperty('startup'.toJS, startup);
}

final storageOptions = JSObject();
storageOptions.setProperty('type'.toJS, 'LOCALSTORAGE'.toJS);
if (configuration.configurationMap['rolloutCacheConfiguration'] != null) {
final rolloutCacheConfiguration =
configuration.configurationMap['rolloutCacheConfiguration']
as Map<String, dynamic>;
if (rolloutCacheConfiguration['expirationDays'] != null) {
storageOptions.setProperty('expirationDays'.toJS,
(rolloutCacheConfiguration['expirationDays'] as int).toJS);
}
if (rolloutCacheConfiguration['clearOnInit'] != null) {
storageOptions.setProperty('clearOnInit'.toJS,
(rolloutCacheConfiguration['clearOnInit'] as bool).toJS);
}
}
if (window.splitio!.InLocalStorage != null) {
config.setProperty(
'storage'.toJS,
window.splitio!.InLocalStorage
?.callAsFunction(null, storageOptions)); // Browser SDK
} else {
config.setProperty('storage'.toJS, storageOptions); // JS SDK
}
}

return config;
}

static JSAny _buildKey(String matchingKey, String? bucketingKey) {
if (bucketingKey != null) {
final splitKey = JSObject();
splitKey.setProperty('matchingKey'.toJS, matchingKey.toJS);
splitKey.setProperty('bucketingKey'.toJS, bucketingKey.toJS);
return splitKey;
}
return matchingKey.toJS;
}
}
8 changes: 7 additions & 1 deletion splitio_web/lib/src/js_interop.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import 'dart:js_interop';

@JS()
extension type JS_IBrowserSDK._(JSObject _) implements JSObject {}
extension type JS_IBrowserSDK._(JSObject _) implements JSObject {
}

@JS()
extension type JS_BrowserSDKPackage._(JSObject _) implements JSObject {
external JSFunction SplitFactory;
external JSFunction? InLocalStorage;
external JSFunction? DebugLogger;
external JSFunction? InfoLogger;
external JSFunction? WarnLogger;
external JSFunction? ErrorLogger;
}
Loading