@splitsoftware/splitio-commons 2.1.0 → 2.1.1-rc.1

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.
Files changed (77) hide show
  1. package/CHANGES.txt +3 -0
  2. package/cjs/logger/constants.js +4 -6
  3. package/cjs/logger/messages/debug.js +1 -3
  4. package/cjs/logger/messages/error.js +1 -1
  5. package/cjs/logger/messages/warn.js +1 -1
  6. package/cjs/sdkClient/client.js +29 -19
  7. package/cjs/sdkClient/clientAttributesDecoration.js +19 -25
  8. package/cjs/sdkClient/clientInputValidation.js +28 -26
  9. package/cjs/storages/AbstractSplitsCacheAsync.js +12 -1
  10. package/cjs/storages/AbstractSplitsCacheSync.js +5 -7
  11. package/cjs/storages/KeyBuilder.js +0 -16
  12. package/cjs/storages/KeyBuilderCS.js +8 -2
  13. package/cjs/storages/dataLoader.js +1 -2
  14. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +5 -2
  15. package/cjs/storages/inMemory/SplitsCacheInMemory.js +24 -31
  16. package/cjs/storages/inRedis/SplitsCacheInRedis.js +4 -21
  17. package/cjs/storages/pluggable/SplitsCachePluggable.js +2 -19
  18. package/cjs/storages/utils.js +1 -0
  19. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +12 -13
  20. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  21. package/cjs/sync/polling/updaters/splitChangesUpdater.js +9 -23
  22. package/cjs/sync/submitters/impressionsSubmitter.js +3 -2
  23. package/cjs/trackers/strategy/strategyOptimized.js +3 -0
  24. package/cjs/utils/inputValidation/eventProperties.js +12 -1
  25. package/cjs/utils/inputValidation/index.js +3 -1
  26. package/esm/logger/constants.js +1 -3
  27. package/esm/logger/messages/debug.js +1 -3
  28. package/esm/logger/messages/error.js +1 -1
  29. package/esm/logger/messages/warn.js +1 -1
  30. package/esm/sdkClient/client.js +29 -19
  31. package/esm/sdkClient/clientAttributesDecoration.js +19 -25
  32. package/esm/sdkClient/clientInputValidation.js +29 -27
  33. package/esm/storages/AbstractSplitsCacheAsync.js +12 -1
  34. package/esm/storages/AbstractSplitsCacheSync.js +5 -7
  35. package/esm/storages/KeyBuilder.js +0 -16
  36. package/esm/storages/KeyBuilderCS.js +8 -2
  37. package/esm/storages/dataLoader.js +1 -2
  38. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -2
  39. package/esm/storages/inMemory/SplitsCacheInMemory.js +24 -31
  40. package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -21
  41. package/esm/storages/pluggable/SplitsCachePluggable.js +2 -19
  42. package/esm/storages/utils.js +1 -0
  43. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +12 -13
  44. package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  45. package/esm/sync/polling/updaters/splitChangesUpdater.js +10 -24
  46. package/esm/sync/submitters/impressionsSubmitter.js +3 -2
  47. package/esm/trackers/strategy/strategyOptimized.js +3 -0
  48. package/esm/utils/inputValidation/eventProperties.js +10 -0
  49. package/esm/utils/inputValidation/index.js +1 -0
  50. package/package.json +1 -1
  51. package/src/logger/constants.ts +1 -3
  52. package/src/logger/messages/debug.ts +1 -3
  53. package/src/logger/messages/error.ts +1 -1
  54. package/src/logger/messages/warn.ts +1 -1
  55. package/src/sdkClient/client.ts +31 -21
  56. package/src/sdkClient/clientAttributesDecoration.ts +20 -27
  57. package/src/sdkClient/clientInputValidation.ts +30 -27
  58. package/src/storages/AbstractSplitsCacheAsync.ts +15 -5
  59. package/src/storages/AbstractSplitsCacheSync.ts +9 -13
  60. package/src/storages/KeyBuilder.ts +0 -20
  61. package/src/storages/KeyBuilderCS.ts +10 -3
  62. package/src/storages/dataLoader.ts +1 -2
  63. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +5 -2
  64. package/src/storages/inMemory/SplitsCacheInMemory.ts +22 -27
  65. package/src/storages/inRedis/SplitsCacheInRedis.ts +4 -21
  66. package/src/storages/pluggable/SplitsCachePluggable.ts +2 -19
  67. package/src/storages/types.ts +10 -16
  68. package/src/storages/utils.ts +1 -0
  69. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +14 -15
  70. package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -2
  71. package/src/sync/polling/updaters/splitChangesUpdater.ts +12 -27
  72. package/src/sync/submitters/impressionsSubmitter.ts +3 -2
  73. package/src/sync/submitters/types.ts +23 -33
  74. package/src/trackers/strategy/strategyOptimized.ts +3 -0
  75. package/src/utils/inputValidation/eventProperties.ts +10 -0
  76. package/src/utils/inputValidation/index.ts +1 -0
  77. package/types/splitio.d.ts +100 -35
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "2.1.0",
3
+ "version": "2.1.1-rc.1",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -20,9 +20,7 @@ export const RETRIEVE_CLIENT_EXISTING = 28;
20
20
  export const RETRIEVE_MANAGER = 29;
