@splitsoftware/splitio-commons 1.16.1-rc.8 → 1.17.0-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 (167) hide show
  1. package/CHANGES.txt +2 -1
  2. package/cjs/evaluator/matchers/index.js +1 -3
  3. package/cjs/evaluator/matchers/matcherTypes.js +0 -1
  4. package/cjs/evaluator/matchersTransform/index.js +1 -1
  5. package/cjs/logger/constants.js +4 -3
  6. package/cjs/logger/messages/info.js +2 -1
  7. package/cjs/readiness/readinessManager.js +10 -14
  8. package/cjs/readiness/sdkReadinessManager.js +6 -5
  9. package/cjs/sdkClient/sdkClientMethodCS.js +2 -2
  10. package/cjs/sdkClient/sdkClientMethodCSWithTT.js +2 -2
  11. package/cjs/sdkFactory/index.js +1 -1
  12. package/cjs/services/decorateHeaders.js +43 -0
  13. package/cjs/services/splitApi.js +0 -4
  14. package/cjs/services/splitHttpClient.js +5 -4
  15. package/cjs/storages/AbstractSplitsCacheAsync.js +2 -2
  16. package/cjs/storages/AbstractSplitsCacheSync.js +6 -5
  17. package/cjs/storages/KeyBuilder.js +0 -3
  18. package/cjs/storages/KeyBuilderCS.js +5 -17
  19. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +4 -16
  20. package/cjs/storages/inLocalStorage/index.js +2 -6
  21. package/cjs/storages/inMemory/InMemoryStorageCS.js +0 -5
  22. package/cjs/storages/inMemory/SplitsCacheInMemory.js +11 -20
  23. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -7
  24. package/cjs/storages/pluggable/inMemoryWrapper.js +1 -1
  25. package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +1 -5
  26. package/cjs/sync/polling/pollingManagerCS.js +33 -51
  27. package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  28. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +21 -20
  29. package/cjs/sync/streaming/SSEClient/index.js +9 -12
  30. package/cjs/sync/streaming/SSEHandler/index.js +0 -1
  31. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +9 -23
  32. package/cjs/sync/streaming/constants.js +1 -2
  33. package/cjs/sync/streaming/parseUtils.js +8 -3
  34. package/cjs/sync/streaming/pushManager.js +69 -100
  35. package/cjs/sync/submitters/telemetrySubmitter.js +0 -4
  36. package/cjs/sync/syncManagerOnline.js +14 -24
  37. package/cjs/utils/constants/index.js +2 -4
  38. package/cjs/utils/settingsValidation/index.js +2 -7
  39. package/esm/evaluator/matchers/index.js +1 -3
  40. package/esm/evaluator/matchers/matcherTypes.js +0 -1
  41. package/esm/evaluator/matchersTransform/index.js +1 -1
  42. package/esm/logger/constants.js +1 -0
  43. package/esm/logger/messages/info.js +2 -1
  44. package/esm/readiness/readinessManager.js +10 -14
  45. package/esm/readiness/sdkReadinessManager.js +6 -5
  46. package/esm/sdkClient/sdkClientMethodCS.js +2 -2
  47. package/esm/sdkClient/sdkClientMethodCSWithTT.js +2 -2
  48. package/esm/sdkFactory/index.js +1 -1
  49. package/esm/services/decorateHeaders.js +39 -0
  50. package/esm/services/splitApi.js +1 -5
  51. package/esm/services/splitHttpClient.js +5 -4
  52. package/esm/storages/AbstractSplitsCacheAsync.js +2 -2
  53. package/esm/storages/AbstractSplitsCacheSync.js +4 -3
  54. package/esm/storages/KeyBuilder.js +0 -3
  55. package/esm/storages/KeyBuilderCS.js +4 -15
  56. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -17
  57. package/esm/storages/inLocalStorage/index.js +3 -7
  58. package/esm/storages/inMemory/InMemoryStorageCS.js +0 -5
  59. package/esm/storages/inMemory/SplitsCacheInMemory.js +12 -21
  60. package/esm/storages/inMemory/TelemetryCacheInMemory.js +10 -7
  61. package/esm/storages/pluggable/inMemoryWrapper.js +1 -1
  62. package/esm/sync/polling/fetchers/mySegmentsFetcher.js +1 -5
  63. package/esm/sync/polling/pollingManagerCS.js +34 -52
  64. package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  65. package/esm/sync/polling/updaters/mySegmentsUpdater.js +19 -18
  66. package/esm/sync/streaming/SSEClient/index.js +10 -13
  67. package/esm/sync/streaming/SSEHandler/index.js +1 -2
  68. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +9 -23
  69. package/esm/sync/streaming/constants.js +0 -1
  70. package/esm/sync/streaming/parseUtils.js +8 -3
  71. package/esm/sync/streaming/pushManager.js +70 -100
  72. package/esm/sync/submitters/telemetrySubmitter.js +0 -4
  73. package/esm/sync/syncManagerOnline.js +15 -25
  74. package/esm/utils/constants/index.js +1 -3
  75. package/esm/utils/settingsValidation/index.js +2 -7
  76. package/package.json +1 -1
  77. package/src/dtos/types.ts +7 -17
  78. package/src/evaluator/matchers/index.ts +0 -2
  79. package/src/evaluator/matchers/matcherTypes.ts +0 -1
  80. package/src/evaluator/matchersTransform/index.ts +1 -1
  81. package/src/logger/constants.ts +1 -0
  82. package/src/logger/messages/info.ts +2 -1
  83. package/src/readiness/readinessManager.ts +9 -13
  84. package/src/readiness/sdkReadinessManager.ts +7 -7
  85. package/src/readiness/types.ts +2 -3
  86. package/src/sdkClient/sdkClientMethodCS.ts +2 -2
  87. package/src/sdkClient/sdkClientMethodCSWithTT.ts +2 -2
  88. package/src/sdkFactory/index.ts +1 -1
  89. package/src/services/decorateHeaders.ts +41 -0
  90. package/src/services/splitApi.ts +2 -7
  91. package/src/services/splitHttpClient.ts +6 -5
  92. package/src/services/types.ts +0 -1
  93. package/src/storages/AbstractSplitsCacheAsync.ts +2 -2
  94. package/src/storages/AbstractSplitsCacheSync.ts +5 -4
  95. package/src/storages/KeyBuilder.ts +0 -3
  96. package/src/storages/KeyBuilderCS.ts +5 -25
  97. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +3 -3
  98. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +5 -20
  99. package/src/storages/inLocalStorage/index.ts +4 -8
  100. package/src/storages/inMemory/InMemoryStorageCS.ts +0 -5
  101. package/src/storages/inMemory/SplitsCacheInMemory.ts +10 -15
  102. package/src/storages/inMemory/TelemetryCacheInMemory.ts +11 -7
  103. package/src/storages/pluggable/inMemoryWrapper.ts +1 -1
  104. package/src/storages/types.ts +5 -7
  105. package/src/sync/polling/fetchers/mySegmentsFetcher.ts +2 -6
  106. package/src/sync/polling/pollingManagerCS.ts +29 -61
  107. package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +10 -10
  108. package/src/sync/polling/types.ts +3 -4
  109. package/src/sync/polling/updaters/mySegmentsUpdater.ts +20 -17
  110. package/src/sync/streaming/SSEClient/index.ts +14 -20
  111. package/src/sync/streaming/SSEHandler/index.ts +1 -2
  112. package/src/sync/streaming/SSEHandler/types.ts +2 -14
  113. package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +10 -26
  114. package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +1 -1
  115. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +1 -1
  116. package/src/sync/streaming/UpdateWorkers/types.ts +2 -2
  117. package/src/sync/streaming/constants.ts +0 -1
  118. package/src/sync/streaming/parseUtils.ts +10 -6
  119. package/src/sync/streaming/pushManager.ts +68 -104
  120. package/src/sync/streaming/types.ts +3 -5
  121. package/src/sync/submitters/telemetrySubmitter.ts +0 -4
  122. package/src/sync/submitters/types.ts +4 -11
  123. package/src/sync/syncManagerOnline.ts +11 -19
  124. package/src/types.ts +9 -28
  125. package/src/utils/constants/index.ts +1 -3
  126. package/src/utils/settingsValidation/index.ts +3 -8
  127. package/src/utils/settingsValidation/types.ts +1 -1
  128. package/types/dtos/types.d.ts +6 -14
  129. package/types/logger/constants.d.ts +1 -0
  130. package/types/readiness/readinessManager.d.ts +2 -2
  131. package/types/readiness/sdkReadinessManager.d.ts +3 -2
  132. package/types/readiness/types.d.ts +2 -3
  133. package/types/services/decorateHeaders.d.ts +2 -0
  134. package/types/services/splitApi.d.ts +1 -1
  135. package/types/services/splitHttpClient.d.ts +1 -1
  136. package/types/services/types.d.ts +0 -1
  137. package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
  138. package/types/storages/AbstractSplitsCacheSync.d.ts +3 -3
  139. package/types/storages/KeyBuilder.d.ts +0 -1
  140. package/types/storages/KeyBuilderCS.d.ts +2 -7
  141. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +2 -2
  142. package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +1 -1
  143. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +2 -3
  144. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -4
  145. package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
  146. package/types/storages/types.d.ts +3 -4
  147. package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +3 -2
  148. package/types/sync/polling/types.d.ts +3 -10
  149. package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +4 -4
  150. package/types/sync/streaming/SSEClient/index.d.ts +2 -5
  151. package/types/sync/streaming/SSEHandler/types.d.ts +2 -13
  152. package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -3
  153. package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +1 -2
  154. package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +2 -3
  155. package/types/sync/streaming/UpdateWorkers/types.d.ts +2 -2
  156. package/types/sync/streaming/constants.d.ts +0 -1
  157. package/types/sync/streaming/parseUtils.d.ts +4 -2
  158. package/types/sync/streaming/pushManager.d.ts +0 -2
  159. package/types/sync/streaming/types.d.ts +4 -5
  160. package/types/sync/submitters/types.d.ts +3 -10
  161. package/types/types.d.ts +11 -26
  162. package/types/utils/constants/index.d.ts +1 -3
  163. package/types/utils/settingsValidation/index.d.ts +0 -2
  164. package/types/utils/settingsValidation/types.d.ts +1 -1
  165. package/cjs/evaluator/matchers/large_segment.js +0 -16
  166. package/esm/evaluator/matchers/large_segment.js +0 -12
  167. package/src/evaluator/matchers/large_segment.ts +0 -18
