@splitsoftware/splitio-commons 2.2.1-rc.0 → 2.2.1-rc.2

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 (151) hide show
  1. package/CHANGES.txt +2 -3
  2. package/README.md +0 -1
  3. package/cjs/evaluator/Engine.js +61 -40
  4. package/cjs/evaluator/combiners/and.js +6 -2
  5. package/cjs/evaluator/combiners/ifelseif.js +6 -6
  6. package/cjs/evaluator/condition/index.js +5 -6
  7. package/cjs/evaluator/index.js +11 -11
  8. package/cjs/evaluator/matchers/index.js +1 -3
  9. package/cjs/evaluator/matchers/matcherTypes.js +0 -1
  10. package/cjs/evaluator/matchersTransform/index.js +0 -4
  11. package/cjs/evaluator/parser/index.js +2 -2
  12. package/cjs/evaluator/value/sanitize.js +0 -1
  13. package/cjs/logger/constants.js +3 -5
  14. package/cjs/logger/messages/debug.js +2 -4
  15. package/cjs/logger/messages/warn.js +1 -1
  16. package/cjs/sdkManager/index.js +1 -2
  17. package/cjs/services/splitApi.js +4 -3
  18. package/cjs/storages/AbstractSplitsCacheSync.js +2 -5
  19. package/cjs/storages/KeyBuilder.js +0 -9
  20. package/cjs/storages/KeyBuilderCS.js +0 -3
  21. package/cjs/storages/KeyBuilderSS.js +0 -3
  22. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +14 -9
  23. package/cjs/storages/inLocalStorage/index.js +1 -5
  24. package/cjs/storages/inLocalStorage/validateCache.js +1 -2
  25. package/cjs/storages/inMemory/InMemoryStorage.js +0 -3
  26. package/cjs/storages/inMemory/InMemoryStorageCS.js +0 -4
  27. package/cjs/storages/inRedis/index.js +9 -5
  28. package/cjs/storages/pluggable/index.js +0 -2
  29. package/cjs/sync/polling/fetchers/splitChangesFetcher.js +4 -51
  30. package/cjs/sync/polling/pollingManagerCS.js +7 -7
  31. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  32. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  33. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  34. package/cjs/sync/polling/updaters/splitChangesUpdater.js +33 -51
  35. package/cjs/sync/streaming/SSEHandler/index.js +0 -1
  36. package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +77 -106
  37. package/cjs/sync/streaming/constants.js +1 -2
  38. package/cjs/sync/streaming/pushManager.js +16 -3
  39. package/cjs/sync/syncManagerOnline.js +2 -2
  40. package/cjs/utils/constants/index.js +2 -3
  41. package/cjs/utils/labels/index.js +1 -2
  42. package/esm/evaluator/Engine.js +62 -40
  43. package/esm/evaluator/combiners/and.js +6 -2
  44. package/esm/evaluator/combiners/ifelseif.js +7 -7
  45. package/esm/evaluator/condition/index.js +5 -6
  46. package/esm/evaluator/index.js +12 -12
  47. package/esm/evaluator/matchers/index.js +1 -3
  48. package/esm/evaluator/matchers/matcherTypes.js +0 -1
  49. package/esm/evaluator/matchersTransform/index.js +0 -4
  50. package/esm/evaluator/parser/index.js +2 -2
  51. package/esm/evaluator/value/sanitize.js +0 -1
  52. package/esm/logger/constants.js +0 -2
  53. package/esm/logger/messages/debug.js +2 -4
  54. package/esm/logger/messages/warn.js +1 -1
  55. package/esm/sdkManager/index.js +1 -2
  56. package/esm/services/splitApi.js +4 -3
  57. package/esm/storages/AbstractSplitsCacheSync.js +2 -5
  58. package/esm/storages/KeyBuilder.js +0 -9
  59. package/esm/storages/KeyBuilderCS.js +0 -3
  60. package/esm/storages/KeyBuilderSS.js +0 -3
  61. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +14 -9
  62. package/esm/storages/inLocalStorage/index.js +1 -5
  63. package/esm/storages/inLocalStorage/validateCache.js +1 -2
  64. package/esm/storages/inMemory/InMemoryStorage.js +0 -3
  65. package/esm/storages/inMemory/InMemoryStorageCS.js +0 -4
  66. package/esm/storages/inRedis/index.js +9 -5
  67. package/esm/storages/pluggable/index.js +0 -2
  68. package/esm/sync/polling/fetchers/splitChangesFetcher.js +4 -51
  69. package/esm/sync/polling/pollingManagerCS.js +7 -7
  70. package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  71. package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  72. package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  73. package/esm/sync/polling/updaters/splitChangesUpdater.js +33 -51
  74. package/esm/sync/streaming/SSEHandler/index.js +1 -2
  75. package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +73 -102
  76. package/esm/sync/streaming/constants.js +0 -1
  77. package/esm/sync/streaming/pushManager.js +19 -6
  78. package/esm/sync/syncManagerOnline.js +2 -2
  79. package/esm/utils/constants/index.js +1 -2
  80. package/esm/utils/labels/index.js +0 -1
  81. package/package.json +1 -1
  82. package/src/dtos/types.ts +8 -36
  83. package/src/evaluator/Engine.ts +69 -42
  84. package/src/evaluator/combiners/and.ts +4 -5
  85. package/src/evaluator/combiners/ifelseif.ts +9 -7
  86. package/src/evaluator/condition/engineUtils.ts +1 -1
  87. package/src/evaluator/condition/index.ts +12 -12
  88. package/src/evaluator/index.ts +14 -12
  89. package/src/evaluator/matchers/index.ts +1 -3
  90. package/src/evaluator/matchers/matcherTypes.ts +0 -1
  91. package/src/evaluator/matchersTransform/index.ts +0 -3
  92. package/src/evaluator/parser/index.ts +3 -3
  93. package/src/evaluator/types.ts +2 -2
  94. package/src/evaluator/value/index.ts +2 -2
  95. package/src/evaluator/value/sanitize.ts +4 -5
  96. package/src/logger/constants.ts +0 -2
  97. package/src/logger/messages/debug.ts +2 -4
  98. package/src/logger/messages/warn.ts +1 -1
  99. package/src/sdkManager/index.ts +2 -3
  100. package/src/services/splitApi.ts +4 -3
  101. package/src/services/types.ts +1 -1
  102. package/src/storages/AbstractSplitsCacheSync.ts +3 -6
  103. package/src/storages/KeyBuilder.ts +0 -12
  104. package/src/storages/KeyBuilderCS.ts +0 -4
  105. package/src/storages/KeyBuilderSS.ts +0 -4
  106. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +14 -10
  107. package/src/storages/inLocalStorage/index.ts +1 -5
  108. package/src/storages/inLocalStorage/validateCache.ts +1 -3
  109. package/src/storages/inMemory/InMemoryStorage.ts +0 -3
  110. package/src/storages/inMemory/InMemoryStorageCS.ts +0 -4
  111. package/src/storages/inRedis/index.ts +11 -7
  112. package/src/storages/pluggable/index.ts +0 -2
  113. package/src/storages/types.ts +1 -33
  114. package/src/sync/polling/fetchers/splitChangesFetcher.ts +4 -62
  115. package/src/sync/polling/fetchers/types.ts +0 -1
  116. package/src/sync/polling/pollingManagerCS.ts +7 -7
  117. package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -1
  118. package/src/sync/polling/types.ts +2 -2
  119. package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
  120. package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
  121. package/src/sync/polling/updaters/splitChangesUpdater.ts +42 -61
  122. package/src/sync/streaming/SSEHandler/index.ts +1 -2
  123. package/src/sync/streaming/SSEHandler/types.ts +2 -2
  124. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +68 -98
  125. package/src/sync/streaming/constants.ts +0 -1
  126. package/src/sync/streaming/parseUtils.ts +2 -2
  127. package/src/sync/streaming/pushManager.ts +18 -6
  128. package/src/sync/streaming/types.ts +2 -3
  129. package/src/sync/syncManagerOnline.ts +2 -2
  130. package/src/utils/constants/index.ts +1 -2
  131. package/src/utils/labels/index.ts +0 -1
  132. package/src/utils/lang/index.ts +1 -1
  133. package/types/splitio.d.ts +1 -5
  134. package/cjs/evaluator/matchers/prerequisites.js +0 -22
  135. package/cjs/evaluator/matchers/rbsegment.js +0 -44
  136. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +0 -117
  137. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +0 -61
  138. package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +0 -64
  139. package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +0 -64
  140. package/esm/evaluator/matchers/prerequisites.js +0 -18
  141. package/esm/evaluator/matchers/rbsegment.js +0 -40
  142. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +0 -114
  143. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +0 -58
  144. package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +0 -61
  145. package/esm/storages/pluggable/RBSegmentsCachePluggable.js +0 -61
  146. package/src/evaluator/matchers/prerequisites.ts +0 -24
  147. package/src/evaluator/matchers/rbsegment.ts +0 -62
  148. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +0 -136
  149. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +0 -68
  150. package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +0 -79
  151. package/src/storages/pluggable/RBSegmentsCachePluggable.ts +0 -76