21
21
  export const SYNC_OFFLINE_DATA = 30;
22
22
  export const SYNC_SPLITS_FETCH = 31;
23
- export const SYNC_SPLITS_NEW = 32;
24
- export const SYNC_SPLITS_REMOVED = 33;
25
- export const SYNC_SPLITS_SEGMENTS = 34;
23
+ export const SYNC_SPLITS_UPDATE = 32;
26
24
  export const STREAMING_NEW_MESSAGE = 35;
27
25
  export const SYNC_TASK_START = 36;
28
26
  export const SYNC_TASK_EXECUTE = 37;
@@ -21,9 +21,7 @@ export const codesDebug: [number, string][] = codesInfo.concat([
21
21
  // synchronizer
22
22
  [c.SYNC_OFFLINE_DATA, c.LOG_PREFIX_SYNC_OFFLINE + 'Feature flags data: \n%s'],
23
23
  [c.SYNC_SPLITS_FETCH, c.LOG_PREFIX_SYNC_SPLITS + 'Spin up feature flags update using since = %s'],
24
- [c.SYNC_SPLITS_NEW, c.LOG_PREFIX_SYNC_SPLITS + 'New feature flags %s'],
25
- [c.SYNC_SPLITS_REMOVED, c.LOG_PREFIX_SYNC_SPLITS + 'Removed feature flags %s'],
26
- [c.SYNC_SPLITS_SEGMENTS, c.LOG_PREFIX_SYNC_SPLITS + 'Segment names collected %s'],
24
+ [c.SYNC_SPLITS_UPDATE, c.LOG_PREFIX_SYNC_SPLITS + 'New feature flags %s. Removed feature flags %s. Segment names collected %s'],
27
25
  [c.STREAMING_NEW_MESSAGE, c.LOG_PREFIX_SYNC_STREAMING + 'New SSE message received, with data: %s.'],
28
26
  [c.SYNC_TASK_START, c.LOG_PREFIX_SYNC + ': Starting %s. Running each %s millis'],
29
27
  [c.SYNC_TASK_EXECUTE, c.LOG_PREFIX_SYNC + ': Running %s'],
@@ -21,7 +21,7 @@ export const codesError: [number, string][] = [
21
21
  // input validation
22
22
  [c.ERROR_EVENT_TYPE_FORMAT, '%s: you passed "%s", event_type must adhere to the regular expression /^[a-zA-Z0-9][-_.:a-zA-Z0-9]{0,79}$/g. This means an event_type must be alphanumeric, cannot be more than 80 characters long, and can only include a dash, underscore, period, or colon as separators of alphanumeric characters.'],
23
23
  [c.ERROR_NOT_PLAIN_OBJECT, '%s: %s must be a plain object.'],
24
- [c.ERROR_SIZE_EXCEEDED, '%s: the maximum size allowed for the properties is 32768 bytes, which was exceeded. Event not queued.'],
24
+ [c.ERROR_SIZE_EXCEEDED, '%s: the maximum size allowed for the properties is 32768 bytes, which was exceeded.'],
25
25
  [c.ERROR_NOT_FINITE, '%s: value must be a finite number.'],
26
26
  [c.ERROR_NULL, '%s: you passed a null or undefined %s. It must be a non-empty string.'],
27
27
  [c.ERROR_TOO_LONG, '%s: %s too long. It must have 250 characters or less.'],
@@ -18,7 +18,7 @@ export const codesWarn: [number, string][] = codesError.concat([
18
18
  [c.CLIENT_NO_LISTENER, 'No listeners for SDK Readiness detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet ready.'],
19
19
  // input validation
20
20
  [c.WARN_SETTING_NULL, '%s: Property "%s" is of invalid type. Setting value to null.'],
21
- [c.WARN_TRIMMING_PROPERTIES, '%s: Event has more than 300 properties. Some of them will be trimmed when processed.'],
21
+ [c.WARN_TRIMMING_PROPERTIES, '%s: more than 300 properties were provided. Some of them will be trimmed when processed.'],
22
22
  [c.WARN_CONVERTING, '%s: %s "%s" is not of type string, converting.'],
23
23
  [c.WARN_TRIMMING, '%s: %s "%s" has extra whitespace, trimming.'],
24
24
  [c.WARN_NOT_EXISTENT_SPLIT, '%s: feature flag "%s" does not exist in this environment. Please double check what feature flags exist in the Split user interface.'],
@@ -23,6 +23,14 @@ function treatmentsNotReady(featureFlagNames: string[]) {
23
23
  return evaluations;
24
24
  }
25
25
 
26
+ function stringify(options?: SplitIO.EvaluationOptions) {
27
+ if (options && options.properties) {
28
+ try {
29
+ return JSON.stringify(options.properties);
30
+ } catch { /* JSON.stringify should never throw with validated options, but handling just in case */ }
31
+ }
32
+ }
33
+
26
34
  /**
27
35
  * Creator of base client with getTreatments and track methods.
28
36
  */
@@ -31,12 +39,12 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
31
39
  const { log, mode } = settings;
32
40
  const isAsync = isConsumerMode(mode);
33
41
 
34
- function getTreatment(key: SplitIO.SplitKey, featureFlagName: string, attributes: SplitIO.Attributes | undefined, withConfig = false, methodName = GET_TREATMENT) {
42
+ function getTreatment(key: SplitIO.SplitKey, featureFlagName: string, attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, methodName = GET_TREATMENT) {
35
43
  const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENT_WITH_CONFIG : TREATMENT);
36
44
 
37
45
  const wrapUp = (evaluationResult: IEvaluationResult) => {
38
46
  const queue: ImpressionDecorated[] = [];
39
- const treatment = processEvaluation(evaluationResult, featureFlagName, key, attributes, withConfig, methodName, queue);
47
+ const treatment = processEvaluation(evaluationResult, featureFlagName, key, stringify(options), withConfig, methodName, queue);
40
48
  impressionsTracker.track(queue, attributes);
41
49
 
42
50
  stopTelemetryTracker(queue[0] && queue[0].imp.label);
@@ -52,18 +60,19 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
52
60
  return thenable(evaluation) ? evaluation.then((res) => wrapUp(res)) : wrapUp(evaluation);
53
61
  }
54
62
 
55
- function getTreatmentWithConfig(key: SplitIO.SplitKey, featureFlagName: string, attributes: SplitIO.Attributes | undefined) {
56
- return getTreatment(key, featureFlagName, attributes, true, GET_TREATMENT_WITH_CONFIG);
63
+ function getTreatmentWithConfig(key: SplitIO.SplitKey, featureFlagName: string, attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions) {
64
+ return getTreatment(key, featureFlagName, attributes, options, true, GET_TREATMENT_WITH_CONFIG);
57
65
  }
58
66
 
59
- function getTreatments(key: SplitIO.SplitKey, featureFlagNames: string[], attributes: SplitIO.Attributes | undefined, withConfig = false, methodName = GET_TREATMENTS) {
67
+ function getTreatments(key: SplitIO.SplitKey, featureFlagNames: string[], attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, methodName = GET_TREATMENTS) {
60
68
  const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENTS_WITH_CONFIG : TREATMENTS);
61
69
 
62
70
  const wrapUp = (evaluationResults: Record<string, IEvaluationResult>) => {
63
71
  const queue: ImpressionDecorated[] = [];
64
- const treatments: Record<string, SplitIO.Treatment | SplitIO.TreatmentWithConfig> = {};
72
+ const treatments: SplitIO.Treatments | SplitIO.TreatmentsWithConfig = {};
73
+ const properties = stringify(options);
65
74
  Object.keys(evaluationResults).forEach(featureFlagName => {
66
- treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
75
+ treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, properties, withConfig, methodName, queue);
67
76
  });
68
77
  impressionsTracker.track(queue, attributes);
69
78
 
@@ -80,19 +89,19 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
80
89
  return thenable(evaluations) ? evaluations.then((res) => wrapUp(res)) : wrapUp(evaluations);
81
90
  }
82
91
 
83
- function getTreatmentsWithConfig(key: SplitIO.SplitKey, featureFlagNames: string[], attributes: SplitIO.Attributes | undefined) {
84
- return getTreatments(key, featureFlagNames, attributes, true, GET_TREATMENTS_WITH_CONFIG);
92
+ function getTreatmentsWithConfig(key: SplitIO.SplitKey, featureFlagNames: string[], attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions) {
93
+ return getTreatments(key, featureFlagNames, attributes, options, true, GET_TREATMENTS_WITH_CONFIG);
85
94
  }
86
95
 
87
- function getTreatmentsByFlagSets(key: SplitIO.SplitKey, flagSetNames: string[], attributes: SplitIO.Attributes | undefined, withConfig = false, method: Method = TREATMENTS_BY_FLAGSETS, methodName = GET_TREATMENTS_BY_FLAG_SETS) {
96
+ function getTreatmentsByFlagSets(key: SplitIO.SplitKey, flagSetNames: string[], attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, method: Method = TREATMENTS_BY_FLAGSETS, methodName = GET_TREATMENTS_BY_FLAG_SETS) {
88
97
  const stopTelemetryTracker = telemetryTracker.trackEval(method);
89
98
 
90
99
  const wrapUp = (evaluationResults: Record<string, IEvaluationResult>) => {
91
100
  const queue: ImpressionDecorated[] = [];
92
- const treatments: Record<string, SplitIO.Treatment | SplitIO.TreatmentWithConfig> = {};
93
- const evaluations = evaluationResults;
94
- Object.keys(evaluations).forEach(featureFlagName => {
95
- treatments[featureFlagName] = processEvaluation(evaluations[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
101
+ const treatments: SplitIO.Treatments | SplitIO.TreatmentsWithConfig = {};
102
+ const properties = stringify(options);
103
+ Object.keys(evaluationResults).forEach(featureFlagName => {
104
+ treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, properties, withConfig, methodName, queue);
96
105
  });
97
106
  impressionsTracker.track(queue, attributes);
98
107
 
@@ -109,16 +118,16 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
109
118
  return thenable(evaluations) ? evaluations.then((res) => wrapUp(res)) : wrapUp(evaluations);
110
119
  }
111
120
 
112
- function getTreatmentsWithConfigByFlagSets(key: SplitIO.SplitKey, flagSetNames: string[], attributes: SplitIO.Attributes | undefined) {
113
- return getTreatmentsByFlagSets(key, flagSetNames, attributes, true, TREATMENTS_WITH_CONFIG_BY_FLAGSETS, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS);
121
+ function getTreatmentsWithConfigByFlagSets(key: SplitIO.SplitKey, flagSetNames: string[], attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions) {
122
+ return getTreatmentsByFlagSets(key, flagSetNames, attributes, options, true, TREATMENTS_WITH_CONFIG_BY_FLAGSETS, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS);
114
123
  }
115
124
 
116
- function getTreatmentsByFlagSet(key: SplitIO.SplitKey, flagSetName: string, attributes: SplitIO.Attributes | undefined) {
117
- return getTreatmentsByFlagSets(key, [flagSetName], attributes, false, TREATMENTS_BY_FLAGSET, GET_TREATMENTS_BY_FLAG_SET);
125
+ function getTreatmentsByFlagSet(key: SplitIO.SplitKey, flagSetName: string, attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions) {
126
+ return getTreatmentsByFlagSets(key, [flagSetName], attributes, options, false, TREATMENTS_BY_FLAGSET, GET_TREATMENTS_BY_FLAG_SET);
118
127
  }
119
128
 
120
- function getTreatmentsWithConfigByFlagSet(key: SplitIO.SplitKey, flagSetName: string, attributes: SplitIO.Attributes | undefined) {
121
- return getTreatmentsByFlagSets(key, [flagSetName], attributes, true, TREATMENTS_WITH_CONFIG_BY_FLAGSET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
129
+ function getTreatmentsWithConfigByFlagSet(key: SplitIO.SplitKey, flagSetName: string, attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions) {
130
+ return getTreatmentsByFlagSets(key, [flagSetName], attributes, options, true, TREATMENTS_WITH_CONFIG_BY_FLAGSET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
122
131
  }
123
132
 
124
133
  // Internal function
@@ -126,7 +135,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
126
135
  evaluation: IEvaluationResult,
127
136
  featureFlagName: string,
128
137
  key: SplitIO.SplitKey,
129
- attributes: SplitIO.Attributes | undefined,
138
+ properties: string | undefined,
130
139
  withConfig: boolean,
131
140
  invokingMethodName: string,
132
141
  queue: ImpressionDecorated[]
@@ -148,6 +157,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
148
157
  bucketingKey,
149
158
  label,
150
159
  changeNumber: changeNumber as number,
160
+ properties
151
161
  },
152
162
  disabled: impressionsDisabled
153
163
  });
@@ -20,50 +20,44 @@ export function clientAttributesDecoration<TClient extends SplitIO.IClient | Spl
20
20
  const clientGetTreatmentsWithConfigByFlagSets = client.getTreatmentsWithConfigByFlagSets;
21
21
  const clientGetTreatmentsByFlagSet = client.getTreatmentsByFlagSet;
22
22
  const clientGetTreatmentsWithConfigByFlagSet = client.getTreatmentsWithConfigByFlagSet;
23
- const clientTrack = client.track;
24
23
 
25
- function getTreatment(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes) {
26
- return clientGetTreatment(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes));
24
+ function getTreatment(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
25
+ return clientGetTreatment(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes), maybeOptions);
27
26
  }
28
27
 
29
- function getTreatmentWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes) {
30
- return clientGetTreatmentWithConfig(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes));
28
+ function getTreatmentWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
29
+ return clientGetTreatmentWithConfig(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes), maybeOptions);
31
30
  }
32
31
 
33
- function getTreatments(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes) {
34
- return clientGetTreatments(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes));
32
+ function getTreatments(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
33
+ return clientGetTreatments(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes), maybeOptions);
35
34
  }
36
35
 
37
- function getTreatmentsWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes) {
38
- return clientGetTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes));
36
+ function getTreatmentsWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
37
+ return clientGetTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes), maybeOptions);
39
38
  }
40
39
 
41
- function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
42
- return clientGetTreatmentsByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes));
40
+ function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
41
+ return clientGetTreatmentsByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes), maybeOptions);
43
42
  }
