@splitsoftware/splitio-commons 2.12.0 → 3.0.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 (395) hide show
  1. package/CHANGES.txt +19 -1
  2. package/cjs/evaluator/condition/engineUtils.js +2 -2
  3. package/cjs/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.js +70 -0
  4. package/cjs/evaluator/fallbackConfigsCalculator/index.js +25 -0
  5. package/cjs/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +5 -8
  6. package/cjs/evaluator/fallbackTreatmentsCalculator/index.js +21 -32
  7. package/cjs/evaluator/index.js +73 -48
  8. package/cjs/evaluator/matchers/whitelist.js +1 -1
  9. package/cjs/integrations/pluggable.js +1 -1
  10. package/cjs/listeners/browser.js +4 -3
  11. package/cjs/listeners/node.js +4 -4
  12. package/cjs/logger/constants.js +15 -21
  13. package/cjs/logger/index.js +1 -1
  14. package/cjs/logger/messages/debug.js +6 -7
  15. package/cjs/logger/messages/error.js +4 -4
  16. package/cjs/logger/messages/info.js +2 -4
  17. package/cjs/logger/messages/warn.js +9 -10
  18. package/cjs/platform/browser.js +15 -0
  19. package/cjs/platform/getEventSource/browser.js +8 -0
  20. package/cjs/platform/getEventSource/eventsource.js +480 -0
  21. package/cjs/platform/getEventSource/node.js +26 -0
  22. package/cjs/platform/getFetch/browser.js +9 -0
  23. package/cjs/platform/getFetch/node.js +27 -0
  24. package/cjs/platform/getOptions/node.js +25 -0
  25. package/cjs/platform/node.js +17 -0
  26. package/cjs/readiness/constants.js +5 -4
  27. package/cjs/readiness/readinessManager.js +22 -22
  28. package/cjs/readiness/sdkReadinessManager.js +0 -16
  29. package/cjs/sdkClient/client.js +9 -35
  30. package/cjs/sdkClient/clientAttributesDecoration.js +3 -3
  31. package/cjs/sdkClient/clientInputValidation.js +38 -81
  32. package/cjs/sdkClient/identity.js +1 -1
  33. package/cjs/sdkClient/sdkClient.js +4 -49
  34. package/cjs/sdkClient/sdkLifecycle.js +71 -0
  35. package/cjs/sdkClient/trackMethod.js +56 -0
  36. package/cjs/sdkFactory/index.js +13 -50
  37. package/cjs/sdkManager/index.js +5 -5
  38. package/cjs/services/authProvider.js +67 -0
  39. package/cjs/services/secureSplitHttpClient.js +39 -0
  40. package/cjs/services/splitApi.js +24 -14
  41. package/cjs/services/splitHttpClient.js +1 -1
  42. package/cjs/storages/AbstractDefinitionsCacheAsync.js +51 -0
  43. package/cjs/storages/AbstractDefinitionsCacheSync.js +76 -0
  44. package/cjs/storages/KeyBuilder.js +16 -16
  45. package/cjs/storages/KeyBuilderCS.js +17 -17
  46. package/cjs/storages/KeyBuilderSS.js +16 -16
  47. package/cjs/storages/getRolloutPlan.js +4 -4
  48. package/cjs/storages/inLocalStorage/DefinitionsCacheInLocal.js +194 -0
  49. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -1
  50. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +10 -10
  51. package/cjs/storages/inLocalStorage/index.js +6 -6
  52. package/cjs/storages/inLocalStorage/validateCache.js +3 -3
  53. package/cjs/storages/inMemory/DefinitionsCacheInMemory.js +121 -0
  54. package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
  55. package/cjs/storages/inMemory/InMemoryStorage.js +4 -4
  56. package/cjs/storages/inMemory/InMemoryStorageCS.js +5 -5
  57. package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +1 -1
  58. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +5 -5
  59. package/cjs/storages/inMemory/SegmentsCacheInMemory.js +1 -1
  60. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +5 -5
  61. package/cjs/storages/inRedis/DefinitionsCacheInRedis.js +243 -0
  62. package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
  63. package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +5 -5
  64. package/cjs/storages/inRedis/ImpressionsCacheInRedis.js +1 -1
  65. package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +1 -1
  66. package/cjs/storages/inRedis/RedisAdapter.js +8 -8
  67. package/cjs/storages/inRedis/TelemetryCacheInRedis.js +7 -7
  68. package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +3 -3
  69. package/cjs/storages/inRedis/index.js +2 -2
  70. package/cjs/storages/pluggable/DefinitionsCachePluggable.js +212 -0
  71. package/cjs/storages/pluggable/EventsCachePluggable.js +1 -1
  72. package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +6 -6
  73. package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +1 -1
  74. package/cjs/storages/pluggable/TelemetryCachePluggable.js +7 -7
  75. package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +2 -2
  76. package/cjs/storages/pluggable/index.js +5 -5
  77. package/cjs/storages/pluggable/wrapperAdapter.js +1 -1
  78. package/cjs/storages/setRolloutPlan.js +6 -6
  79. package/cjs/storages/utils.js +6 -6
  80. package/cjs/sync/offline/splitsParser/parseCondition.js +1 -1
  81. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +5 -5
  82. package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
  83. package/cjs/sync/polling/fetchers/splitChangesFetcher.js +24 -15
  84. package/cjs/sync/polling/pollingManagerCS.js +18 -18
  85. package/cjs/sync/polling/pollingManagerSS.js +13 -13
  86. package/cjs/sync/polling/syncTasks/definitionsSyncTask.js +12 -0
  87. package/cjs/sync/polling/updaters/{splitChangesUpdater.js → definitionChangesUpdater.js} +72 -64
  88. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +3 -3
  89. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +6 -6
  90. package/cjs/sync/streaming/SSEClient/index.js +2 -2
  91. package/cjs/sync/streaming/SSEHandler/NotificationKeeper.js +1 -1
  92. package/cjs/sync/streaming/SSEHandler/index.js +1 -1
  93. package/cjs/sync/streaming/UpdateWorkers/{SplitsUpdateWorker.js → DefinitionsUpdateWorker.js} +18 -18
  94. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
  95. package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
  96. package/cjs/sync/streaming/constants.js +3 -3
  97. package/cjs/sync/streaming/parseUtils.js +12 -12
  98. package/cjs/sync/streaming/pushManager.js +14 -14
  99. package/cjs/sync/submitters/impressionsSubmitter.js +6 -6
  100. package/cjs/sync/submitters/submitter.js +1 -1
  101. package/cjs/sync/submitters/telemetrySubmitter.js +1 -2
  102. package/cjs/sync/syncManagerOnline.js +9 -6
  103. package/cjs/trackers/eventTracker.js +10 -12
  104. package/cjs/trackers/impressionObserver/buildKey.js +1 -1
  105. package/cjs/trackers/impressionsTracker.js +37 -20
  106. package/cjs/trackers/uniqueKeysTracker.js +1 -1
  107. package/cjs/utils/Backoff.js +20 -0
  108. package/cjs/utils/EventEmitter.js +391 -0
  109. package/cjs/utils/filter/bloomFilter.js +37 -0
  110. package/cjs/utils/inputValidation/apiKey.js +1 -1
  111. package/cjs/utils/inputValidation/attribute.js +2 -2
  112. package/cjs/utils/inputValidation/{split.js → definition.js} +10 -10
  113. package/cjs/utils/inputValidation/{splitExistence.js → definitionExistence.js} +6 -6
  114. package/cjs/utils/inputValidation/definitions.js +25 -0
  115. package/cjs/utils/inputValidation/eventProperties.js +1 -1
  116. package/cjs/utils/inputValidation/index.js +7 -7
  117. package/cjs/utils/inputValidation/isOperational.js +4 -4
  118. package/cjs/utils/inputValidation/target.js +22 -0
  119. package/cjs/utils/labels/index.js +3 -3
  120. package/cjs/utils/lang/index.js +1 -1
  121. package/cjs/utils/lang/sets.js +4 -4
  122. package/cjs/utils/promise/timeout.js +1 -1
  123. package/cjs/utils/settingsValidation/splitFilters.js +4 -4
  124. package/cjs/utils/settingsValidation/url.js +6 -6
  125. package/esm/evaluator/condition/engineUtils.js +2 -2
  126. package/esm/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.js +64 -0
  127. package/esm/evaluator/fallbackConfigsCalculator/index.js +21 -0
  128. package/esm/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +5 -8
  129. package/esm/evaluator/fallbackTreatmentsCalculator/index.js +21 -33
  130. package/esm/evaluator/index.js +72 -48
  131. package/esm/evaluator/matchers/whitelist.js +1 -1
  132. package/esm/integrations/pluggable.js +1 -1
  133. package/esm/listeners/browser.js +4 -3
  134. package/esm/listeners/node.js +4 -4
  135. package/esm/logger/constants.js +12 -18
  136. package/esm/logger/index.js +1 -1
  137. package/esm/logger/messages/debug.js +5 -6
  138. package/esm/logger/messages/error.js +3 -3
  139. package/esm/logger/messages/info.js +1 -3
  140. package/esm/logger/messages/warn.js +8 -9
  141. package/esm/platform/browser.js +12 -0
  142. package/esm/platform/getEventSource/browser.js +4 -0
  143. package/esm/platform/getEventSource/eventsource.js +480 -0
  144. package/esm/platform/getEventSource/node.js +20 -0
  145. package/esm/platform/getFetch/browser.js +5 -0
  146. package/esm/platform/getFetch/node.js +22 -0
  147. package/esm/platform/getOptions/node.js +20 -0
  148. package/esm/platform/node.js +14 -0
  149. package/esm/readiness/constants.js +4 -3
  150. package/esm/readiness/readinessManager.js +23 -23
  151. package/esm/readiness/sdkReadinessManager.js +1 -17
  152. package/esm/sdkClient/client.js +10 -37
  153. package/esm/sdkClient/clientAttributesDecoration.js +3 -3
  154. package/esm/sdkClient/clientInputValidation.js +40 -83
  155. package/esm/sdkClient/identity.js +1 -1
  156. package/esm/sdkClient/sdkClient.js +4 -49
  157. package/esm/sdkClient/sdkLifecycle.js +67 -0
  158. package/esm/sdkClient/trackMethod.js +52 -0
  159. package/esm/sdkFactory/index.js +14 -51
  160. package/esm/sdkManager/index.js +6 -6
  161. package/esm/services/authProvider.js +63 -0
  162. package/esm/services/secureSplitHttpClient.js +35 -0
  163. package/esm/services/splitApi.js +24 -14
  164. package/esm/services/splitHttpClient.js +1 -1
  165. package/esm/storages/AbstractDefinitionsCacheAsync.js +48 -0
  166. package/esm/storages/AbstractDefinitionsCacheSync.js +71 -0
  167. package/esm/storages/KeyBuilder.js +16 -16
  168. package/esm/storages/KeyBuilderCS.js +16 -16
  169. package/esm/storages/KeyBuilderSS.js +15 -15
  170. package/esm/storages/getRolloutPlan.js +4 -4
  171. package/esm/storages/inLocalStorage/DefinitionsCacheInLocal.js +191 -0
  172. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +7 -7
  173. package/esm/storages/inLocalStorage/index.js +6 -6
  174. package/esm/storages/inLocalStorage/validateCache.js +3 -3
  175. package/esm/storages/inMemory/DefinitionsCacheInMemory.js +118 -0
  176. package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
  177. package/esm/storages/inMemory/InMemoryStorage.js +4 -4
  178. package/esm/storages/inMemory/InMemoryStorageCS.js +5 -5
  179. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +2 -2
  180. package/esm/storages/inMemory/SegmentsCacheInMemory.js +1 -1
  181. package/esm/storages/inMemory/TelemetryCacheInMemory.js +5 -5
  182. package/esm/storages/inRedis/DefinitionsCacheInRedis.js +240 -0
  183. package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
  184. package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +4 -4
  185. package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +1 -1
  186. package/esm/storages/inRedis/RedisAdapter.js +7 -7
  187. package/esm/storages/inRedis/TelemetryCacheInRedis.js +7 -7
  188. package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +1 -1
  189. package/esm/storages/inRedis/index.js +2 -2
  190. package/esm/storages/pluggable/DefinitionsCachePluggable.js +209 -0
  191. package/esm/storages/pluggable/EventsCachePluggable.js +1 -1
  192. package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +5 -5
  193. package/esm/storages/pluggable/RBSegmentsCachePluggable.js +1 -1
  194. package/esm/storages/pluggable/TelemetryCachePluggable.js +7 -7
  195. package/esm/storages/pluggable/UniqueKeysCachePluggable.js +1 -1
  196. package/esm/storages/pluggable/index.js +4 -4
  197. package/esm/storages/pluggable/wrapperAdapter.js +1 -1
  198. package/esm/storages/setRolloutPlan.js +6 -6
  199. package/esm/storages/utils.js +6 -6
  200. package/esm/sync/offline/splitsParser/parseCondition.js +1 -1
  201. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +6 -6
  202. package/esm/sync/polling/fetchers/splitChangesFetcher.js +25 -16
  203. package/esm/sync/polling/pollingManagerCS.js +15 -15
  204. package/esm/sync/polling/pollingManagerSS.js +13 -13
  205. package/esm/sync/polling/syncTasks/definitionsSyncTask.js +8 -0
  206. package/esm/sync/polling/updaters/definitionChangesUpdater.js +200 -0
  207. package/esm/sync/polling/updaters/mySegmentsUpdater.js +3 -3
  208. package/esm/sync/polling/updaters/segmentChangesUpdater.js +7 -7
  209. package/esm/sync/streaming/SSEClient/index.js +2 -2
  210. package/esm/sync/streaming/SSEHandler/NotificationKeeper.js +2 -2
  211. package/esm/sync/streaming/SSEHandler/index.js +2 -2
  212. package/esm/sync/streaming/UpdateWorkers/{SplitsUpdateWorker.js → DefinitionsUpdateWorker.js} +17 -17
  213. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
  214. package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
  215. package/esm/sync/streaming/constants.js +2 -2
  216. package/esm/sync/streaming/parseUtils.js +10 -10
  217. package/esm/sync/streaming/pushManager.js +16 -16
  218. package/esm/sync/submitters/impressionsSubmitter.js +6 -6
  219. package/esm/sync/submitters/submitter.js +1 -1
  220. package/esm/sync/submitters/telemetrySubmitter.js +1 -2
  221. package/esm/sync/syncManagerOnline.js +8 -5
  222. package/esm/trackers/eventTracker.js +10 -12
  223. package/esm/trackers/impressionObserver/buildKey.js +1 -1
  224. package/esm/trackers/impressionsTracker.js +38 -21
  225. package/esm/trackers/uniqueKeysTracker.js +1 -1
  226. package/esm/utils/Backoff.js +20 -0
  227. package/esm/utils/EventEmitter.js +387 -0
  228. package/esm/utils/filter/bloomFilter.js +33 -0
  229. package/esm/utils/inputValidation/apiKey.js +1 -1
  230. package/esm/utils/inputValidation/attribute.js +2 -2
  231. package/esm/utils/inputValidation/{split.js → definition.js} +8 -8
  232. package/esm/utils/inputValidation/definitionExistence.js +15 -0
  233. package/esm/utils/inputValidation/definitions.js +21 -0
  234. package/esm/utils/inputValidation/index.js +3 -3
  235. package/esm/utils/inputValidation/isOperational.js +4 -4
  236. package/esm/utils/inputValidation/target.js +18 -0
  237. package/esm/utils/labels/index.js +2 -2
  238. package/esm/utils/lang/sets.js +4 -4
  239. package/esm/utils/promise/timeout.js +1 -1
  240. package/esm/utils/settingsValidation/splitFilters.js +4 -4
  241. package/esm/utils/settingsValidation/url.js +6 -6
  242. package/package.json +15 -6
  243. package/src/dtos/types.ts +65 -70
  244. package/src/evaluator/Engine.ts +4 -4
  245. package/src/evaluator/combiners/and.ts +3 -3
  246. package/src/evaluator/combiners/ifelseif.ts +2 -2
  247. package/src/evaluator/condition/engineUtils.ts +2 -2
  248. package/src/evaluator/condition/index.ts +3 -3
  249. package/src/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.ts +76 -0
  250. package/src/evaluator/fallbackConfigsCalculator/index.ts +24 -0
  251. package/src/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.ts +5 -7
  252. package/src/evaluator/fallbackTreatmentsCalculator/index.ts +27 -41
  253. package/src/evaluator/index.ts +86 -51
  254. package/src/evaluator/matchers/dependency.ts +2 -2
  255. package/src/evaluator/matchers/matcherTypes.ts +2 -2
  256. package/src/evaluator/matchers/prerequisites.ts +4 -4
  257. package/src/evaluator/matchers/rbsegment.ts +2 -2
  258. package/src/evaluator/matchers/whitelist.ts +2 -2
  259. package/src/evaluator/matchersTransform/index.ts +2 -2
  260. package/src/evaluator/matchersTransform/whitelist.ts +2 -2
  261. package/src/evaluator/parser/index.ts +4 -4
  262. package/src/evaluator/treatments/index.ts +2 -2
  263. package/src/evaluator/types.ts +6 -6
  264. package/src/evaluator/value/index.ts +1 -1
  265. package/src/integrations/pluggable.ts +1 -1
  266. package/src/listeners/browser.ts +11 -8
  267. package/src/listeners/node.ts +2 -5
  268. package/src/logger/constants.ts +12 -18
  269. package/src/logger/messages/debug.ts +5 -6
  270. package/src/logger/messages/error.ts +3 -3
  271. package/src/logger/messages/info.ts +1 -3
  272. package/src/logger/messages/warn.ts +8 -9
  273. package/src/platform/browser.ts +14 -0
  274. package/src/platform/getEventSource/browser.ts +4 -0
  275. package/src/platform/getEventSource/eventsource.js +519 -0
  276. package/src/platform/getEventSource/node.ts +23 -0
  277. package/src/platform/getFetch/browser.ts +5 -0
  278. package/src/platform/getFetch/node.ts +27 -0
  279. package/src/platform/getOptions/node.ts +24 -0
  280. package/src/platform/node.ts +16 -0
  281. package/src/readiness/constants.ts +4 -3
  282. package/src/readiness/readinessManager.ts +22 -22
  283. package/src/readiness/sdkReadinessManager.ts +1 -16
  284. package/src/readiness/types.ts +10 -16
  285. package/src/sdkClient/client.ts +11 -41
  286. package/src/sdkClient/clientInputValidation.ts +44 -84
  287. package/src/sdkClient/sdkClient.ts +5 -54
  288. package/src/sdkClient/sdkLifecycle.ts +79 -0
  289. package/src/sdkClient/trackMethod.ts +59 -0
  290. package/src/sdkFactory/index.ts +15 -59
  291. package/src/sdkFactory/types.ts +19 -16
  292. package/src/sdkManager/index.ts +15 -15
  293. package/src/services/authProvider.ts +86 -0
  294. package/src/services/secureSplitHttpClient.ts +44 -0
  295. package/src/services/splitApi.ts +14 -2
  296. package/src/services/types.ts +7 -2
  297. package/src/storages/AbstractDefinitionsCacheAsync.ts +63 -0
  298. package/src/storages/AbstractDefinitionsCacheSync.ts +95 -0
  299. package/src/storages/KeyBuilder.ts +6 -6
  300. package/src/storages/KeyBuilderCS.ts +6 -6
  301. package/src/storages/KeyBuilderSS.ts +2 -2
  302. package/src/storages/getRolloutPlan.ts +3 -3
  303. package/src/storages/inLocalStorage/DefinitionsCacheInLocal.ts +234 -0
  304. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +8 -8
  305. package/src/storages/inLocalStorage/index.ts +6 -6
  306. package/src/storages/inLocalStorage/validateCache.ts +4 -4
  307. package/src/storages/inMemory/DefinitionsCacheInMemory.ts +130 -0
  308. package/src/storages/inMemory/InMemoryStorage.ts +4 -4
  309. package/src/storages/inMemory/InMemoryStorageCS.ts +5 -5
  310. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +3 -3
  311. package/src/storages/inMemory/SegmentsCacheInMemory.ts +1 -1
  312. package/src/storages/inMemory/TelemetryCacheInMemory.ts +5 -5
  313. package/src/storages/inRedis/{SplitsCacheInRedis.ts → DefinitionsCacheInRedis.ts} +69 -69
  314. package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +2 -2
  315. package/src/storages/inRedis/index.ts +2 -2
  316. package/src/storages/pluggable/DefinitionsCachePluggable.ts +230 -0
  317. package/src/storages/pluggable/RBSegmentsCachePluggable.ts +2 -2
  318. package/src/storages/pluggable/index.ts +2 -2
  319. package/src/storages/setRolloutPlan.ts +7 -7
  320. package/src/storages/types.ts +34 -29
  321. package/src/sync/offline/splitsParser/parseCondition.ts +2 -2
  322. package/src/sync/offline/splitsParser/splitsParserFromSettings.ts +3 -3
  323. package/src/sync/offline/splitsParser/types.ts +6 -3
  324. package/src/sync/offline/syncManagerOffline.ts +2 -2
  325. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +14 -14
  326. package/src/sync/polling/fetchers/splitChangesFetcher.ts +58 -23
  327. package/src/sync/polling/fetchers/types.ts +5 -3
  328. package/src/sync/polling/pollingManagerCS.ts +16 -14
  329. package/src/sync/polling/pollingManagerSS.ts +15 -13
  330. package/src/sync/polling/syncTasks/{splitsSyncTask.ts → definitionsSyncTask.ts} +11 -12
  331. package/src/sync/polling/types.ts +3 -3
  332. package/src/sync/polling/updaters/definitionChangesUpdater.ts +239 -0
  333. package/src/sync/polling/updaters/mySegmentsUpdater.ts +3 -3
  334. package/src/sync/polling/updaters/segmentChangesUpdater.ts +7 -7
  335. package/src/sync/streaming/AuthClient/index.ts +2 -2
  336. package/src/sync/streaming/AuthClient/types.ts +14 -11
  337. package/src/sync/streaming/SSEClient/index.ts +2 -2
  338. package/src/sync/streaming/SSEClient/types.ts +2 -2
  339. package/src/sync/streaming/SSEHandler/NotificationKeeper.ts +2 -2
  340. package/src/sync/streaming/SSEHandler/index.ts +2 -2
  341. package/src/sync/streaming/UpdateWorkers/{SplitsUpdateWorker.ts → DefinitionsUpdateWorker.ts} +21 -21
  342. package/src/sync/streaming/constants.ts +2 -2
  343. package/src/sync/streaming/parseUtils.ts +12 -12
  344. package/src/sync/streaming/pushManager.ts +18 -18
  345. package/src/sync/streaming/types.ts +2 -2
  346. package/src/sync/submitters/impressionsSubmitter.ts +9 -9
  347. package/src/sync/submitters/telemetrySubmitter.ts +1 -2
  348. package/src/sync/submitters/types.ts +3 -0
  349. package/src/sync/syncManagerOnline.ts +9 -5
  350. package/src/trackers/eventTracker.ts +7 -10
  351. package/src/trackers/impressionsTracker.ts +42 -26
  352. package/src/trackers/types.ts +3 -1
  353. package/src/utils/Backoff.ts +21 -0
  354. package/src/utils/EventEmitter.js +444 -0
  355. package/src/utils/filter/bloomFilter.ts +38 -0
  356. package/src/utils/inputValidation/definition.ts +27 -0
  357. package/src/utils/inputValidation/definitionExistence.ts +19 -0
  358. package/src/utils/inputValidation/definitions.ts +21 -0
  359. package/src/utils/inputValidation/index.ts +3 -3
  360. package/src/utils/inputValidation/isOperational.ts +4 -4
  361. package/src/utils/inputValidation/target.ts +21 -0
  362. package/src/utils/inputValidation/trafficTypeExistence.ts +2 -2
  363. package/src/utils/jwt/types.ts +1 -1
  364. package/src/utils/labels/index.ts +2 -2
  365. package/src/utils/lang/sets.ts +4 -2
  366. package/src/utils/settingsValidation/splitFilters.ts +3 -3
  367. package/src/utils/settingsValidation/url.ts +1 -1
  368. package/types/splitio.d.ts +222 -11
  369. package/cjs/storages/AbstractSplitsCacheAsync.js +0 -51
  370. package/cjs/storages/AbstractSplitsCacheSync.js +0 -76
  371. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +0 -194
  372. package/cjs/storages/inMemory/SplitsCacheInMemory.js +0 -121
  373. package/cjs/storages/inRedis/SplitsCacheInRedis.js +0 -243
  374. package/cjs/storages/pluggable/SplitsCachePluggable.js +0 -212
  375. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +0 -13
  376. package/cjs/utils/inputValidation/splits.js +0 -25
  377. package/esm/storages/AbstractSplitsCacheAsync.js +0 -48
  378. package/esm/storages/AbstractSplitsCacheSync.js +0 -71
  379. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +0 -191
  380. package/esm/storages/inMemory/SplitsCacheInMemory.js +0 -118
  381. package/esm/storages/inRedis/SplitsCacheInRedis.js +0 -240
  382. package/esm/storages/pluggable/SplitsCachePluggable.js +0 -209
  383. package/esm/sync/polling/syncTasks/splitsSyncTask.js +0 -9
  384. package/esm/sync/polling/updaters/splitChangesUpdater.js +0 -192
  385. package/esm/utils/inputValidation/splitExistence.js +0 -15
  386. package/esm/utils/inputValidation/splits.js +0 -21
  387. package/src/storages/AbstractSplitsCacheAsync.ts +0 -63
  388. package/src/storages/AbstractSplitsCacheSync.ts +0 -95
  389. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +0 -234
  390. package/src/storages/inMemory/SplitsCacheInMemory.ts +0 -130
  391. package/src/storages/pluggable/SplitsCachePluggable.ts +0 -230
  392. package/src/sync/polling/updaters/splitChangesUpdater.ts +0 -230
  393. package/src/utils/inputValidation/split.ts +0 -27
  394. package/src/utils/inputValidation/splitExistence.ts +0 -19
  395. package/src/utils/inputValidation/splits.ts +0 -21