@@ -11,30 +11,35 @@ import { TelemetryCacheInRedis } from './TelemetryCacheInRedis';
11
11
  import { UniqueKeysCacheInRedis } from './UniqueKeysCacheInRedis';
12
12
  import { ImpressionCountsCacheInRedis } from './ImpressionCountsCacheInRedis';
13
13
  import { metadataBuilder } from '../utils';
14
- import { RBSegmentsCacheInRedis } from './RBSegmentsCacheInRedis';
15
14
 
16
15
  export interface InRedisStorageOptions {
17
16
  prefix?: string
18
17
  options?: Record<string, any>
19
18
  }
20
19
 
20
+ let RD: typeof RedisAdapter | undefined;
21
+
22
+ try {
23
+ // Using `require` to prevent error when bundling or importing the SDK in a .mjs file, since ioredis is a CommonJS module.
24
+ // Redis storage is not supported with .mjs files.
25
+ RD = require('./RedisAdapter').RedisAdapter;
26
+ } catch (error) { /* empty */ }
27
+
21
28
  /**
22
29
  * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.js
23
30
  * @see {@link https://www.npmjs.com/package/ioredis}
24
31
  */
25
32
  export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsyncFactory {
26
33
 
27
- // Lazy loading to prevent error when bundling or importing the SDK in a .mjs file, since ioredis is a CommonJS module.
28
- // Redis storage is not supported with .mjs files.
29
- const RD = require('./RedisAdapter').RedisAdapter;
30
-
31
34
  const prefix = validatePrefix(options.prefix);
32
35
 
33
36
  function InRedisStorageFactory(params: IStorageFactoryParams): IStorageAsync {
37
+ if (!RD) throw new Error('The SDK Redis storage is not available. Your runtime environment must support CommonJS (`require`) to import the ioredis dependency.');
38
+
34
39
  const { onReadyCb, settings, settings: { log } } = params;
35
40
  const metadata = metadataBuilder(settings);
36
41
  const keys = new KeyBuilderSS(prefix, metadata);
37
- const redisClient: RedisAdapter = new RD(log, options.options || {});
42
+ const redisClient = new RD(log, options.options || {});
38
43
  const telemetry = new TelemetryCacheInRedis(log, keys, redisClient);
39
44
  const impressionCountsCache = new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient);
40
45
  const uniqueKeysCache = new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient);