44
43
 
45
- function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
46
- return clientGetTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes));
44
+ function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
45
+ return clientGetTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes), maybeOptions);
47
46
  }
48
47
 
49
- function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
50
- return clientGetTreatmentsByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes));
48
+ function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
49
+ return clientGetTreatmentsByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes), maybeOptions);
51
50
  }
52
51
 
53
- function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
54
- return clientGetTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes));
52
+ function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
53
+ return clientGetTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes), maybeOptions);
55
54
  }
56
55
 
57
- function track(maybeKey: SplitIO.SplitKey, maybeTT: string, maybeEvent: string, maybeEventValue?: number, maybeProperties?: SplitIO.Properties) {
58
- return clientTrack(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties);
59
- }
60
-
61
- function combineAttributes(maybeAttributes: SplitIO.Attributes | undefined): SplitIO.Attributes | undefined{
56
+ function combineAttributes(maybeAttributes: SplitIO.Attributes | undefined): SplitIO.Attributes | undefined {
62
57
  const storedAttributes = attributeStorage.getAll();
63
- if (Object.keys(storedAttributes).length > 0) {
64
- return objectAssign({}, storedAttributes, maybeAttributes);
65
- }
66
- return maybeAttributes;
58
+ return Object.keys(storedAttributes).length > 0 ?
59
+ objectAssign({}, storedAttributes, maybeAttributes) :
60
+ maybeAttributes;
67
61
  }
68
62
 
69
63
  return objectAssign(client, {
@@ -75,7 +69,6 @@ export function clientAttributesDecoration<TClient extends SplitIO.IClient | Spl
75
69
  getTreatmentsWithConfigByFlagSets: getTreatmentsWithConfigByFlagSets,
76
70
  getTreatmentsByFlagSet: getTreatmentsByFlagSet,
77
71
  getTreatmentsWithConfigByFlagSet: getTreatmentsWithConfigByFlagSet,
78
- track: track,
79
72
 
80
73
  /**
81
74
  * Add an attribute to client's in memory attributes storage
@@ -9,7 +9,8 @@ import {
9
9
  validateSplits,
10
10
  validateTrafficType,
11
11
  validateIfNotDestroyed,
12
- validateIfOperational
12
+ validateIfOperational,
13
+ validateEvaluationOptions
13
14
  } from '../utils/inputValidation';
14
15
  import { startsWith } from '../utils/lang';
15
16
  import { CONTROL, CONTROL_WITH_CONFIG, GET_TREATMENT, GET_TREATMENTS, GET_TREATMENTS_BY_FLAG_SET, GET_TREATMENTS_BY_FLAG_SETS, GET_TREATMENTS_WITH_CONFIG, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, GET_TREATMENT_WITH_CONFIG, TRACK_FN_LABEL } from '../utils/constants';
@@ -32,7 +33,7 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
32
33
  /**
33
34
  * Avoid repeating this validations code
34
35
  */
35
- function validateEvaluationParams(maybeKey: SplitIO.SplitKey, maybeNameOrNames: string | string[], maybeAttributes: SplitIO.Attributes | undefined, methodName: string) {
36
+ function validateEvaluationParams(methodName: string, maybeKey: SplitIO.SplitKey, maybeNameOrNames: string | string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
36
37
  const key = validateKey(log, maybeKey, methodName);
37
38
 
38
39
  const nameOrNames = methodName.indexOf('ByFlagSet') > -1 ?
@@ -43,6 +44,7 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
43
44
 
44
45
  const attributes = validateAttributes(log, maybeAttributes, methodName);
45
46
  const isNotDestroyed = validateIfNotDestroyed(log, readinessManager, methodName);
47
+ const options = validateEvaluationOptions(log, maybeOptions, methodName);
46
48
 
47
49
  validateIfOperational(log, readinessManager, methodName, nameOrNames);
48
50
 
@@ -52,7 +54,8 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
52
54
  valid,
53
55
  key,
54
56
  nameOrNames,
55
- attributes
57
+ attributes,
58
+ options
56
59
  };
57
60
  }
58
61
 
@@ -60,31 +63,31 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
60
63
  return isAsync ? Promise.resolve(value) : value;
61
64
  }
62
65
 
63
- function getTreatment(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes) {
64
- const params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes, GET_TREATMENT);
66
+ function getTreatment(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
67
+ const params = validateEvaluationParams(GET_TREATMENT, maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions);
65
68
 
66
69
  if (params.valid) {
67
- return client.getTreatment(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined);
70
+ return client.getTreatment(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined, params.options);
68
71
  } else {
69
72
  return wrapResult(CONTROL);
70
73
  }
71
74
  }
72
75
 
73
- function getTreatmentWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes) {
74
- const params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes, GET_TREATMENT_WITH_CONFIG);
76
+ function getTreatmentWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
77
+ const params = validateEvaluationParams(GET_TREATMENT_WITH_CONFIG, maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions);
75
78
 
76
79
  if (params.valid) {
77
- return client.getTreatmentWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined);
80
+ return client.getTreatmentWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined, params.options);
78
81
  } else {
79
82
  return wrapResult(objectAssign({}, CONTROL_WITH_CONFIG));
80
83
  }