@@ -1,12 +1,12 @@
1
1
  import { ISettings } from '../../../types';
2
- import { ISplitChangesResponse } from '../../../dtos/types';
3
- import { IFetchSplitChanges, IResponse } from '../../../services/types';
4
- import { IStorageBase } from '../../../storages/types';
2
+ import { IDefinition, IRBSegment, IDefinitionChangesResponse } from '../../../dtos/types';
3
+ import { IResponse } from '../../../services/types';
5
4
  import { FLAG_SPEC_VERSION } from '../../../utils/constants';
6
5
  import { base } from '../../../utils/settingsValidation';
7
- import { ISplitChangesFetcher } from './types';
8
- import { LOG_PREFIX_SYNC_SPLITS } from '../../../logger/constants';
6
+ import { IDefinitionChangesFetcher } from './types';
7
+ import { LOG_PREFIX_SYNC } from '../../../logger/constants';
9
8
  import { checkIfServerSide } from '../../../utils/key';
9
+ import { ISdkFactoryContextSync } from '../../../sdkFactory/types';
10
10
 
11
11
  const PROXY_CHECK_INTERVAL_MILLIS_CS = 60 * 60 * 1000; // 1 hour in Client Side
12
12
  const PROXY_CHECK_INTERVAL_MILLIS_SS = 24 * PROXY_CHECK_INTERVAL_MILLIS_CS; // 24 hours in Server Side