@@ -36,6 +36,7 @@ export const IMPRESSION = 102;
36
36
  export const IMPRESSION_QUEUEING = 103;
37
37
  export const NEW_SHARED_CLIENT = 104;
38
38
  export const NEW_FACTORY = 105;
39
+ export const POLLING_SMART_PAUSING = 106;
39
40
  export const POLLING_START = 107;
40
41
  export const POLLING_STOP = 108;
41
42
  export const SYNC_SPLITS_FETCH_RETRY = 109;
@@ -19,10 +19,11 @@ export const codesInfo: [number, string][] = codesWarn.concat([
19
19
  [c.USER_CONSENT_INITIAL, 'Starting the SDK with %s user consent. No data will be sent.'],
20
20
 
21
21
  // synchronizer
22
+ [c.POLLING_SMART_PAUSING, c.LOG_PREFIX_SYNC_POLLING + 'Turning segments data polling %s.'],
22
23
  [c.POLLING_START, c.LOG_PREFIX_SYNC_POLLING + 'Starting polling'],
23
24
  [c.POLLING_STOP, c.LOG_PREFIX_SYNC_POLLING + 'Stopping polling'],
24
25
  [c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying download of feature flags #%s. Reason: %s'],
25
- [c.SUBMITTERS_PUSH_FULL_QUEUE, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing full %s queue and resetting timer.'],
26
+ [c.SUBMITTERS_PUSH_FULL_QUEUE, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing full %s queue and reseting timer.'],
26
27
  [c.SUBMITTERS_PUSH, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Pushing %s.'],
27
28
  [c.STREAMING_REFRESH_TOKEN, c.LOG_PREFIX_SYNC_STREAMING + 'Refreshing streaming token in %s seconds, and connecting streaming in %s seconds.'],
28
29
  [c.STREAMING_RECONNECT, c.LOG_PREFIX_SYNC_STREAMING + 'Attempting to reconnect streaming in %s seconds.'],
@@ -1,5 +1,5 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
- import { IEventEmitter, ISettings } from '../types';
2
+ import { IEventEmitter } from '../types';
3
3
  import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED, SDK_SEGMENTS_ARRIVED, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE, SDK_READY } from './constants';
4
4
  import { IReadinessEventEmitter, IReadinessManager, ISegmentsEventEmitter, ISplitsEventEmitter } from './types';
5
5
 
@@ -18,8 +18,10 @@ function splitsEventEmitterFactory(EventEmitter: new () => IEventEmitter): ISpli
18
18
  return splitsEventEmitter;
19
19
  }
20
20
 
21
- function segmentsEventEmitterFactory(EventEmitter: new () => IEventEmitter, segmentsArrived = false): ISegmentsEventEmitter {
22
- const segmentsEventEmitter = objectAssign(new EventEmitter(), { segmentsArrived });
21
+ function segmentsEventEmitterFactory(EventEmitter: new () => IEventEmitter): ISegmentsEventEmitter {
22
+ const segmentsEventEmitter = objectAssign(new EventEmitter(), {
23
+ segmentsArrived: false
24
+ });
23
25
 
24
26
  segmentsEventEmitter.once(SDK_SEGMENTS_ARRIVED, () => { segmentsEventEmitter.segmentsArrived = true; });
25
27
 
@@ -31,13 +33,10 @@ function segmentsEventEmitterFactory(EventEmitter: new () => IEventEmitter, segm
31
33
  */
32
34
  export function readinessManagerFactory(
33
35
  EventEmitter: new () => IEventEmitter,
34
- settings: ISettings,
36
+ readyTimeout = 0,
35
37
  splits: ISplitsEventEmitter = splitsEventEmitterFactory(EventEmitter)): IReadinessManager {
36
38
 
37
- const { startup: { readyTimeout, waitForLargeSegments }, sync: { largeSegmentsEnabled } } = settings;
38
-
39
39
  const segments: ISegmentsEventEmitter = segmentsEventEmitterFactory(EventEmitter);
40
- const largeSegments = largeSegmentsEnabled ? segmentsEventEmitterFactory(EventEmitter, !waitForLargeSegments) : undefined;
41
40
  const gate: IReadinessEventEmitter = new EventEmitter();
42
41
 
43
42
  // emit SDK_READY_FROM_CACHE
@@ -63,7 +62,6 @@ export function readinessManagerFactory(
63
62
  let isReady = false;
64
63
  splits.on(SDK_SPLITS_ARRIVED, checkIsReadyOrUpdate);
65
64
  segments.on(SDK_SEGMENTS_ARRIVED, checkIsReadyOrUpdate);
66
- if (largeSegments) largeSegments.on(SDK_SEGMENTS_ARRIVED, checkIsReadyOrUpdate);
67
65
 
68
66
  let isDestroyed = false;
69
67
 
@@ -89,7 +87,7 @@ export function readinessManagerFactory(
89
87
  setTimeout(() => { throw e; }, 0);
90
88
  }
91
89
  } else {
92
- if (splits.splitsArrived && segments.segmentsArrived && (!largeSegments || largeSegments.segmentsArrived)) {
90
+ if (splits.splitsArrived && segments.segmentsArrived) {
93
91
  clearTimeout(readyTimeoutId);
94
92
  isReady = true;
95
93
  try {
@@ -107,12 +105,11 @@ export function readinessManagerFactory(
107
105
  return {
108
106
  splits,
109
107
  segments,
110
- largeSegments,
111
108
  gate,
112
109
 
113
- shared() {
110
+ shared(readyTimeout = 0) {
114
111
  refCount++;
115
- return readinessManagerFactory(EventEmitter, settings, splits);
112
+ return readinessManagerFactory(EventEmitter, readyTimeout, splits);
116
113
  },
117
114
 
118
115
  // @TODO review/remove next methods when non-recoverable errors are reworked
@@ -126,7 +123,6 @@ export function readinessManagerFactory(
126
123
  isDestroyed = true;
127
124
 
128
125
  segments.removeAllListeners();
129
- if (largeSegments) largeSegments.removeAllListeners();
130
126
  gate.removeAllListeners();
131
127
  clearTimeout(readyTimeoutId);
132
128
 
@@ -2,8 +2,9 @@ import { objectAssign } from '../utils/lang/objectAssign';
2
2
  import { promiseWrapper } from '../utils/promise/wrapper';
3
3
  import { readinessManagerFactory } from './readinessManager';
4
4
  import { ISdkReadinessManager } from './types';
5
- import { IEventEmitter, ISettings } from '../types';
5
+ import { IEventEmitter } from '../types';
6
6
  import { SDK_READY, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE } from './constants';
7
+ import { ILogger } from '../logger/types';
7
8
  import { ERROR_CLIENT_LISTENER, CLIENT_READY_FROM_CACHE, CLIENT_READY, CLIENT_NO_LISTENER } from '../logger/constants';
8
9
 
9
10
  const NEW_LISTENER_EVENT = 'newListener';
@@ -17,11 +18,10 @@ const REMOVE_LISTENER_EVENT = 'removeListener';
17
18
  * @param readinessManager optional readinessManager to use. only used internally for `shared` method
18
19
  */
19
20
  export function sdkReadinessManagerFactory(
21
+ log: ILogger,
20
22
  EventEmitter: new () => IEventEmitter,
21
- settings: ISettings,
22
- readinessManager = readinessManagerFactory(EventEmitter, settings)): ISdkReadinessManager {
23
-
24
- const log = settings.log;
23
+ readyTimeout = 0,
24
+ readinessManager = readinessManagerFactory(EventEmitter, readyTimeout)): ISdkReadinessManager {
25
25
 
26
26
  /** Ready callback warning */
27
27
  let internalReadyCbCount = 0;
@@ -72,8 +72,8 @@ export function sdkReadinessManagerFactory(
72
72
  return {
73
73
  readinessManager,
74
74
 
75
- shared() {
76
- return sdkReadinessManagerFactory(EventEmitter, settings, readinessManager.shared());
75
+ shared(readyTimeout = 0) {
76
+ return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager.shared(readyTimeout));
77
77
  },
78
78
 
79
79
  incInternalReadyCbCount() {
@@ -45,7 +45,6 @@ export interface IReadinessManager {
45
45
  /** Event emitters */
46
46
  splits: ISplitsEventEmitter,
47
47
  segments: ISegmentsEventEmitter,
48
- largeSegments?: ISegmentsEventEmitter, // Undefined if largeSegmentsEnabled or waitForLargeSegments are false
49
48
  gate: IReadinessEventEmitter,
50
49
 
51
50
  /** Readiness status */
@@ -60,7 +59,7 @@ export interface IReadinessManager {
60
59
  destroy(): void,
61
60
 
62
61
  /** for client-side */
63
- shared(): IReadinessManager,
62
+ shared(readyTimeout?: number): IReadinessManager,
64
63
  }
65
64
 
66
65
  /** SDK readiness manager */
@@ -76,5 +75,5 @@ export interface ISdkReadinessManager {
76
75
  incInternalReadyCbCount(): void
77
76
 
78
77
  /** for client-side */
79
- shared(): ISdkReadinessManager
78
+ shared(readyTimeout?: number): ISdkReadinessManager
80
79
  }
@@ -19,7 +19,7 @@ function buildInstanceId(key: SplitIO.SplitKey) {
19
19
  * Therefore, clients don't have a bound TT for the track method.
20
20
  */
21
21
  export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey) => SplitIO.ICsClient {
22
- const { storage, syncManager, sdkReadinessManager, settings: { core: { key }, log } } = params;
22
+ const { storage, syncManager, sdkReadinessManager, settings: { core: { key }, startup: { readyTimeout }, log } } = params;
23
23
 
24
24
  const mainClientInstance = clientCSDecorator(
25
25
  log,
@@ -51,7 +51,7 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
51
51
  if (!clientInstances[instanceId]) {
52
52
  const matchingKey = getMatching(validKey);
53
53
 
54
- const sharedSdkReadiness = sdkReadinessManager.shared();
54
+ const sharedSdkReadiness = sdkReadinessManager.shared(readyTimeout);
55
55
  const sharedStorage = storage.shared && storage.shared(matchingKey, (err) => {
56
56
  if (err) {
57
57
  sharedSdkReadiness.readinessManager.timeout();
@@ -21,7 +21,7 @@ function buildInstanceId(key: SplitIO.SplitKey, trafficType?: string) {
21
21
  * (default client) or the client method (shared clients).
22
22
  */
23
23
  export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey, trafficType?: string) => SplitIO.ICsClient {
24
- const { storage, syncManager, sdkReadinessManager, settings: { core: { key, trafficType }, log } } = params;
24
+ const { storage, syncManager, sdkReadinessManager, settings: { core: { key, trafficType }, startup: { readyTimeout }, log } } = params;
25
25
 
26
26
  const mainClientInstance = clientCSDecorator(
27
27
  log,
@@ -61,7 +61,7 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
61
61
  if (!clientInstances[instanceId]) {
62
62
  const matchingKey = getMatching(validKey);
63
63
 
64
- const sharedSdkReadiness = sdkReadinessManager.shared();
64
+ const sharedSdkReadiness = sdkReadinessManager.shared(readyTimeout);
65
65
  const sharedStorage = storage.shared && storage.shared(matchingKey, (err) => {
66
66
  if (err) {
67
67
  sharedSdkReadiness.readinessManager.timeout();
@@ -32,7 +32,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
32
32
  // We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle.
33
33
  validateAndTrackApiKey(log, settings.core.authorizationKey);
34
34
 
35
- const sdkReadinessManager = sdkReadinessManagerFactory(platform.EventEmitter, settings);
35
+ const sdkReadinessManager = sdkReadinessManagerFactory(log, platform.EventEmitter, settings.startup.readyTimeout);
36
36
  const readiness = sdkReadinessManager.readinessManager;
37
37
 
38
38
  const storage = storageFactory({
@@ -0,0 +1,41 @@
1
+ import { objectAssign } from '../utils/lang/objectAssign';
2
+ import { _Set } from '../utils/lang/sets';
3
+ import { ISettings } from '../types';
4
+
5
+ const FORBIDDEN_HEADERS = new _Set([
6
+ 'splitsdkclientkey',
7
+ 'splitsdkversion',
8
+ 'splitsdkmachineip',
9
+ 'splitsdkmachinename',
10
+ 'splitsdkimpressionsmode',
11
+ 'host',
12
+ 'referrer',
13
+ 'content-type',
14
+ 'content-length',
15
+ 'content-encoding',
16
+ 'accept',
17
+ 'keep-alive',
18
+ 'x-fastly-debug'
19
+ ]);
20
+
21
+ function copyToLowerCase(obj: Record<string, string>) {
22
+ return Object.keys(obj).reduce<Record<string, string>>((acc, key) => {
23
+ acc[key.toLowerCase()] = obj[key];
24
+ return acc;
25
+ }, {});
26
+ }
27
+
28
+ export function decorateHeaders(settings: ISettings, headers: Record<string, string>) {
29
+ if (settings.sync.requestOptions?.getHeaderOverrides) {
30
+ headers = copyToLowerCase(headers);
31
+ try {
32
+ const headerOverrides = copyToLowerCase(settings.sync.requestOptions.getHeaderOverrides({ headers: objectAssign({}, headers) }));
33
+ Object.keys(headerOverrides)
34
+ .filter(key => !FORBIDDEN_HEADERS.has(key))
35
+ .forEach(key => headers[key] = headerOverrides[key]);
36
+ } catch (e) {
37
+ settings.log.error('Problem adding custom headers to request decorator: ' + e);
38
+ }
39
+ }
40
+ return headers;
41
+ }
@@ -4,7 +4,7 @@ import { splitHttpClientFactory } from './splitHttpClient';
4
4
  import { ISplitApi } from './types';
5
5
  import { objectAssign } from '../utils/lang/objectAssign';
6
6
  import { ITelemetryTracker } from '../trackers/types';
7
- import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT, MY_LARGE_SEGMENT } from '../utils/constants';
7
+ import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT } from '../utils/constants';
8
8
  import { ERROR_TOO_MANY_SETS } from '../logger/constants';
9
9
 
10
10
  const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
@@ -22,7 +22,7 @@ function userKeyToQueryParam(userKey: string) {
22
22
  */
23
23
  export function splitApiFactory(
24
24
  settings: ISettings,
25
- platform: Pick<IPlatform, 'getOptions' | 'getFetch'>,
25
+ platform: IPlatform,
26
26
  telemetryTracker: ITelemetryTracker
27
27
  ): ISplitApi {
28
28
 
@@ -78,11 +78,6 @@ export function splitApiFactory(
78
78
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MY_SEGMENT));
79
79
  },
80
80
 
81
- fetchMyLargeSegments(userMatchingKey: string, noCache?: boolean) {
82
- const url = `${urls.sdk}/myLargeSegments/${encodeURIComponent(userMatchingKey)}`;
83
- return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MY_LARGE_SEGMENT));
84
- },
85
-
86
81
  /**
87
82
  * Post events.
88
83
  *
@@ -3,6 +3,7 @@ import { objectAssign } from '../utils/lang/objectAssign';
3
3
  import { ERROR_HTTP, ERROR_CLIENT_CANNOT_GET_READY } from '../logger/constants';
4
4
  import { ISettings } from '../types';
5
5
  import { IPlatform } from '../sdkFactory/types';
6
+ import { decorateHeaders } from './decorateHeaders';
6
7
 
7
8
  const messageNoFetch = 'Global fetch API is not available.';
8
9
 
@@ -12,7 +13,7 @@ const messageNoFetch = 'Global fetch API is not available.';
12
13
  * @param settings SDK settings, used to access authorizationKey, logger instance and metadata (SDK version, ip and hostname) to set additional headers
13
14
  * @param platform object containing environment-specific dependencies
14
15
  */
15
- export function splitHttpClientFactory(settings: ISettings, { getOptions, getFetch }: Pick<IPlatform, 'getOptions' | 'getFetch'>): ISplitHttpClient {
16
+ export function splitHttpClientFactory(settings: ISettings, { getOptions, getFetch }: IPlatform): ISplitHttpClient {
16
17
 
17
18
  const { log, core: { authorizationKey }, version, runtime: { ip, hostname } } = settings;
18
19
  const options = getOptions && getOptions(settings);
@@ -21,20 +22,20 @@ export function splitHttpClientFactory(settings: ISettings, { getOptions, getFet
21
22
  // if fetch is not available, log Error
22
23
  if (!fetch) log.error(ERROR_CLIENT_CANNOT_GET_READY, [messageNoFetch]);
23
24
 
24
- const headers: Record<string, string> = {
25
+ const commonHeaders: Record<string, string> = {
25
26
  'Accept': 'application/json',
26
27
  'Content-Type': 'application/json',
27
28
  'Authorization': `Bearer ${authorizationKey}`,
28
29
  'SplitSDKVersion': version
29
30
  };
30
31
 
31
- if (ip) headers['SplitSDKMachineIP'] = ip;
32
- if (hostname) headers['SplitSDKMachineName'] = hostname;
32
+ if (ip) commonHeaders['SplitSDKMachineIP'] = ip;
33
+ if (hostname) commonHeaders['SplitSDKMachineName'] = hostname;
33
34
 
34
35
  return function httpClient(url: string, reqOpts: IRequestOptions = {}, latencyTracker: (error?: NetworkError) => void = () => { }, logErrorsAsInfo: boolean = false): Promise<IResponse> {
35
36
 
36
37
  const request = objectAssign({
37
- headers: reqOpts.headers ? objectAssign({}, headers, reqOpts.headers) : headers,
38
+ headers: decorateHeaders(settings, objectAssign({}, commonHeaders, reqOpts.headers || {})),
38
39
  method: reqOpts.method || 'GET',
39
40
  body: reqOpts.body
40
41
  }, options);
@@ -62,7 +62,6 @@ export interface ISplitApi {
62
62
  fetchSplitChanges: IFetchSplitChanges
63
63
  fetchSegmentChanges: IFetchSegmentChanges
64
64
  fetchMySegments: IFetchMySegments
65
- fetchMyLargeSegments: IFetchMySegments
66
65
  postEventsBulk: IPostEventsBulk
67
66
  postUniqueKeysBulkCs: IPostUniqueKeysBulkCs
68
67
  postUniqueKeysBulkSs: IPostUniqueKeysBulkSs
@@ -22,9 +22,9 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
22
22
  abstract trafficTypeExists(trafficType: string): Promise<boolean>
23
23
  abstract clear(): Promise<boolean | void>
24
24
 
25
- // @TODO revisit segment-related methods ('usesMatcher', 'getRegisteredSegments', 'registerSegments')
25
+ // @TODO revisit segment-related methods ('usesSegments', 'getRegisteredSegments', 'registerSegments')
26
26
  // noop, just keeping the interface. This is used by standalone client-side API only, and so only implemented by InMemory and InLocalStorage.
27
- usesMatcher(): Promise<boolean> {
27
+ usesSegments(): Promise<boolean> {
28
28
  return Promise.resolve(true);
29
29
  }
30
30
 
@@ -2,6 +2,7 @@ import { ISplitsCacheSync } from './types';
2
2
  import { ISplit } from '../dtos/types';
3
3
  import { objectAssign } from '../utils/lang/objectAssign';
4
4
  import { ISet } from '../utils/lang/sets';
5
+ import { IN_SEGMENT } from '../utils/constants';
5
6
 
6
7
  /**
7
8
  * This class provides a skeletal implementation of the ISplitsCacheSync interface
@@ -43,7 +44,7 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
43
44
 
44
45
  abstract trafficTypeExists(trafficType: string): boolean
45
46
 
46
- abstract usesMatcher(matcherType: string): boolean
47
+ abstract usesSegments(): boolean
47
48
 
48
49
  abstract clear(): void
49
50
 
@@ -85,15 +86,15 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
85
86
 
86
87
  /**
87
88
  * Given a parsed split, it returns a boolean flagging if its conditions use segments matchers (rules & whitelists).
88
- * This util is intended to simplify the implementation of `splitsCache::usesMatcher` method
89
+ * This util is intended to simplify the implementation of `splitsCache::usesSegments` method
89
90
  */
90
- export function usesMatcher(split: ISplit, matcherType: string) {
91
+ export function usesSegments(split: ISplit) {
91
92
  const conditions = split.conditions || [];
92
93
  for (let i = 0; i < conditions.length; i++) {
93
94
  const matchers = conditions[i].matcherGroup.matchers;
94
95
 
95
96
  for (let j = 0; j < matchers.length; j++) {
96
- if (matchers[j].matcherType === matcherType) return true;
97
+ if (matchers[j].matcherType === IN_SEGMENT) return true;
97
98
  }
98
99
  }
99
100
 
@@ -51,9 +51,6 @@ export class KeyBuilder {
51
51
  buildSplitsWithSegmentCountKey() {
52
52
  return `${this.prefix}.splits.usingSegments`;
53
53
  }
54
- buildSplitsWithLargeSegmentCountKey() {
55
- return `${this.prefix}.splits.usingLargeSegments`;
56
- }
57
54
 
58
55
  buildSegmentNameKey(segmentName: string) {
59
56
  return `${this.prefix}.segment.${segmentName}`;
@@ -1,13 +1,7 @@
1
1
  import { startsWith } from '../utils/lang';
2
2
  import { KeyBuilder } from './KeyBuilder';
3
3
 
4
- export interface MySegmentsKeyBuilder {
5
- buildSegmentNameKey(segmentName: string): string;
6
- extractSegmentName(builtSegmentKeyName: string): string | undefined;
7
- extractOldSegmentKey(builtSegmentKeyName: string): string | undefined;
8
- }
9
-
10
- export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
4
+ export class KeyBuilderCS extends KeyBuilder {
11
5
 
12
6
  protected readonly regexSplitsCacheKey: RegExp;
13
7
  protected readonly matchingKey: string;
@@ -32,6 +26,10 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
32
26
  return builtSegmentKeyName.substr(prefix.length);
33
27
  }
34
28
 
29
+ // @BREAKING: The key used to start with the matching key instead of the prefix, this was changed on version 10.17.3
30
+ buildOldSegmentNameKey(segmentName: string) {
31
+ return `${this.matchingKey}.${this.prefix}.segment.${segmentName}`;
32
+ }
35
33
  // @BREAKING: The key used to start with the matching key instead of the prefix, this was changed on version 10.17.3
36
34
  extractOldSegmentKey(builtSegmentKeyName: string) {
37
35
  const prefix = `${this.matchingKey}.${this.prefix}.segment.`;
@@ -48,21 +46,3 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
48
46
  return this.regexSplitsCacheKey.test(key);
49
47
  }
50
48
  }
51
-
52
- export function myLargeSegmentsKeyBuilder(prefix: string, matchingKey: string): MySegmentsKeyBuilder {
53
- return {
54
- buildSegmentNameKey(segmentName: string) {
55
- return `${prefix}.${matchingKey}.largeSegment.${segmentName}`;
56
- },
57
-
58
- extractSegmentName(builtSegmentKeyName: string) {
59
- const p = `${prefix}.${matchingKey}.largeSegment.`;
60
-
61
- if (startsWith(builtSegmentKeyName, p)) return builtSegmentKeyName.substr(p.length);
62
- },
63
-
64
- extractOldSegmentKey() {
65
- return undefined;
66
- }
67
- };
68
- }
@@ -1,14 +1,14 @@
1
1
  import { ILogger } from '../../logger/types';
2
2
  import { AbstractSegmentsCacheSync } from '../AbstractSegmentsCacheSync';
3
- import type { MySegmentsKeyBuilder } from '../KeyBuilderCS';
3
+ import { KeyBuilderCS } from '../KeyBuilderCS';
4
4
  import { LOG_PREFIX, DEFINED } from './constants';
5
5
 
6
6
  export class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync {
7
7
 
8
- private readonly keys: MySegmentsKeyBuilder;
8
+ private readonly keys: KeyBuilderCS;
9
9
  private readonly log: ILogger;
10
10
 
11
- constructor(log: ILogger, keys: MySegmentsKeyBuilder) {
11
+ constructor(log: ILogger, keys: KeyBuilderCS) {
12
12
  super();
13
13
  this.log = log;
14
14
  this.keys = keys;
@@ -1,5 +1,5 @@
1
1
  import { ISplit } from '../../dtos/types';
2
- import { AbstractSplitsCacheSync, usesMatcher } from '../AbstractSplitsCacheSync';
2
+ import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
3
3
  import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
4
4
  import { KeyBuilderCS } from '../KeyBuilderCS';
5
5
  import { ILogger } from '../../logger/types';
@@ -7,7 +7,6 @@ import { LOG_PREFIX } from './constants';
7
7
  import { ISet, _Set, setToArray } from '../../utils/lang/sets';
8
8
  import { ISettings } from '../../types';
9
9
  import { getStorageHash } from '../KeyBuilder';
10
- import { IN_LARGE_SEGMENT, IN_SEGMENT } from '../../utils/constants';
11
10
 
12
11
  /**
13
12
  * ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
@@ -51,15 +50,10 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
51
50
  const ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
52
51
  this._decrementCount(ttKey);
53
52
 
54
- if (usesMatcher(split, IN_SEGMENT)) {
53
+ if (usesSegments(split)) {
55
54
  const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
56
55
  this._decrementCount(segmentsCountKey);
57
56
  }
58
-
59
- if (usesMatcher(split, IN_LARGE_SEGMENT)) {
60
- const segmentsCountKey = this.keys.buildSplitsWithLargeSegmentCountKey();
61
- this._decrementCount(segmentsCountKey);
62
- }
63
57
  }
64
58
  } catch (e) {
65
59
  this.log.error(LOG_PREFIX + e);
@@ -73,17 +67,11 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
73
67
  // @ts-expect-error
74
68
  localStorage.setItem(ttKey, toNumber(localStorage.getItem(ttKey)) + 1);
75
69
 
76
- if (usesMatcher(split, IN_SEGMENT)) {
70
+ if (usesSegments(split)) {
77
71
  const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
78
72
  // @ts-expect-error
79
73
  localStorage.setItem(segmentsCountKey, toNumber(localStorage.getItem(segmentsCountKey)) + 1);
80
74
  }
81
-
82
- if (usesMatcher(split, IN_LARGE_SEGMENT)) {
83
- const segmentsCountKey = this.keys.buildSplitsWithLargeSegmentCountKey();
84
- // @ts-expect-error
85
- localStorage.setItem(segmentsCountKey, toNumber(localStorage.getItem(segmentsCountKey)) + 1);
86
- }
87
75
  }
88
76
  } catch (e) {
89
77
  this.log.error(LOG_PREFIX + e);
@@ -215,14 +203,11 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
215
203
  return isFiniteNumber(ttCount) && ttCount > 0;
216
204
  }
217
205
 
218
- usesMatcher(matcherType: string) {
206
+ usesSegments() {
219
207
  // If cache hasn't been synchronized with the cloud, assume we need them.
220
208
  if (!this.hasSync) return true;
221
209
 
222
- const storedCount = localStorage.getItem(matcherType === IN_SEGMENT ?
223
- this.keys.buildSplitsWithSegmentCountKey() :
224
- this.keys.buildSplitsWithLargeSegmentCountKey()
225
- );
210
+ const storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
226
211
  const splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
227
212
 
228
213
  if (isFiniteNumber(splitsWithSegmentsCount)) {
@@ -3,7 +3,7 @@ import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCache
3
3
  import { EventsCacheInMemory } from '../inMemory/EventsCacheInMemory';
4
4
  import { IStorageFactoryParams, IStorageSync, IStorageSyncFactory } from '../types';
5
5
  import { validatePrefix } from '../KeyBuilder';
6
- import { KeyBuilderCS, myLargeSegmentsKeyBuilder } from '../KeyBuilderCS';
6
+ import { KeyBuilderCS } from '../KeyBuilderCS';
7
7
  import { isLocalStorageAvailable } from '../../utils/env/isLocalStorageAvailable';
8
8
  import { SplitsCacheInLocal } from './SplitsCacheInLocal';
9
9
  import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
@@ -38,17 +38,15 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
38
38
 
39
39
  const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation } } } = params;
40
40
  const matchingKey = getMatching(settings.core.key);
41
- const keys = new KeyBuilderCS(prefix, matchingKey);
41
+ const keys = new KeyBuilderCS(prefix, matchingKey as string);
42
42
  const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
43
43
 
44
44
  const splits = new SplitsCacheInLocal(settings, keys, expirationTimestamp);
45
45
  const segments = new MySegmentsCacheInLocal(log, keys);
46
- const largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey));
47
46
 
48
47
  return {
49
48
  splits,
50
49
  segments,
51
- largeSegments,
52
50
  impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
53
51
  impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
54
52
  events: new EventsCacheInMemory(eventsQueueSize),
@@ -58,7 +56,6 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
58
56
  destroy() {
59
57
  this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
60
58
  this.segments = new MySegmentsCacheInMemory();
61
- this.largeSegments = new MySegmentsCacheInMemory();
62
59
  this.impressions.clear();
63
60
  this.impressionCounts && this.impressionCounts.clear();
64
61
  this.events.clear();
@@ -67,11 +64,11 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
67
64
 
68
65
  // When using shared instanciation with MEMORY we reuse everything but segments (they are customer per key).
69
66
  shared(matchingKey: string) {
67
+ const childKeysBuilder = new KeyBuilderCS(prefix, matchingKey);
70
68
 
71
69
  return {
72
70
  splits: this.splits,
73
- segments: new MySegmentsCacheInLocal(log, new KeyBuilderCS(prefix, matchingKey)),
74
- largeSegments: new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey)),
71
+ segments: new MySegmentsCacheInLocal(log, childKeysBuilder),
75
72
  impressions: this.impressions,
76
73
  impressionCounts: this.impressionCounts,
77
74
  events: this.events,
@@ -80,7 +77,6 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
80
77
  destroy() {
81
78
  this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
82
79
  this.segments = new MySegmentsCacheInMemory();
83
- this.largeSegments = new MySegmentsCacheInMemory();
84
80
  }
85
81
  };
86
82
  },
@@ -18,12 +18,10 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
18
18
 
19
19
  const splits = new SplitsCacheInMemory(__splitFiltersValidation);
20
20
  const segments = new MySegmentsCacheInMemory();
21
- const largeSegments = new MySegmentsCacheInMemory();
22
21
 
23
22
  const storage = {
24
23
  splits,
25
24
  segments,
26
- largeSegments,
27
25
  impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
28
26
  impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
29
27
  events: new EventsCacheInMemory(eventsQueueSize),
@@ -34,7 +32,6 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
34
32
  destroy() {
35
33
  this.splits.clear();
36
34
  this.segments.clear();
37
- this.largeSegments.clear();
38
35
  this.impressions.clear();
39
36
  this.impressionCounts && this.impressionCounts.clear();
40
37
  this.events.clear();
@@ -46,7 +43,6 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
46
43
  return {
47
44
  splits: this.splits,
48
45
  segments: new MySegmentsCacheInMemory(),
49
- largeSegments: new MySegmentsCacheInMemory(),
50
46
  impressions: this.impressions,
51
47
  impressionCounts: this.impressionCounts,
52
48
  events: this.events,
@@ -56,7 +52,6 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
56
52
  destroy() {
57
53
  this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
58
54
  this.segments.clear();
59
- this.largeSegments.clear();
60
55
  }
61
56
  };
62
57
  },