81
84
  }
82
85
 
83
- function getTreatments(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes) {
84
- const params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes, GET_TREATMENTS);
86
+ function getTreatments(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
87
+ const params = validateEvaluationParams(GET_TREATMENTS, maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions);
85
88
 
86
89
  if (params.valid) {
87
- return client.getTreatments(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined);
90
+ return client.getTreatments(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
88
91
  } else {
89
92
  const res: SplitIO.Treatments = {};
90
93
  if (params.nameOrNames) (params.nameOrNames as string[]).forEach((split: string) => res[split] = CONTROL);
@@ -93,11 +96,11 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
93
96
  }
94
97
  }
95
98
 
96
- function getTreatmentsWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes) {
97
- const params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes, GET_TREATMENTS_WITH_CONFIG);
99
+ function getTreatmentsWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
100
+ const params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG, maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions);
98
101
 
99
102
  if (params.valid) {
100
- return client.getTreatmentsWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined);
103
+ return client.getTreatmentsWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
101
104
  } else {
102
105
  const res: SplitIO.TreatmentsWithConfig = {};
103
106
  if (params.nameOrNames) (params.nameOrNames as string[]).forEach(split => res[split] = objectAssign({}, CONTROL_WITH_CONFIG));
@@ -106,41 +109,41 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
106
109
  }