@@ -15,25 +15,59 @@ function sdkEndpointOverridden(settings: ISettings) {
15
15
  return settings.urls.sdk !== base.urls.sdk;
16
16
  }
17
17
 
18
+ export type ISplit = IDefinition;
19
+
20
+ /** JSON response of `/splitChanges` */
21
+ export interface ISplitChangesResponse {
22
+ ff?: {
23
+ t: number,
24
+ s?: number,
25
+ d?: ISplit[] | null,
26
+ },
27
+ rbs?: {
28
+ t: number,
29
+ s?: number,
30
+ d?: IRBSegment[] | null,
31
+ }
32
+ }
33
+
34
+ /** JSON response of `/splitChanges` for flag spec version 1.2 or below */
35
+ export interface ISplitChangesLegacyResponse {
36
+ till: number,
37
+ since?: number,
38
+ splits: ISplit[]
39
+ }
40
+
41
+ function isSplitChangesLegacyResponse(data: ISplitChangesResponse | ISplitChangesLegacyResponse): data is ISplitChangesLegacyResponse {
42
+ return (data as ISplitChangesLegacyResponse).splits != null;
43
+ }
44
+
45
+ function partitionByStatus<T extends { status?: string; name: string }>(items: T[], till: number, since?: number) {
46
+ const updated: T[] = [], removed: string[] = [];
47
+ items.forEach(item => item.status === 'ARCHIVED' ? removed.push(item.name) : updated.push(item));
48
+ return { updated, removed, till, since };
49
+ }
50
+
18
51
  /**
19
52
  * Factory of SplitChanges fetcher.
20
53
  * SplitChanges fetcher is a wrapper around `splitChanges` API service that parses the response and handle errors.
21
54
  */