@@ -51,7 +56,6 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
51
56
 
52
57
  return {
53
58
  splits: new SplitsCacheInRedis(log, keys, redisClient, settings.sync.__splitFiltersValidation),
54
- rbSegments: new RBSegmentsCacheInRedis(log, keys, redisClient),
55
59
  segments: new SegmentsCacheInRedis(log, keys, redisClient),
56
60
  impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
57
61
  impressionCounts: impressionCountsCache,
@@ -20,7 +20,6 @@ import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
20
20
  import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
21
21
  import { metadataBuilder } from '../utils';
22
22
  import { LOG_PREFIX } from '../pluggable/constants';
23
- import { RBSegmentsCachePluggable } from './RBSegmentsCachePluggable';
24
23
 
25
24
  const NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
26
25
  const NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
@@ -118,7 +117,6 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
118
117
 
119
118
  return {
120
119
  splits: new SplitsCachePluggable(log, keys, wrapper, settings.sync.__splitFiltersValidation),
121
- rbSegments: new RBSegmentsCachePluggable(log, keys, wrapper),
122
120
  segments: new SegmentsCachePluggable(log, keys, wrapper),
123
121
  impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
124
122
  impressionCounts: impressionCountsCache,
@@ -1,5 +1,5 @@
1
1
  import SplitIO from '../../types/splitio';
2
- import { MaybeThenable, ISplit, IRBSegment, IMySegmentsResponse } from '../dtos/types';
2
+ import { MaybeThenable, ISplit, IMySegmentsResponse } from '../dtos/types';
3
3
  import { MySegmentsData } from '../sync/polling/types';
4
4
  import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, MultiMethodExceptions, MultiMethodLatencies, MultiConfigs, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent, UniqueKeysPayloadCs, UniqueKeysPayloadSs, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../sync/submitters/types';
5
5
  import { ISettings } from '../types';
@@ -221,34 +221,6 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
221
221
  getNamesByFlagSets(flagSets: string[]): Promise<Set<string>[]>
222
222
  }
223
223
 
224
- /** Rule-Based Segments cache */
225
-
226
- export interface IRBSegmentsCacheBase {
227
- update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): MaybeThenable<boolean>,
228
- get(name: string): MaybeThenable<IRBSegment | null>,
229
- getChangeNumber(): MaybeThenable<number>,
230
- clear(): MaybeThenable<boolean | void>,
231
- contains(names: Set<string>): MaybeThenable<boolean>,
232
- }
233
-
234
- export interface IRBSegmentsCacheSync extends IRBSegmentsCacheBase {
235
- update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): boolean,
236
- get(name: string): IRBSegment | null,
237
- getChangeNumber(): number,
238
- clear(): void,
239
- contains(names: Set<string>): boolean,
240
- // Used only for smart pausing in client-side standalone. Returns true if the storage contains a RBSegment using segments or large segments matchers
241
- usesSegments(): boolean,
242
- }
243
-
244
- export interface IRBSegmentsCacheAsync extends IRBSegmentsCacheBase {
245
- update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): Promise<boolean>,
246
- get(name: string): Promise<IRBSegment | null>,
247
- getChangeNumber(): Promise<number>,
248
- clear(): Promise<boolean | void>,
249
- contains(names: Set<string>): Promise<boolean>,
250
- }
251
-
252
224
  /** Segments cache */