107
110
  }
108
111
 
109
- function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
110
- const params = validateEvaluationParams(maybeKey, maybeFlagSets, maybeAttributes, GET_TREATMENTS_BY_FLAG_SETS);
112
+ function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
113
+ const params = validateEvaluationParams(GET_TREATMENTS_BY_FLAG_SETS, maybeKey, maybeFlagSets, maybeAttributes, maybeOptions);
111
114
 
112
115
  if (params.valid) {
113
- return client.getTreatmentsByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined);
116
+ return client.getTreatmentsByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
114
117
  } else {
115
118
  return wrapResult({});
116
119
  }
117
120
  }
118
121
 
119
- function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
120
- const params = validateEvaluationParams(maybeKey, maybeFlagSets, maybeAttributes, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS);
122
+ function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
123
+ const params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, maybeKey, maybeFlagSets, maybeAttributes, maybeOptions);
121
124
 
122
125
  if (params.valid) {
123
- return client.getTreatmentsWithConfigByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined);
126
+ return client.getTreatmentsWithConfigByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
124
127
  } else {
125
128
  return wrapResult({});
126
129
  }
127
130
  }
128
131
 
129
- function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
130
- const params = validateEvaluationParams(maybeKey, [maybeFlagSet], maybeAttributes, GET_TREATMENTS_BY_FLAG_SET);
132
+ function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
133
+ const params = validateEvaluationParams(GET_TREATMENTS_BY_FLAG_SET, maybeKey, [maybeFlagSet], maybeAttributes, maybeOptions);
131
134
 