22
55
  // @TODO breaking: drop support for Split Proxy below v5.10.0 and simplify the implementation
23
- export function splitChangesFetcherFactory(fetchSplitChanges: IFetchSplitChanges, settings: ISettings, storage: Pick<IStorageBase, 'splits' | 'rbSegments'>): ISplitChangesFetcher {
56
+ export function splitChangesFetcherFactory(params: ISdkFactoryContextSync): IDefinitionChangesFetcher {
24
57
 
58
+ const { splitApi: { fetchSplitChanges }, settings, storage } = params;
25
59
  const log = settings.log;
26
60
  const PROXY_CHECK_INTERVAL_MILLIS = checkIfServerSide(settings) ? PROXY_CHECK_INTERVAL_MILLIS_SS : PROXY_CHECK_INTERVAL_MILLIS_CS;
27
61
  let lastProxyCheckTimestamp: number | undefined;
28
62
 
29
- return function splitChangesFetcher(
63
+ function splitChangesFetcher(
30
64
  since: number,
31
65
  noCache?: boolean,
32
66
  till?: number,
33
67
  rbSince?: number,
34
68
  // Optional decorator for `fetchSplitChanges` promise, such as timeout or time tracker
35
69
  decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
36
- ): Promise<ISplitChangesResponse> {
70
+ ): Promise<IDefinitionChangesResponse> {
37
71
 
38
72
  // Recheck proxy
39
73
  if (lastProxyCheckTimestamp && (Date.now() - lastProxyCheckTimestamp) > PROXY_CHECK_INTERVAL_MILLIS) {
@@ -44,7 +78,7 @@ export function splitChangesFetcherFactory(fetchSplitChanges: IFetchSplitChanges
44
78
  .catch((err) => {
45
79
  // Handle proxy error with spec 1.3
46
80
  if ((!err.statusCode || err.statusCode === 400) && sdkEndpointOverridden(settings) && settings.sync.flagSpecVersion === FLAG_SPEC_VERSION) {
47
- log.error(LOG_PREFIX_SYNC_SPLITS + 'Proxy error detected. Retrying with spec 1.2. If you are using Split Proxy, please upgrade to latest version');
81
+ log.error(LOG_PREFIX_SYNC + 'Proxy error detected. Retrying with spec 1.2. If you are using Split Proxy, please upgrade to latest version');
48
82
  lastProxyCheckTimestamp = Date.now();
49
83
  settings.sync.flagSpecVersion = '1.2'; // fallback to 1.2 spec
50
84
  return fetchSplitChanges(since, noCache, till); // retry request without rbSince
@@ -56,31 +90,32 @@ export function splitChangesFetcherFactory(fetchSplitChanges: IFetchSplitChanges
56
90
 
57
91
  return splitsPromise
58
92
  .then(resp => resp.json())
59
- .then(data => {
93
+ .then((data: ISplitChangesResponse | ISplitChangesLegacyResponse) => {
60
94
  // Using flag spec version 1.2 or below
61
- if (data.splits) {
62
- return {
63
- ff: {
64
- d: data.splits,
65
- s: data.since,
66
- t: data.till
67
- }
68
- };
95
+ if (isSplitChangesLegacyResponse(data)) {
96
+ return { d: partitionByStatus(data.splits || [], data.till, data.since) };
69
97
  }
70
98
 
71
99
  // Proxy recovery
72
100
  if (lastProxyCheckTimestamp) {
73
- log.info(LOG_PREFIX_SYNC_SPLITS + 'Proxy error recovered');
101
+ log.info(LOG_PREFIX_SYNC + 'Proxy error recovered');
74
102
  lastProxyCheckTimestamp = undefined;
75
103
  return splitChangesFetcher(-1, undefined, undefined, -1)
76
- .then((splitChangesResponse: ISplitChangesResponse) =>
77
- Promise.all([storage.splits.clear(), storage.rbSegments.clear()])
104
+ .then((splitChangesResponse: IDefinitionChangesResponse) =>
105
+ Promise.all([storage.definitions.clear(), storage.rbSegments.clear()])
78
106
  .then(() => splitChangesResponse)
79
107
  );
80
108
  }
81
109
 
82
- return data;
110
+ const { ff, rbs } = data;
111
+
112
+ return {
113
+ d: ff?.d ? partitionByStatus(ff.d, ff.t, ff.s) : undefined,
114
+ rbs: rbs?.d ? partitionByStatus(rbs.d, rbs.t, rbs.s) : undefined,
115
+ };
83
116
  });
84
- };
117
+ }
85
118
 
119
+ splitChangesFetcher.type = 'feature flags' as const;
120
+ return splitChangesFetcher;
86
121
  }
@@ -1,13 +1,15 @@
1
- import { ISplitChangesResponse, ISegmentChangesResponse, IMembershipsResponse } from '../../../dtos/types';
1
+ import { IDefinitionChangesResponse, ISegmentChangesResponse, IMembershipsResponse } from '../../../dtos/types';
2
2
  import { IResponse } from '../../../services/types';
3
3
 
4
- export type ISplitChangesFetcher = (
4
+ export type IDefinitionChangesFetcher = ((
5
5
  since: number,
6
6
  noCache?: boolean,
7
7
  till?: number,
8
8
  rbSince?: number,
9
9
  decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
10
- ) => Promise<ISplitChangesResponse>
10
+ ) => Promise<IDefinitionChangesResponse>) & {
11
+ type: 'configs' | 'feature flags'
12
+ }
11
13
 
12
14
  export type ISegmentChangesFetcher = (
13
15
  since: number,
@@ -3,26 +3,28 @@ import { forOwn } from '../../utils/lang';
3
3
  import { IReadinessManager } from '../../readiness/types';
4
4
  import { IStorageSync } from '../../storages/types';
5
5
  import { mySegmentsSyncTaskFactory } from './syncTasks/mySegmentsSyncTask';
6
- import { splitsSyncTaskFactory } from './syncTasks/splitsSyncTask';
6
+ import { definitionsSyncTaskFactory } from './syncTasks/definitionsSyncTask';
7
7
  import { getMatching } from '../../utils/key';
8
- import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../readiness/constants';
8
+ import { SDK_DEFINITIONS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../readiness/constants';
9
9
  import { POLLING_SMART_PAUSING, POLLING_START, POLLING_STOP } from '../../logger/constants';
10
10
  import { ISdkFactoryContextSync } from '../../sdkFactory/types';
11
- import { usesSegmentsSync } from '../../storages/AbstractSplitsCacheSync';
11
+ import { usesSegmentsSync } from '../../storages/AbstractDefinitionsCacheSync';
12
12
  import { SdkUpdateMetadata } from '../../../types/splitio';
13
+ import { IDefinitionChangesFetcher } from './fetchers/types';
13
14
 
14
15
  /**
15
16
  * Expose start / stop mechanism for polling data from services.
16
17
  * For client-side API with multiple clients.
17
18
  */
18
19
  export function pollingManagerCSFactory(
19
- params: ISdkFactoryContextSync
20
+ params: ISdkFactoryContextSync,
21
+ definitionChangesFetcher: IDefinitionChangesFetcher
20
22
  ): IPollingManagerCS {
21
23
 
22
24
  const { splitApi, storage, readiness, settings } = params;
23
25
  const log = settings.log;
24
26
 
25
- const splitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings, true);
27
+ const definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, true);
26
28
 
27
29
  // Map of matching keys to their corresponding MySegmentsSyncTask.
28
30
  const mySegmentsSyncTasks: Record<string, IMySegmentsSyncTask> = {};
@@ -43,8 +45,8 @@ export function pollingManagerCSFactory(
43
45
  }
44
46
 
45
47
  // smart pausing
46
- readiness.splits.on(SDK_SPLITS_ARRIVED, () => {
47
- if (!splitsSyncTask.isRunning()) return; // noop if not doing polling
48
+ readiness.definitions.on(SDK_DEFINITIONS_ARRIVED, () => {
49
+ if (!definitionsSyncTask.isRunning()) return; // noop if not doing polling
48
50
  const usingSegments = usesSegmentsSync(storage);
49
51
  if (usingSegments !== mySegmentsSyncTask.isRunning()) {
50
52
  log.info(POLLING_SMART_PAUSING, [usingSegments ? 'ON' : 'OFF']);
@@ -64,21 +66,21 @@ export function pollingManagerCSFactory(
64
66
  if (!readiness.isReady() && !usesSegmentsSync(storage)) readiness.segments.emit(SDK_SEGMENTS_ARRIVED, metadata);
65
67
  }
66
68
  if (!usesSegmentsSync(storage)) setTimeout(smartReady, 0);
67
- else readiness.splits.once(SDK_SPLITS_ARRIVED, smartReady);
69
+ else readiness.definitions.once(SDK_DEFINITIONS_ARRIVED, smartReady);
68
70
 
69
71
  mySegmentsSyncTasks[matchingKey] = mySegmentsSyncTask;
70
72
  return mySegmentsSyncTask;
71
73
  }
72
74
 
73
75
  return {
74
- splitsSyncTask,
76
+ definitionsSyncTask,
75
77
  segmentsSyncTask: mySegmentsSyncTask,
76
78
 
77
79
  // Start periodic fetching (polling)
78
80
  start() {
79
81
  log.info(POLLING_START);
80
82
 
81
- splitsSyncTask.start();
83
+ definitionsSyncTask.start();
82
84
  if (usesSegmentsSync(storage)) startMySegmentsSyncTasks();
83
85
  },
84
86
 
@@ -86,16 +88,16 @@ export function pollingManagerCSFactory(
86
88
  stop() {
87
89
  log.info(POLLING_STOP);
88
90
 
89
- if (splitsSyncTask.isRunning()) splitsSyncTask.stop();
91
+ if (definitionsSyncTask.isRunning()) definitionsSyncTask.stop();
90
92
  stopMySegmentsSyncTasks();
91
93
  },
92
94
 
93
95
  // Used by SyncManager to know if running in polling mode.
94
- isRunning: splitsSyncTask.isRunning,
96
+ isRunning: definitionsSyncTask.isRunning,
95
97
 
96
- // fetch splits and segments
98
+ // fetch definitions and segments
97
99
  syncAll() {
98
- const promises = [splitsSyncTask.execute()];
100
+ const promises = [definitionsSyncTask.execute()];
99
101
  forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask) => {
100
102
  promises.push(mySegmentsSyncTask.execute());
101
103
  });
@@ -1,36 +1,38 @@
1
- import { splitsSyncTaskFactory } from './syncTasks/splitsSyncTask';
1
+ import { definitionsSyncTaskFactory } from './syncTasks/definitionsSyncTask';
2
2
  import { segmentsSyncTaskFactory } from './syncTasks/segmentsSyncTask';
3
- import { IPollingManager, ISegmentsSyncTask, ISplitsSyncTask } from './types';
3
+ import { IPollingManager, ISegmentsSyncTask, IDefinitionsSyncTask } from './types';
4
4
  import { POLLING_START, POLLING_STOP, LOG_PREFIX_SYNC_POLLING } from '../../logger/constants';
5
5
  import { ISdkFactoryContextSync } from '../../sdkFactory/types';
6
+ import { IDefinitionChangesFetcher } from './fetchers/types';
6
7
 
7
8
  /**
8
9
  * Expose start / stop mechanism for pulling data from services.
9
10
  */
10
11
  export function pollingManagerSSFactory(
11
- params: ISdkFactoryContextSync
12
+ params: ISdkFactoryContextSync,
13
+ definitionChangesFetcher: IDefinitionChangesFetcher
12
14
  ): IPollingManager {
13
15
 
14
16
  const { splitApi, storage, readiness, settings } = params;
15
17
  const log = settings.log;
16
18
 
17
- const splitsSyncTask: ISplitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings);
19
+ const definitionsSyncTask: IDefinitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings);
18
20
  const segmentsSyncTask: ISegmentsSyncTask = segmentsSyncTaskFactory(splitApi.fetchSegmentChanges, storage, readiness, settings);
19
21
 
20
22
  return {
21
- splitsSyncTask,
23
+ definitionsSyncTask,
22
24
  segmentsSyncTask,
23
25
 
24
26
  // Start periodic fetching (polling)
25
27
  start() {
26
28
  log.info(POLLING_START);
27
- log.debug(LOG_PREFIX_SYNC_POLLING + `Splits will be refreshed each ${settings.scheduler.featuresRefreshRate} millis`);
28
- log.debug(LOG_PREFIX_SYNC_POLLING + `Segments will be refreshed each ${settings.scheduler.segmentsRefreshRate} millis`);
29
+ log.debug(LOG_PREFIX_SYNC_POLLING + `${definitionChangesFetcher.type} will be refreshed each ${settings.scheduler.featuresRefreshRate} millis`);
30
+ log.debug(LOG_PREFIX_SYNC_POLLING + `segments will be refreshed each ${settings.scheduler.segmentsRefreshRate} millis`);
29
31
 
30
- const startingUp = splitsSyncTask.start();
32
+ const startingUp = definitionsSyncTask.start();
31
33
  if (startingUp) {
32
34
  startingUp.then(() => {
33
- if (splitsSyncTask.isRunning()) segmentsSyncTask.start();
35
+ if (definitionsSyncTask.isRunning()) segmentsSyncTask.start();
34
36
  });
35
37
  }
36
38
  },
@@ -39,16 +41,16 @@ export function pollingManagerSSFactory(
39
41
  stop() {
40
42
  log.info(POLLING_STOP);
41
43
 
42
- if (splitsSyncTask.isRunning()) splitsSyncTask.stop();
44
+ if (definitionsSyncTask.isRunning()) definitionsSyncTask.stop();
43
45
  if (segmentsSyncTask.isRunning()) segmentsSyncTask.stop();
44
46
  },
45
47
 
46
48
  // Used by SyncManager to know if running in polling mode.
47
- isRunning: splitsSyncTask.isRunning,
49
+ isRunning: definitionsSyncTask.isRunning,
48
50
 
49
51
  syncAll() {
50
- // fetch splits and segments. There is no need to catch this promise (`SplitChangesUpdater` is always resolved with a boolean value)
51
- return splitsSyncTask.execute().then(() => {
52
+ // fetch definitions and segments. There is no need to catch this promise (`DefinitionChangesUpdater` is always resolved with a boolean value)
53
+ return definitionsSyncTask.execute().then(() => {
52
54
  return segmentsSyncTask.execute();
53
55
  });
54
56
  }
@@ -1,35 +1,34 @@
1
1
  import { IStorageSync } from '../../../storages/types';
2
2
  import { IReadinessManager } from '../../../readiness/types';
3
3
  import { syncTaskFactory } from '../../syncTask';
4
- import { ISplitsSyncTask } from '../types';
5
- import { splitChangesFetcherFactory } from '../fetchers/splitChangesFetcher';
6
- import { IFetchSplitChanges } from '../../../services/types';
4
+ import { IDefinitionsSyncTask } from '../types';
7
5
  import { ISettings } from '../../../types';
8
- import { splitChangesUpdaterFactory } from '../updaters/splitChangesUpdater';
6
+ import { definitionChangesUpdaterFactory } from '../updaters/definitionChangesUpdater';
7
+ import { IDefinitionChangesFetcher } from '../fetchers/types';
9
8
 
10
9
  /**
11
- * Creates a sync task that periodically executes a `splitChangesUpdater` task
10
+ * Creates a sync task that periodically executes a `definitionChangesUpdater` task
12
11
  */
13
- export function splitsSyncTaskFactory(
14
- fetchSplitChanges: IFetchSplitChanges,
12
+ export function definitionsSyncTaskFactory(
13
+ definitionChangesFetcher: IDefinitionChangesFetcher,
15
14
  storage: IStorageSync,
16
15
  readiness: IReadinessManager,
17
16
  settings: ISettings,
18
17
  isClientSide?: boolean
19
- ): ISplitsSyncTask {
18
+ ): IDefinitionsSyncTask {
20
19
  return syncTaskFactory(
21
20
  settings.log,
22
- splitChangesUpdaterFactory(
21
+ definitionChangesUpdaterFactory(
23
22
  settings.log,
24
- splitChangesFetcherFactory(fetchSplitChanges, settings, storage),
23
+ definitionChangesFetcher,
25
24
  storage,
26
25
  settings.sync.__splitFiltersValidation,
27
- readiness.splits,
26
+ readiness.definitions,
28
27
  settings.startup.requestTimeoutBeforeReady,
29
28
  settings.startup.retriesOnFailureBeforeReady,
30
29
  isClientSide
31
30
  ),
32
31
  settings.scheduler.featuresRefreshRate,
33
- 'splitChangesUpdater',
32
+ 'definitionChangesUpdater',
34
33
  );
35
34
  }
@@ -1,10 +1,10 @@
1
- import { IRBSegment, ISplit } from '../../dtos/types';
1
+ import { IRBSegment, IDefinition } 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 IDefinitionsSyncTask extends ISyncTask<[noCache?: boolean, till?: number, definitionUpdateNotification?: { payload: IDefinition | IRBSegment, changeNumber: number }], boolean> { }
8
8
 
9
9
  export interface ISegmentsSyncTask extends ISyncTask<[fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number], boolean> { }
10
10
 
@@ -19,7 +19,7 @@ export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegment
19
19
 
20
20
  export interface IPollingManager extends ITask {
21
21
  syncAll(): Promise<any>
22
- splitsSyncTask: ISplitsSyncTask
22
+ definitionsSyncTask: IDefinitionsSyncTask
23
23
  segmentsSyncTask: ISyncTask
24
24
  }
25
25
 
@@ -0,0 +1,239 @@
1
+ import { ISegmentsCacheBase, IStorageBase } from '../../../storages/types';
2
+ import { IDefinitionChangesFetcher } from '../fetchers/types';
3
+ import { IRBSegment, IDefinition, IDefinitionChangesResponse, ISplitFiltersValidation, MaybeThenable } from '../../../dtos/types';
4
+ import { IDefinitionsEventEmitter } from '../../../readiness/types';
5
+ import { timeout } from '../../../utils/promise/timeout';
6
+ import { SDK_DEFINITIONS_ARRIVED, FLAGS_UPDATE, SEGMENTS_UPDATE, CONFIGS_UPDATE } from '../../../readiness/constants';
7
+ import { ILogger } from '../../../logger/types';
8
+ import { SYNC_FETCH, SYNC_UPDATE, SYNC_FETCH_FAILS, SYNC_FETCH_RETRY } from '../../../logger/constants';
9
+ import { startsWith } from '../../../utils/lang';
10
+ import { IN_RULE_BASED_SEGMENT, IN_SEGMENT, RULE_BASED_SEGMENT, STANDARD_SEGMENT } from '../../../utils/constants';
11
+ import { setToArray } from '../../../utils/lang/sets';
12
+ import { SPLIT_UPDATE } from '../../streaming/constants';
13
+ import { SdkUpdateMetadata } from '../../../../types/splitio';
14
+ import { ISplit } from '../fetchers/splitChangesFetcher';
15
+
16
+ export type InstantUpdate = { payload: ISplit | IRBSegment, changeNumber: number, type: string };
17
+ type DefinitionChangesUpdater = (noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) => Promise<boolean>
18
+
19
+ // Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
20
+ // Returns a promise that could be rejected.
21
+ // @TODO review together with Segments and MySegments storage APIs
22
+ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
23
+ let registeredSegments = Promise.resolve(segments.getRegisteredSegments());
24
+ return registeredSegments.then(segmentNames => {
25
+ return Promise.all(segmentNames.map(segmentName => segments.getChangeNumber(segmentName)))
26
+ .then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== undefined));
27
+ });
28
+ }
29
+
30
+ /**
31
+ * Collect segments from a raw FF or RBS definition.
32
+ * Exported for testing purposes.
33
+ */
34
+ export function parseSegments(ruleEntity: IDefinition | IRBSegment, matcherType: typeof IN_SEGMENT | typeof IN_RULE_BASED_SEGMENT = IN_SEGMENT): Set<string> {
35
+ const { conditions, excluded } = ruleEntity as IRBSegment;
36
+
37
+ const segments = new Set<string>();
38
+ if (excluded && excluded.segments) {
39
+ excluded.segments.forEach(({ type, name }) => {
40
+ if ((type === STANDARD_SEGMENT && matcherType === IN_SEGMENT) || (type === RULE_BASED_SEGMENT && matcherType === IN_RULE_BASED_SEGMENT)) {
41
+ segments.add(name);
42
+ }
43
+ });
44
+ }
45
+
46
+ if (conditions) {
47
+ for (let i = 0; i < conditions.length; i++) {
48
+ const matchers = conditions[i].matcherGroup.matchers;
49
+
50
+ matchers.forEach(matcher => {
51
+ if (matcher.matcherType === matcherType) segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
52
+ });
53
+ }
54
+ }
55
+
56
+ return segments;
57
+ }
58
+
59
+ interface IDefinitionMutations<T extends IDefinition | IRBSegment> {
60
+ added: T[],
61
+ removed: string[],
62
+ names: string[]
63
+ }
64
+
65
+ /**
66
+ * If there are defined filters and one definition doesn't match with them, its status is changed to 'ARCHIVE' to avoid storing it
67
+ * If there is `bySet` filter, `byName` and `byPrefix` filters are ignored
68
+ *
69
+ * @param definition - definition to be evaluated
70
+ * @param filters - splitFiltersValidation bySet | byName
71
+ */
72
+ function matchFilters(definition: IDefinition, filters: ISplitFiltersValidation) {
73
+ const { bySet: setsFilter, byName: namesFilter, byPrefix: prefixFilter } = filters.groupedFilters;
74
+ if (setsFilter.length > 0) return definition.sets && definition.sets.some((definitionSet: string) => setsFilter.indexOf(definitionSet) > -1);
75
+
76
+ const namesFilterConfigured = namesFilter.length > 0;
77
+ const prefixFilterConfigured = prefixFilter.length > 0;
78
+
79
+ if (!namesFilterConfigured && !prefixFilterConfigured) return true;
80
+
81
+ const matchNames = namesFilterConfigured && namesFilter.indexOf(definition.name) > -1;
82
+ const matchPrefix = prefixFilterConfigured && prefixFilter.some(prefix => startsWith(definition.name, prefix));
83
+ return matchNames || matchPrefix;
84
+ }
85
+
86
+ /**
87
+ * Given the list of definitions from /splitChanges or /configs endpoint, it returns the mutations,
88
+ * i.e., an object with added definitions, removed definitions, and used segments.
89
+ * Exported for testing purposes.
90
+ */
91
+ export function computeMutation<T extends IDefinition | IRBSegment>(update: { updated: T[], removed: string[] }, segments: Set<string>, filters?: ISplitFiltersValidation): IDefinitionMutations<T> {
92
+ return update.updated.reduce((accum, ruleEntity) => {
93
+ if (!filters || matchFilters(ruleEntity as IDefinition, filters)) {
94
+ accum.added.push(ruleEntity);
95
+
96
+ parseSegments(ruleEntity).forEach((segmentName: string) => {
97
+ segments.add(segmentName);
98
+ });
99
+ } else {
100
+ accum.removed.push(ruleEntity.name);
101
+ }
102
+ accum.names.push(ruleEntity.name);
103
+ return accum;
104
+ }, { added: [], removed: update.removed, names: update.removed.slice() } as IDefinitionMutations<T>);
105
+ }
106
+
107
+ function convertInstantUpdateToDefinitionChanges(instantUpdate: InstantUpdate) {
108
+ const { payload, changeNumber } = instantUpdate;
109
+ return payload.status === 'ARCHIVED' ?
110
+ { till: changeNumber, updated: [], removed: [payload.name] } :
111
+ { till: changeNumber, updated: [payload], removed: [] };
112
+ }
113
+
114
+ /**
115
+ * Factory of DefinitionChanges updater, a task that:
116
+ * - fetches definition changes using `definitionChangesFetcher`
117
+ * - updates definitions storage
118
+ * - uses `definitionsEventEmitter` to emit events related to definition data updates
119
+ *
120
+ * @param log - Logger instance
121
+ * @param definitionChangesFetcher - Fetcher of `/splitChanges` or `/configs`
122
+ * @param definitions - Definitions storage, with sync or async methods
123
+ * @param segments - Segments storage, with sync or async methods
124
+ * @param definitionsEventEmitter - Optional readiness manager. Not required for synchronizer or producer mode.
125
+ * @param requestTimeoutBeforeReady - How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
126
+ * @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` or `/configs` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
127
+ */
128
+ export function definitionChangesUpdaterFactory(
129
+ log: ILogger,
130
+ definitionChangesFetcher: IDefinitionChangesFetcher,
131
+ storage: Pick<IStorageBase, 'definitions' | 'rbSegments' | 'segments' | 'save'>,
132
+ splitFiltersValidation: ISplitFiltersValidation,
133
+ definitionsEventEmitter?: IDefinitionsEventEmitter,
134
+ requestTimeoutBeforeReady = 0,
135
+ retriesOnFailureBeforeReady = 0,
136
+ isClientSide?: boolean
137
+ ): DefinitionChangesUpdater {
138
+ const { definitions, rbSegments, segments } = storage;
139
+
140
+ let startingUp = true;
141
+
142
+ /** timeout decorator for `definitionChangesFetcher` promise */
143
+ function _promiseDecorator<T>(promise: Promise<T>) {
144
+ if (startingUp && requestTimeoutBeforeReady) promise = timeout(requestTimeoutBeforeReady, promise);
145
+ return promise;
146
+ }
147
+
148
+ /**
149
+ * DefinitionChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch definitions or synchronize them with the storage.
150
+ * Returned promise will not be rejected.
151
+ *
152
+ * @param noCache - true to revalidate data to fetch
153
+ * @param till - query param to bypass CDN requests
154
+ */
155
+ return function definitionChangesUpdater(noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) {
156
+
157
+ /**
158
+ * @param since - current changeNumber at definitionsCache
159
+ * @param retry - current number of retry attempts
160
+ */
161
+ function _definitionChangesUpdater(sinces: [number, number], retry = 0): Promise<boolean> {
162
+ const [since, rbSince] = sinces;
163
+ log.debug(SYNC_FETCH, [definitionChangesFetcher.type, since, rbSince]);
164
+
165
+ return Promise.resolve(
166
+ instantUpdate ?
167
+ instantUpdate.type === SPLIT_UPDATE ?
168
+ // IFFU edge case: a change to definition that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
169
+ Promise.resolve(rbSegments.contains(parseSegments(instantUpdate.payload, IN_RULE_BASED_SEGMENT))).then((contains) => {
170
+ return contains ?
171
+ { d: convertInstantUpdateToDefinitionChanges(instantUpdate) as IDefinitionChangesResponse['d'] } :
172
+ definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
173
+ }) :
174
+ { rbs: convertInstantUpdateToDefinitionChanges(instantUpdate) as IDefinitionChangesResponse['rbs'] } :
175
+ definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator)
176
+ )
177
+ .then((definitionChanges: IDefinitionChangesResponse) => {
178
+ const usedSegments = new Set<string>();
179
+
180
+ let updatedDefinitions: string[] = [];
181
+ let ffUpdate: MaybeThenable<boolean> = false;
182
+ if (definitionChanges.d) {
183
+ const { added, removed, names } = computeMutation(definitionChanges.d, usedSegments, splitFiltersValidation);
184
+ updatedDefinitions = names;
185
+ log.debug(SYNC_UPDATE, [definitionChangesFetcher.type, added.length, removed.length]);
186
+ ffUpdate = definitions.update(added, removed, definitionChanges.d.till);
187
+ }
188
+
189
+ let rbsUpdate: MaybeThenable<boolean> = false;
190
+ if (definitionChanges.rbs) {
191
+ const { added, removed } = computeMutation(definitionChanges.rbs, usedSegments);
192
+ log.debug(SYNC_UPDATE, ['rule-based segments', added.length, removed.length]);
193
+ rbsUpdate = rbSegments.update(added, removed, definitionChanges.rbs.till);
194
+ }
195
+
196
+ return Promise.all([ffUpdate, rbsUpdate,
197
+ // @TODO if at least 1 segment fetch fails due to 404 and other segments are updated in the storage, SDK_UPDATE is not emitted
198
+ segments.registerSegments(setToArray(usedSegments))
199
+ ]).then(([ffChanged, rbsChanged]) => {
200
+ if (storage.save) storage.save();
201
+
202
+ startingUp = false;
203
+
204
+ if (definitionsEventEmitter) {
205
+ // To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
206
+ return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
207
+ .catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
208
+ .then(emitSplitsArrivedEvent => {
209
+ // emit SDK events
210
+ if (emitSplitsArrivedEvent) {
211
+ const metadata: SdkUpdateMetadata = {
212
+ type: updatedDefinitions.length > 0 ? definitionChangesFetcher.type === 'configs' ? CONFIGS_UPDATE : FLAGS_UPDATE : SEGMENTS_UPDATE,
213
+ names: updatedDefinitions.length > 0 ? updatedDefinitions : []
214
+ };
215
+ definitionsEventEmitter.emit(SDK_DEFINITIONS_ARRIVED, metadata);
216
+ }
217
+ return true;
218
+ });
219
+ }
220
+ return true;
221
+ });
222
+ })
223
+ .catch(error => {
224
+ if (startingUp && retriesOnFailureBeforeReady > retry) {
225
+ retry += 1;
226
+ log.warn(SYNC_FETCH_RETRY, [definitionChangesFetcher.type, retry, error]);
227
+ return _definitionChangesUpdater(sinces, retry);
228
+ } else {
229
+ startingUp = false;
230
+ log.warn(SYNC_FETCH_FAILS, [definitionChangesFetcher.type, error]);
231
+ }
232
+ return false;
233
+ });
234
+ }
235
+
236
+ // `getChangeNumber` never rejects or throws error
237
+ return Promise.all([definitions.getChangeNumber(), rbSegments.getChangeNumber()]).then(_definitionChangesUpdater);
238
+ };
239
+ }
@@ -4,11 +4,11 @@ import { ISegmentsEventEmitter } from '../../../readiness/types';
4
4
  import { timeout } from '../../../utils/promise/timeout';
5
5
  import { SDK_SEGMENTS_ARRIVED, SEGMENTS_UPDATE } from '../../../readiness/constants';
6
6
  import { ILogger } from '../../../logger/types';
7
- import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants';
7
+ import { SYNC_FETCH_RETRY } from '../../../logger/constants';
8
8
  import { MySegmentsData } from '../types';
9
9
  import { IMembershipsResponse } from '../../../dtos/types';
10
10
  import { MEMBERSHIPS_LS_UPDATE } from '../../streaming/constants';
11
- import { usesSegmentsSync } from '../../../storages/AbstractSplitsCacheSync';
11
+ import { usesSegmentsSync } from '../../../storages/AbstractDefinitionsCacheSync';
12
12
 
13
13
  type IMySegmentsUpdater = (segmentsData?: MySegmentsData, noCache?: boolean, till?: number) => Promise<boolean>
14
14
 
@@ -76,7 +76,7 @@ export function mySegmentsUpdaterFactory(
76
76
  return updaterPromise.catch(error => {
77
77
  if (startingUp && retriesOnFailureBeforeReady > retry) {
78
78
  retry += 1;
79
- log.warn(SYNC_MYSEGMENTS_FETCH_RETRY, [retry, error]);
79
+ log.warn(SYNC_FETCH_RETRY, ['memberships', retry, error]);
80
80
  return _mySegmentsUpdater(retry); // no need to forward `segmentList` and `noCache` params
81
81
  } else {
82
82
  startingUp = false;