253
225
 
254
226
  export interface ISegmentsCacheBase {
@@ -447,7 +419,6 @@ export interface ITelemetryCacheAsync extends ITelemetryEvaluationProducerAsync,
447
419
 
448
420
  export interface IStorageBase<
449
421
  TSplitsCache extends ISplitsCacheBase = ISplitsCacheBase,
450
- TRBSegmentsCache extends IRBSegmentsCacheBase = IRBSegmentsCacheBase,
451
422
  TSegmentsCache extends ISegmentsCacheBase = ISegmentsCacheBase,
452
423
  TImpressionsCache extends IImpressionsCacheBase = IImpressionsCacheBase,
453
424
  TImpressionsCountCache extends IImpressionCountsCacheBase = IImpressionCountsCacheBase,
@@ -456,7 +427,6 @@ export interface IStorageBase<
456
427
  TUniqueKeysCache extends IUniqueKeysCacheBase = IUniqueKeysCacheBase
457
428
  > {
458
429
  splits: TSplitsCache,
459
- rbSegments: TRBSegmentsCache,
460
430
  segments: TSegmentsCache,
461
431
  impressions: TImpressionsCache,
462
432
  impressionCounts: TImpressionsCountCache,
@@ -469,7 +439,6 @@ export interface IStorageBase<
469
439
 
470
440
  export interface IStorageSync extends IStorageBase<
471
441
  ISplitsCacheSync,
472
- IRBSegmentsCacheSync,
473
442
  ISegmentsCacheSync,
474
443
  IImpressionsCacheSync,
475
444
  IImpressionCountsCacheSync,
@@ -484,7 +453,6 @@ export interface IStorageSync extends IStorageBase<
484
453
 
485
454
  export interface IStorageAsync extends IStorageBase<
486
455
  ISplitsCacheAsync,
487
- IRBSegmentsCacheAsync,
488
456
  ISegmentsCacheAsync,
489
457
  IImpressionsCacheAsync | IImpressionsCacheSync,
490
458
  IImpressionCountsCacheBase,
@@ -1,82 +1,24 @@
1
- import { ISettings } from '../../../types';
2
- import { ISplitChangesResponse } from '../../../dtos/types';
3
1
  import { IFetchSplitChanges, IResponse } from '../../../services/types';
4
- import { IStorageBase } from '../../../storages/types';
5
- import { FLAG_SPEC_VERSION } from '../../../utils/constants';
6
- import { base } from '../../../utils/settingsValidation';
7
2
  import { ISplitChangesFetcher } from './types';
8
- import { LOG_PREFIX_SYNC_SPLITS } from '../../../logger/constants';
9
-
10
- const PROXY_CHECK_INTERVAL_MILLIS_CS = 60 * 60 * 1000; // 1 hour in Client Side
11
- const PROXY_CHECK_INTERVAL_MILLIS_SS = 24 * PROXY_CHECK_INTERVAL_MILLIS_CS; // 24 hours in Server Side
12
-
13
- function sdkEndpointOverriden(settings: ISettings) {
14
- return settings.urls.sdk !== base.urls.sdk;
15
- }
16
3
 
17
4
  /**
18
5
  * Factory of SplitChanges fetcher.
19
6
  * SplitChanges fetcher is a wrapper around `splitChanges` API service that parses the response and handle errors.
20
7
  */
21
- // @TODO breaking: drop support for Split Proxy below v5.10.0 and simplify the implementation
22
- export function splitChangesFetcherFactory(fetchSplitChanges: IFetchSplitChanges, settings: ISettings, storage: Pick<IStorageBase, 'splits' | 'rbSegments'>): ISplitChangesFetcher {
23
-
24
- const log = settings.log;
25
- const PROXY_CHECK_INTERVAL_MILLIS = settings.core.key !== undefined ? PROXY_CHECK_INTERVAL_MILLIS_CS : PROXY_CHECK_INTERVAL_MILLIS_SS;
26
- let lastProxyCheckTimestamp: number | undefined;
8
+ export function splitChangesFetcherFactory(fetchSplitChanges: IFetchSplitChanges): ISplitChangesFetcher {
27
9
 
28
10
  return function splitChangesFetcher(
29
11
  since: number,
30
12
  noCache?: boolean,
31
13
  till?: number,
32
- rbSince?: number,
33
14
  // Optional decorator for `fetchSplitChanges` promise, such as timeout or time tracker
34
15
  decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
35
- ): Promise<ISplitChangesResponse> {
36
-
37
- // Recheck proxy
38
- if (lastProxyCheckTimestamp && (Date.now() - lastProxyCheckTimestamp) > PROXY_CHECK_INTERVAL_MILLIS) {
39
- settings.sync.flagSpecVersion = FLAG_SPEC_VERSION;
40
- }
41
-
42
- let splitsPromise = fetchSplitChanges(since, noCache, till, settings.sync.flagSpecVersion === FLAG_SPEC_VERSION ? rbSince : undefined)
43
- // Handle proxy error with spec 1.3
44
- .catch((err) => {
45
- if (err.statusCode === 400 && sdkEndpointOverriden(settings) && settings.sync.flagSpecVersion === FLAG_SPEC_VERSION) {
46
- log.error(LOG_PREFIX_SYNC_SPLITS + 'Proxy error detected. If you are using Split Proxy, please upgrade to latest version');
47
- lastProxyCheckTimestamp = Date.now();
48
- settings.sync.flagSpecVersion = '1.2'; // fallback to 1.2 spec
49
- return fetchSplitChanges(since, noCache, till); // retry request without rbSince
50
- }
51
- throw err;
52
- });
16
+ ) {
53
17
 
18
+ let splitsPromise = fetchSplitChanges(since, noCache, till);
54
19
  if (decorator) splitsPromise = decorator(splitsPromise);
55
20
 
56
- return splitsPromise
57
- .then(resp => resp.json())
58
- .then(data => {
59
- // Using flag spec version 1.2
60
- if (data.splits) {
61
- return {
62
- ff: {
63
- d: data.splits,
64
- s: data.since,
65
- t: data.till
66
- }
67
- };
68
- }
69
-
70
- // Proxy recovery
71
- if (lastProxyCheckTimestamp) {
72
- log.info(LOG_PREFIX_SYNC_SPLITS + 'Proxy error recovered');
73
- lastProxyCheckTimestamp = undefined;
74
- return Promise.all([storage.splits.clear(), storage.rbSegments.clear()])
75
- .then(() => splitChangesFetcher(storage.splits.getChangeNumber() as number, undefined, undefined, storage.rbSegments.getChangeNumber() as number));
76
- }
77
-
78
- return data;
79
- });
21
+ return splitsPromise.then(resp => resp.json());
80
22
  };
81
23
 
82
24
  }
@@ -5,7 +5,6 @@ export type ISplitChangesFetcher = (
5
5
  since: number,
6
6
  noCache?: boolean,
7
7
  till?: number,
8
- rbSince?: number,
9
8
  decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
10
9
  ) => Promise<ISplitChangesResponse>
11
10
 
@@ -43,10 +43,10 @@ export function pollingManagerCSFactory(
43
43
  // smart pausing
44
44
  readiness.splits.on(SDK_SPLITS_ARRIVED, () => {
45
45
  if (!splitsSyncTask.isRunning()) return; // noop if not doing polling
46
- const usingSegments = storage.splits.usesSegments() || storage.rbSegments.usesSegments();
47
- if (usingSegments !== mySegmentsSyncTask.isRunning()) {
48
- log.info(POLLING_SMART_PAUSING, [usingSegments ? 'ON' : 'OFF']);
49
- if (usingSegments) {
46
+ const splitsHaveSegments = storage.splits.usesSegments();
47
+ if (splitsHaveSegments !== mySegmentsSyncTask.isRunning()) {
48
+ log.info(POLLING_SMART_PAUSING, [splitsHaveSegments ? 'ON' : 'OFF']);
49
+ if (splitsHaveSegments) {
50
50
  startMySegmentsSyncTasks();
51
51
  } else {
52
52
  stopMySegmentsSyncTasks();
@@ -59,9 +59,9 @@ export function pollingManagerCSFactory(
59
59
 
60
60
  // smart ready
61
61
  function smartReady() {
62
- if (!readiness.isReady() && !storage.splits.usesSegments() && !storage.rbSegments.usesSegments()) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
62
+ if (!readiness.isReady() && !storage.splits.usesSegments()) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
63
63
  }
64
- if (!storage.splits.usesSegments() && !storage.rbSegments.usesSegments()) setTimeout(smartReady, 0);
64
+ if (!storage.splits.usesSegments()) setTimeout(smartReady, 0);
65
65
  else readiness.splits.once(SDK_SPLITS_ARRIVED, smartReady);
66
66
 
67
67
  mySegmentsSyncTasks[matchingKey] = mySegmentsSyncTask;
@@ -77,7 +77,7 @@ export function pollingManagerCSFactory(
77
77
  log.info(POLLING_START);
78
78
 
79
79
  splitsSyncTask.start();
80
- if (storage.splits.usesSegments() || storage.rbSegments.usesSegments()) startMySegmentsSyncTasks();
80
+ if (storage.splits.usesSegments()) startMySegmentsSyncTasks();
81
81
  },
82
82
 
83
83
  // Stop periodic fetching (polling)
@@ -21,7 +21,7 @@ export function splitsSyncTaskFactory(
21
21
  settings.log,
22
22
  splitChangesUpdaterFactory(
23
23
  settings.log,
24
- splitChangesFetcherFactory(fetchSplitChanges, settings, storage),
24
+ splitChangesFetcherFactory(fetchSplitChanges),
25
25
  storage,
26
26
  settings.sync.__splitFiltersValidation,
27
27
  readiness.splits,
@@ -1,10 +1,10 @@
1
- import { IRBSegment, ISplit } from '../../dtos/types';
1
+ import { ISplit } from '../../dtos/types';
2
2
  import { IReadinessManager } from '../../readiness/types';
3
3
  import { IStorageSync } from '../../storages/types';
4
4
  import { MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../streaming/types';
5
5
  import { ITask, ISyncTask } from '../types';
6
6
 
7
- export interface ISplitsSyncTask extends ISyncTask<[noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit | IRBSegment, changeNumber: number }], boolean> { }
7
+ export interface ISplitsSyncTask extends ISyncTask<[noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }], boolean> { }
8
8
 
9
9
  export interface ISegmentsSyncTask extends ISyncTask<[fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number], boolean> { }
10
10
 
@@ -27,7 +27,7 @@ export function mySegmentsUpdaterFactory(
27
27
  matchingKey: string
28
28
  ): IMySegmentsUpdater {
29
29
 
30
- const { splits, rbSegments, segments, largeSegments } = storage;
30
+ const { splits, segments, largeSegments } = storage;
31
31
  let readyOnAlreadyExistentState = true;
32
32
  let startingUp = true;
33
33
 
@@ -51,7 +51,7 @@ export function mySegmentsUpdaterFactory(
51
51
  }
52
52
 
53
53
  // Notify update if required
54
- if ((splits.usesSegments() || rbSegments.usesSegments()) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
54
+ if (splits.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
55
55
  readyOnAlreadyExistentState = false;
56
56
  segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
57
57
  }
@@ -51,7 +51,7 @@ export function segmentChangesUpdaterFactory(
51
51
  * Returned promise will not be rejected.
52
52
  *
53
53
  * @param fetchOnlyNew - if true, only fetch the segments that not exists, i.e., which `changeNumber` is equal to -1.
54
- * This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE or RB_SEGMENT_UPDATE notifications.
54
+ * This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE notifications.
55
55
  * @param segmentName - segment name to fetch. By passing `undefined` it fetches the list of segments registered at the storage
56
56
  * @param noCache - true to revalidate data to fetch on a SEGMENT_UPDATE notifications.
57
57
  * @param till - till target for the provided segmentName, for CDN bypass.
@@ -1,18 +1,16 @@
1
1
  import { ISegmentsCacheBase, IStorageBase } from '../../../storages/types';
2
2
  import { ISplitChangesFetcher } from '../fetchers/types';
3
- import { IRBSegment, ISplit, ISplitChangesResponse, ISplitFiltersValidation, MaybeThenable } from '../../../dtos/types';
3
+ import { ISplit, ISplitChangesResponse, ISplitFiltersValidation } from '../../../dtos/types';
4
4
  import { ISplitsEventEmitter } from '../../../readiness/types';
5
5
  import { timeout } from '../../../utils/promise/timeout';
6
6
  import { SDK_SPLITS_ARRIVED } from '../../../readiness/constants';
7
7
  import { ILogger } from '../../../logger/types';
8
- import { SYNC_SPLITS_FETCH, SYNC_SPLITS_UPDATE, SYNC_RBS_UPDATE, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
8
+ import { SYNC_SPLITS_FETCH, SYNC_SPLITS_UPDATE, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
9
9
  import { startsWith } from '../../../utils/lang';
10
- import { IN_RULE_BASED_SEGMENT, IN_SEGMENT } from '../../../utils/constants';
10
+ import { IN_SEGMENT } from '../../../utils/constants';
11
11
  import { setToArray } from '../../../utils/lang/sets';
12
- import { SPLIT_UPDATE } from '../../streaming/constants';
13
12
 
14
- export type InstantUpdate = { payload: ISplit | IRBSegment, changeNumber: number, type: string };
15
- type SplitChangesUpdater = (noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) => Promise<boolean>
13
+ type ISplitChangesUpdater = (noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }) => Promise<boolean>
16
14
 
17
15
  // Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
18
16
  // Returns a promise that could be rejected.
@@ -29,24 +27,24 @@ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
29
27
  * Collect segments from a raw split definition.
30
28
  * Exported for testing purposes.
31
29
  */
32
- export function parseSegments(ruleEntity: ISplit | IRBSegment, matcherType: typeof IN_SEGMENT | typeof IN_RULE_BASED_SEGMENT = IN_SEGMENT): Set<string> {
33
- const { conditions = [], excluded } = ruleEntity as IRBSegment;
34
- const segments = new Set<string>(excluded && excluded.segments);
30
+ export function parseSegments({ conditions }: ISplit): Set<string> {
31
+ let segments = new Set<string>();
35
32
 
36
33
  for (let i = 0; i < conditions.length; i++) {
37
34
  const matchers = conditions[i].matcherGroup.matchers;
38
35
 
39
36
  matchers.forEach(matcher => {
40
- if (matcher.matcherType === matcherType) segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
37
+ if (matcher.matcherType === IN_SEGMENT) segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
41
38
  });
42
39
  }
43
40
 
44
41
  return segments;
45
42
  }
46
43
 
47
- interface ISplitMutations<T extends ISplit | IRBSegment> {
48
- added: T[],
49
- removed: T[]
44
+ interface ISplitMutations {
45
+ added: ISplit[],
46
+ removed: ISplit[],
47
+ segments: string[]
50
48
  }
51
49
 
52
50
  /**
@@ -75,21 +73,25 @@ function matchFilters(featureFlag: ISplit, filters: ISplitFiltersValidation) {
75
73
  * i.e., an object with added splits, removed splits and used segments.
76
74
  * Exported for testing purposes.
77
75
  */
78
- export function computeMutation<T extends ISplit | IRBSegment>(rules: Array<T>, segments: Set<string>, filters?: ISplitFiltersValidation): ISplitMutations<T> {
76
+ export function computeSplitsMutation(entries: ISplit[], filters: ISplitFiltersValidation): ISplitMutations {
77
+ const segments = new Set<string>();
78
+ const computed = entries.reduce((accum, split) => {
79
+ if (split.status === 'ACTIVE' && matchFilters(split, filters)) {
80
+ accum.added.push(split);
79
81
 
80
- return rules.reduce((accum, ruleEntity) => {
81
- if (ruleEntity.status === 'ACTIVE' && (!filters || matchFilters(ruleEntity as ISplit, filters))) {
82
- accum.added.push(ruleEntity);
83
-
84
- parseSegments(ruleEntity).forEach((segmentName: string) => {
82
+ parseSegments(split).forEach((segmentName: string) => {
85
83
  segments.add(segmentName);
86
84
  });
87
85
  } else {
88
- accum.removed.push(ruleEntity);
86
+ accum.removed.push(split);
89
87
  }
90
88
 
91
89
  return accum;
92
- }, { added: [], removed: [] } as ISplitMutations<T>);
90
+ }, { added: [], removed: [], segments: [] } as ISplitMutations);
91
+
92
+ computed.segments = setToArray(segments);
93
+
94
+ return computed;
93
95
  }
94
96
 
95
97
  /**
@@ -109,14 +111,14 @@ export function computeMutation<T extends ISplit | IRBSegment>(rules: Array<T>,
109
111
  export function splitChangesUpdaterFactory(
110
112
  log: ILogger,
111
113
  splitChangesFetcher: ISplitChangesFetcher,
112
- storage: Pick<IStorageBase, 'splits' | 'rbSegments' | 'segments'>,
114
+ storage: Pick<IStorageBase, 'splits' | 'segments'>,
113
115
  splitFiltersValidation: ISplitFiltersValidation,
114
116
  splitsEventEmitter?: ISplitsEventEmitter,
115
117
  requestTimeoutBeforeReady: number = 0,
116
118
  retriesOnFailureBeforeReady: number = 0,
117
119
  isClientSide?: boolean
118
- ): SplitChangesUpdater {
119
- const { splits, rbSegments, segments } = storage;
120
+ ): ISplitChangesUpdater {
121
+ const { splits, segments } = storage;
120
122
 
121
123
  let startingUp = true;
122
124
 
@@ -133,53 +135,32 @@ export function splitChangesUpdaterFactory(
133
135
  * @param noCache - true to revalidate data to fetch
134
136
  * @param till - query param to bypass CDN requests
135
137
  */
136
- return function splitChangesUpdater(noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) {
138
+ return function splitChangesUpdater(noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }) {
137
139
 
138
140
  /**
139
141
  * @param since - current changeNumber at splitsCache
140
142
  * @param retry - current number of retry attempts
141
143
  */
142
- function _splitChangesUpdater(sinces: [number, number], retry = 0): Promise<boolean> {
143
- const [since, rbSince] = sinces;
144
- log.debug(SYNC_SPLITS_FETCH, sinces);
145
- return Promise.resolve(
146
- instantUpdate ?
147
- instantUpdate.type === SPLIT_UPDATE ?
148
- // IFFU edge case: a change to a flag that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
149
- Promise.resolve(rbSegments.contains(parseSegments(instantUpdate.payload, IN_RULE_BASED_SEGMENT))).then((contains) => {
150
- return contains ?
151
- { ff: { d: [instantUpdate.payload as ISplit], t: instantUpdate.changeNumber } } :
152
- splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
153
- }) :
154
- { rbs: { d: [instantUpdate.payload as IRBSegment], t: instantUpdate.changeNumber } } :
155
- splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator)
144
+ function _splitChangesUpdater(since: number, retry = 0): Promise<boolean> {
145
+ log.debug(SYNC_SPLITS_FETCH, [since]);
146
+ return Promise.resolve(splitUpdateNotification ?
147
+ { splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
148
+ splitChangesFetcher(since, noCache, till, _promiseDecorator)
156
149
  )
157
150
  .then((splitChanges: ISplitChangesResponse) => {
158
151
  startingUp = false;
159
152
 
160
- const usedSegments = new Set<string>();
153
+ const mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
161
154
 
162
- let ffUpdate: MaybeThenable<boolean> = false;
163
- if (splitChanges.ff) {
164
- const { added, removed } = computeMutation(splitChanges.ff.d, usedSegments, splitFiltersValidation);
165
- log.debug(SYNC_SPLITS_UPDATE, [added.length, removed.length]);
166
- ffUpdate = splits.update(added, removed, splitChanges.ff.t);
167
- }
168
-
169
- let rbsUpdate: MaybeThenable<boolean> = false;
170
- if (splitChanges.rbs) {
171
- const { added, removed } = computeMutation(splitChanges.rbs.d, usedSegments);
172
- log.debug(SYNC_RBS_UPDATE, [added.length, removed.length]);
173
- rbsUpdate = rbSegments.update(added, removed, splitChanges.rbs.t);
174
- }
155
+ log.debug(SYNC_SPLITS_UPDATE, [mutation.added.length, mutation.removed.length, mutation.segments.length]);
175
156
 
176
- return Promise.all([ffUpdate, rbsUpdate,
177
- // @TODO if at least 1 segment fetch fails due to 404 and other segments are updated in the storage, SDK_UPDATE is not emitted
178
- segments.registerSegments(setToArray(usedSegments))
179
- ]).then(([ffChanged, rbsChanged]) => {
157
+ return Promise.all([
158
+ splits.update(mutation.added, mutation.removed, splitChanges.till),
159
+ segments.registerSegments(mutation.segments)
160
+ ]).then(([isThereUpdate]) => {
180
161
  if (splitsEventEmitter) {
181
162
  // To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
182
- return Promise.resolve(!splitsEventEmitter.splitsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
163
+ return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate && (isClientSide || checkAllSegmentsExist(segments))))
183
164
  .catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
184
165
  .then(emitSplitsArrivedEvent => {
185
166
  // emit SDK events
@@ -196,7 +177,7 @@ export function splitChangesUpdaterFactory(
196
177
  if (startingUp && retriesOnFailureBeforeReady > retry) {
197
178
  retry += 1;
198
179
  log.info(SYNC_SPLITS_FETCH_RETRY, [retry, error]);
199
- return _splitChangesUpdater(sinces, retry);
180
+ return _splitChangesUpdater(since, retry);
200
181
  } else {
201
182
  startingUp = false;
202
183
  }
@@ -204,7 +185,7 @@ export function splitChangesUpdaterFactory(
204
185
  });
205
186
  }
206
187
 
207
- // `getChangeNumber` never rejects or throws error
208
- return Promise.all([splits.getChangeNumber(), rbSegments.getChangeNumber()]).then(_splitChangesUpdater);
188
+ let sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error
189
+ return sincePromise.then(_splitChangesUpdater);
209
190
  };
210
191
  }
@@ -1,6 +1,6 @@
1
1
  import { errorParser, messageParser } from './NotificationParser';
2
2
  import { notificationKeeperFactory } from './NotificationKeeper';
3
- import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, RB_SEGMENT_UPDATE } from '../constants';
3
+ import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE } from '../constants';
4
4
  import { IPushEventEmitter } from '../types';
5
5
  import { ISseEventHandler } from '../SSEClient/types';
6
6
  import { INotificationError, INotificationMessage } from './types';
@@ -84,7 +84,6 @@ export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter,
84
84
  case MEMBERSHIPS_MS_UPDATE:
85
85
  case MEMBERSHIPS_LS_UPDATE:
86
86
  case SPLIT_KILL:
87
- case RB_SEGMENT_UPDATE:
88
87
  pushEmitter.emit(parsedData.type, parsedData);
89
88
  break;
90
89
 
@@ -1,5 +1,5 @@
1
1
  import { ControlType } from '../constants';
2
- import { SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE, RB_SEGMENT_UPDATE } from '../types';
2
+ import { SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../types';
3
3
 
4
4
  export enum Compression {
5
5
  None = 0,
@@ -42,7 +42,7 @@ export interface ISegmentUpdateData {
42
42
  }
43
43
 
44
44
  export interface ISplitUpdateData {
45
- type: SPLIT_UPDATE | RB_SEGMENT_UPDATE,
45
+ type: SPLIT_UPDATE,
46
46
  changeNumber: number,
47
47
  pcn?: number,
48
48
  d?: string,