132
135
  if (params.valid) {
133
- return client.getTreatmentsByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined);
136
+ return client.getTreatmentsByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined, params.options);
134
137
  } else {
135
138
  return wrapResult({});
136
139
  }
137
140
  }
138
141
 
139
- function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
140
- const params = validateEvaluationParams(maybeKey, [maybeFlagSet], maybeAttributes, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
142
+ function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
143
+ const params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, maybeKey, [maybeFlagSet], maybeAttributes, maybeOptions);
141
144
 
142
145
  if (params.valid) {
143
- return client.getTreatmentsWithConfigByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined);
146
+ return client.getTreatmentsWithConfigByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined, params.options);
144
147
  } else {
145
148
  return wrapResult({});
146
149
  }
@@ -8,12 +8,22 @@ import { objectAssign } from '../utils/lang/objectAssign';
8
8
  */
9
9
  export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
10
10
 
11
- abstract addSplit(name: string, split: ISplit): Promise<boolean>
12
- abstract addSplits(entries: [string, ISplit][]): Promise<boolean[] | void>
13
- abstract removeSplits(names: string[]): Promise<boolean[] | void>
11
+ protected abstract addSplit(split: ISplit): Promise<boolean>
12
+ protected abstract removeSplit(name: string): Promise<boolean>
13
+ protected abstract setChangeNumber(changeNumber: number): Promise<boolean | void>
14
+
15
+ update(toAdd: ISplit[], toRemove: ISplit[], changeNumber: number): Promise<boolean> {
16
+ return Promise.all([
17
+ this.setChangeNumber(changeNumber),
18
+ Promise.all(toAdd.map(addedFF => this.addSplit(addedFF))),
19
+ Promise.all(toRemove.map(removedFF => this.removeSplit(removedFF.name)))
20
+ ]).then(([, added, removed]) => {
21
+ return added.some(result => result) || removed.some(result => result);
22
+ });
23
+ }
24
+
14
25
  abstract getSplit(name: string): Promise<ISplit | null>
15
26
  abstract getSplits(names: string[]): Promise<Record<string, ISplit | null>>
16
- abstract setChangeNumber(changeNumber: number): Promise<boolean | void>
17
27
  abstract getChangeNumber(): Promise<number>
18
28
  abstract getAll(): Promise<ISplit[]>
19
29
  abstract getSplitNames(): Promise<string[]>
@@ -52,7 +62,7 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
52
62
  newSplit.defaultTreatment = defaultTreatment;
53
63
  newSplit.changeNumber = changeNumber;
54
64
 
55
- return this.addSplit(name, newSplit);
65
+ return this.addSplit(newSplit);
56
66
  }
57
67
  return false;
58
68
  }).catch(() => false);
@@ -9,16 +9,14 @@ import { IN_SEGMENT, IN_LARGE_SEGMENT } from '../utils/constants';
9
9
  */
10
10
  export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
11
11
 
12
- abstract addSplit(name: string, split: ISplit): boolean
13
-
14
- addSplits(entries: [string, ISplit][]): boolean[] {
15
- return entries.map(keyValuePair => this.addSplit(keyValuePair[0], keyValuePair[1]));
16
- }
17
-
18
- abstract removeSplit(name: string): boolean
19
-
20
- removeSplits(names: string[]): boolean[] {
21
- return names.map(name => this.removeSplit(name));
12
+ protected abstract addSplit(split: ISplit): boolean
13
+ protected abstract removeSplit(name: string): boolean
14
+ protected abstract setChangeNumber(changeNumber: number): boolean | void
15
+
16
+ update(toAdd: ISplit[], toRemove: ISplit[], changeNumber: number): boolean {
17
+ this.setChangeNumber(changeNumber);
18
+ const updated = toAdd.map(addedFF => this.addSplit(addedFF)).some(result => result);
19
+ return toRemove.map(removedFF => this.removeSplit(removedFF.name)).some(result => result) || updated;
22
20
  }
23
21
 
24
22
  abstract getSplit(name: string): ISplit | null
@@ -31,8 +29,6 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
31
29
  return splits;
32
30
  }
33
31
 
34
- abstract setChangeNumber(changeNumber: number): boolean | void
35
-
36
32
  abstract getChangeNumber(): number
37
33
 
38
34
  getAll(): ISplit[] {
@@ -71,7 +67,7 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
71
67
  newSplit.defaultTreatment = defaultTreatment;
72
68
  newSplit.changeNumber = changeNumber;
73
69
 
74
- return this.addSplit(name, newSplit);
70
+ return this.addSplit(newSplit);
75
71
  }
76
72
  return false;
77
73
  }
@@ -1,5 +1,4 @@
1
1
  import { ISettings } from '../types';
2
- import { startsWith } from '../utils/lang';
3
2
  import { hash } from '../utils/murmur3/murmur3';
4
3
 
5
4
  const everythingAtTheEnd = /[^.]+$/;
@@ -34,24 +33,10 @@ export class KeyBuilder {
34
33
  return `${this.prefix}.splits.till`;
35
34
  }
36
35
 
37
- // NOT USED
38
- // buildSplitsReady() {
39
- // return `${this.prefix}.splits.ready`;
40
- // }
41
-
42
- isSplitKey(key: string) {
43
- return startsWith(key, `${this.prefix}.split.`);
44
- }
45
-
46
36
  buildSplitKeyPrefix() {
47
37
  return `${this.prefix}.split.`;
48
38
  }
49
39
 
50
- // Only used by InLocalStorage.
51
- buildSplitsWithSegmentCountKey() {
52
- return `${this.prefix}.splits.usingSegments`;
53
- }
54
-
55
40
  buildSegmentNameKey(segmentName: string) {
56
41
  return `${this.prefix}.segment.${segmentName}`;
57
42
  }
@@ -60,11 +45,6 @@ export class KeyBuilder {
60
45
  return `${this.prefix}.segment.${segmentName}.till`;
61
46
  }
62
47
 
63
- // NOT USED
64
- // buildSegmentsReady() {
65
- // return `${this.prefix}.segments.ready`;
66
- // }
67
-
68
48
  extractKey(builtKey: string) {
69
49
  const s = builtKey.match(everythingAtTheEnd);
70
50
 
@@ -28,8 +28,7 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
28
28
  extractSegmentName(builtSegmentKeyName: string) {
29
29
  const prefix = `${this.prefix}.${this.matchingKey}.segment.`;
30
30
 
31
- if (startsWith(builtSegmentKeyName, prefix))
32
- return builtSegmentKeyName.substr(prefix.length);
31
+ if (startsWith(builtSegmentKeyName, prefix)) return builtSegmentKeyName.slice(prefix.length);
33
32
  }
34
33
 
35
34
  buildLastUpdatedKey() {
@@ -43,6 +42,14 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
43
42
  buildTillKey() {
44
43
  return `${this.prefix}.${this.matchingKey}.segments.till`;
45
44
  }
45
+
46
+ isSplitKey(key: string) {
47
+ return startsWith(key, `${this.prefix}.split.`);
48
+ }
49
+
50
+ buildSplitsWithSegmentCountKey() {
51
+ return `${this.prefix}.splits.usingSegments`;
52
+ }
46
53
  }
47
54
 
48
55
  export function myLargeSegmentsKeyBuilder(prefix: string, matchingKey: string): MySegmentsKeyBuilder {
@@ -54,7 +61,7 @@ export function myLargeSegmentsKeyBuilder(prefix: string, matchingKey: string):
54
61
  extractSegmentName(builtSegmentKeyName: string) {
55
62
  const p = `${prefix}.${matchingKey}.largeSegment.`;
56
63
 
57
- if (startsWith(builtSegmentKeyName, p)) return builtSegmentKeyName.substr(p.length);
64
+ if (startsWith(builtSegmentKeyName, p)) return builtSegmentKeyName.slice(p.length);
58
65
  },
59
66
 
60
67
  buildTillKey() {
@@ -35,10 +35,9 @@ export function dataLoaderFactory(preloadedData: PreloadedData): DataLoader {
35
35
 
36
36
  // cleaning up the localStorage data, since some cached splits might need be part of the preloaded data
37
37
  storage.splits.clear();
38
- storage.splits.setChangeNumber(since);
39
38
 
40
39
  // splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
41
- storage.splits.addSplits(Object.keys(splitsData).map(splitName => JSON.parse(splitsData[splitName])));
40
+ storage.splits.update(Object.keys(splitsData).map(splitName => JSON.parse(splitsData[splitName])), [], since);
42
41
 
43
42
  // add mySegments data
44
43
  let mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userId];
@@ -96,8 +96,9 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
96
96
  this.hasSync = false;
97
97
  }
98
98
 
99
- addSplit(name: string, split: ISplit) {
99
+ addSplit(split: ISplit) {
100
100
  try {
101
+ const name = split.name;
101
102
  const splitKey = this.keys.buildSplitKey(name);
102
103
  const splitFromLocalStorage = localStorage.getItem(splitKey);
103
104
  const previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
@@ -120,6 +121,8 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
120
121
  removeSplit(name: string): boolean {
121
122
  try {
122
123
  const split = this.getSplit(name);
124
+ if (!split) return false;
125
+
123
126
  localStorage.removeItem(this.keys.buildSplitKey(name));
124
127
 
125
128
  this._decrementCounts(split);
@@ -132,7 +135,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
132
135
  }
133
136
  }
134
137
 
135
- getSplit(name: string) {
138
+ getSplit(name: string): ISplit | null {
136
139
  const item = localStorage.getItem(this.keys.buildSplitKey(name));
137
140
  return item && JSON.parse(item);
138
141
  }