@splitsoftware/splitio-commons 1.8.0 → 1.8.2-rc.0

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 (28) hide show
  1. package/CHANGES.txt +6 -0
  2. package/cjs/sync/polling/updaters/splitChangesUpdater.js +12 -5
  3. package/esm/integrations/ga/GaToSplit.js +1 -1
  4. package/esm/sync/polling/updaters/splitChangesUpdater.js +12 -5
  5. package/package.json +2 -2
  6. package/src/integrations/ga/GaToSplit.ts +1 -1
  7. package/src/sync/polling/updaters/splitChangesUpdater.ts +12 -6
  8. package/src/sync/submitters/types.ts +1 -1
  9. package/types/sync/submitters/types.d.ts +1 -1
  10. package/types/sdkClient/types.d.ts +0 -18
  11. package/types/storages/inMemory/CountsCacheInMemory.d.ts +0 -20
  12. package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +0 -20
  13. package/types/storages/inRedis/CountsCacheInRedis.d.ts +0 -9
  14. package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +0 -9
  15. package/types/sync/offline/LocalhostFromFile.d.ts +0 -2
  16. package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +0 -2
  17. package/types/sync/submitters/eventsSyncTask.d.ts +0 -8
  18. package/types/sync/submitters/impressionCountsSubmitterInRedis.d.ts +0 -5
  19. package/types/sync/submitters/impressionCountsSyncTask.d.ts +0 -13
  20. package/types/sync/submitters/impressionsSyncTask.d.ts +0 -14
  21. package/types/sync/submitters/metricsSyncTask.d.ts +0 -12
  22. package/types/sync/submitters/submitterSyncTask.d.ts +0 -10
  23. package/types/sync/submitters/uniqueKeysSubmitterInRedis.d.ts +0 -5
  24. package/types/sync/syncTaskComposite.d.ts +0 -5
  25. package/types/trackers/filter/bloomFilter.d.ts +0 -10
  26. package/types/trackers/filter/dictionaryFilter.d.ts +0 -8
  27. package/types/trackers/filter/types.d.ts +0 -5
  28. package/types/utils/timeTracker/index.d.ts +0 -70
package/CHANGES.txt CHANGED
@@ -1,3 +1,9 @@
1
+ 1.8.2 (February 27, 2023)
2
+ - Updated internal splitChangesUpdater module to be resilient to duplicated split definitions when fetching split changes from Split backend.
3
+
4
+ 1.8.1 (February 7, 2023)
5
+ - Updated a module import to remove a trailing comma that can cause issues with some bundlers.
6
+
1
7
  1.8.0 (February 3, 2023)
2
8
  - Added flush data method to client
3
9
 
@@ -5,6 +5,7 @@ var sets_1 = require("../../../utils/lang/sets");
5
5
  var timeout_1 = require("../../../utils/promise/timeout");
6
6
  var constants_1 = require("../../../readiness/constants");
7
7
  var constants_2 = require("../../../logger/constants");
8
+ var maps_1 = require("../../../utils/lang/maps");
8
9
  // Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
9
10
  // Returns a promise that could be rejected.
10
11
  // @TODO review together with Segments and MySegments storage APIs
@@ -38,19 +39,25 @@ exports.parseSegments = parseSegments;
38
39
  * Exported for testing purposes.
39
40
  */
40
41
  function computeSplitsMutation(entries) {
42
+ var uniqueEntries = new maps_1._Map();
43
+ entries.forEach(function (split) {
44
+ var prevSplit = uniqueEntries.get(split.name);
45
+ if (!prevSplit || prevSplit.changeNumber < split.changeNumber)
46
+ uniqueEntries.set(split.name, split);
47
+ });
41
48
  var segments = new sets_1._Set();
42
- var computed = entries.reduce(function (accum, split) {
49
+ var computed = { added: [], removed: [], segments: [] };
50
+ uniqueEntries.forEach(function (split) {
43
51
  if (split.status === 'ACTIVE') {
44
- accum.added.push([split.name, split]);
52
+ computed.added.push([split.name, split]);
45
53
  parseSegments(split).forEach(function (segmentName) {
46
54
  segments.add(segmentName);
47
55
  });
48
56
  }
49
57
  else {
50
- accum.removed.push(split.name);
58
+ computed.removed.push(split.name);
51
59
  }
52
- return accum;
53
- }, { added: [], removed: [], segments: [] });
60
+ });
54
61
  computed.segments = (0, sets_1.setToArray)(segments);
55
62
  return computed;
56
63
  }
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable no-undef */
2
2
  import { objectAssign } from '../../utils/lang/objectAssign';
3
3
  import { isString, isFiniteNumber, uniqAsStrings } from '../../utils/lang';
4
- import { validateEvent, validateEventValue, validateEventProperties, validateKey, validateTrafficType, } from '../../utils/inputValidation';
4
+ import { validateEvent, validateEventValue, validateEventProperties, validateKey, validateTrafficType } from '../../utils/inputValidation';
5
5
  var logPrefix = 'ga-to-split: ';
6
6
  var logNameMapper = 'ga-to-split:mapper';
7
7
  /**
@@ -2,6 +2,7 @@ import { _Set, setToArray } from '../../../utils/lang/sets';
2
2
  import { timeout } from '../../../utils/promise/timeout';
3
3
  import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
4
4
  import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
5
+ import { _Map } from '../../../utils/lang/maps';
5
6
  // Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
6
7
  // Returns a promise that could be rejected.
7
8
  // @TODO review together with Segments and MySegments storage APIs
@@ -34,19 +35,25 @@ export function parseSegments(_a) {
34
35
  * Exported for testing purposes.
35
36
  */
36
37
  export function computeSplitsMutation(entries) {
38
+ var uniqueEntries = new _Map();
39
+ entries.forEach(function (split) {
40
+ var prevSplit = uniqueEntries.get(split.name);
41
+ if (!prevSplit || prevSplit.changeNumber < split.changeNumber)
42
+ uniqueEntries.set(split.name, split);
43
+ });
37
44
  var segments = new _Set();
38
- var computed = entries.reduce(function (accum, split) {
45
+ var computed = { added: [], removed: [], segments: [] };
46
+ uniqueEntries.forEach(function (split) {
39
47
  if (split.status === 'ACTIVE') {
40
- accum.added.push([split.name, split]);
48
+ computed.added.push([split.name, split]);
41
49
  parseSegments(split).forEach(function (segmentName) {
42
50
  segments.add(segmentName);
43
51
  });
44
52
  }
45
53
  else {
46
- accum.removed.push(split.name);
54
+ computed.removed.push(split.name);
47
55
  }
48
- return accum;
49
- }, { added: [], removed: [], segments: [] });
56
+ });
50
57
  computed.segments = setToArray(segments);
51
58
  return computed;
52
59
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "1.8.0",
3
+ "version": "1.8.2-rc.0",
4
4
  "description": "Split Javascript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -22,7 +22,7 @@
22
22
  "build": "npm run build:cjs && npm run build:esm",
23
23
  "build:esm": "rimraf esm && tsc -m es2015 --outDir esm -d true --declarationDir types",
24
24
  "build:cjs": "rimraf cjs && tsc -m CommonJS --outDir cjs",
25
- "test": "jest",
25
+ "test": "jest --runInBand",
26
26
  "test:coverage": "jest --coverage",
27
27
  "all": "npm run check && npm run build && npm run test",
28
28
  "publish:rc": "npm run check && npm run test && npm run build && npm publish --tag rc",
@@ -6,7 +6,7 @@ import {
6
6
  validateEventValue,
7
7
  validateEventProperties,
8
8
  validateKey,
9
- validateTrafficType,
9
+ validateTrafficType
10
10
  } from '../../utils/inputValidation';
11
11
  import { SplitIO } from '../../types';
12
12
  import { Identity, GoogleAnalyticsToSplitOptions } from './types';
@@ -7,6 +7,7 @@ import { timeout } from '../../../utils/promise/timeout';
7
7
  import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
8
8
  import { ILogger } from '../../../logger/types';
9
9
  import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
10
+ import { _Map } from '../../../utils/lang/maps';
10
11
 
11
12
  type ISplitChangesUpdater = (noCache?: boolean, till?: number) => Promise<boolean>
12
13
 
@@ -51,20 +52,25 @@ interface ISplitMutations {
51
52
  * Exported for testing purposes.
52
53
  */
53
54
  export function computeSplitsMutation(entries: ISplit[]): ISplitMutations {
55
+ const uniqueEntries = new _Map();
56
+ entries.forEach(split => {
57
+ const prevSplit = uniqueEntries.get(split.name);
58
+ if (!prevSplit || prevSplit.changeNumber < split.changeNumber) uniqueEntries.set(split.name, split);
59
+ });
60
+
54
61
  const segments = new _Set<string>();
55
- const computed = entries.reduce((accum, split) => {
62
+ const computed = { added: [], removed: [], segments: [] } as ISplitMutations;
63
+ uniqueEntries.forEach((split) => {
56
64
  if (split.status === 'ACTIVE') {
57
- accum.added.push([split.name, split]);
65
+ computed.added.push([split.name, split]);
58
66
 
59
67
  parseSegments(split).forEach((segmentName: string) => {
60
68
  segments.add(segmentName);
61
69
  });
62
70
  } else {
63
- accum.removed.push(split.name);
71
+ computed.removed.push(split.name);
64
72
  }
65
-
66
- return accum;
67
- }, { added: [], removed: [], segments: [] } as ISplitMutations);
73
+ });
68
74
 
69
75
  computed.segments = setToArray(segments);
70
76
 
@@ -9,7 +9,7 @@ export type ImpressionsPayload = {
9
9
  f: string,
10
10
  /** Key Impressions */
11
11
  i: {
12
- /** Key */
12
+ /** User Key */
13
13
  k: string;
14
14
  /** Treatment */
15
15
  t: string;
@@ -7,7 +7,7 @@ export declare type ImpressionsPayload = {
7
7
  f: string;
8
8
  /** Key Impressions */
9
9
  i: {
10
- /** Key */
10
+ /** User Key */
11
11
  k: string;
12
12
  /** Treatment */
13
13
  t: string;
@@ -1,18 +0,0 @@
1
- import { ISignalListener } from '../listeners/types';
2
- import { ISdkReadinessManager } from '../readiness/types';
3
- import { IStorageAsync, IStorageSync } from '../storages/types';
4
- import { ISyncManager } from '../sync/types';
5
- import { IEventTracker, IImpressionsTracker } from '../trackers/types';
6
- import { ISettings } from '../types';
7
- export interface IClientFactoryParams {
8
- storage: IStorageSync | IStorageAsync;
9
- sdkReadinessManager: ISdkReadinessManager;
10
- settings: ISettings;
11
- impressionsTracker: IImpressionsTracker;
12
- eventTracker: IEventTracker;
13
- }
14
- export interface ISdkClientFactoryParams extends IClientFactoryParams {
15
- signalListener?: ISignalListener;
16
- syncManager?: ISyncManager;
17
- sharedClient?: boolean;
18
- }
@@ -1,20 +0,0 @@
1
- import { ICountsCacheSync } from '../types';
2
- export declare class CountsCacheInMemory implements ICountsCacheSync {
3
- private counters;
4
- /**
5
- * Add counts.
6
- */
7
- track(metricName: string): boolean;
8
- /**
9
- * Clear the collector
10
- */
11
- clear(): void;
12
- /**
13
- * Get the collected data, used as payload for posting.
14
- */
15
- state(): Record<string, number>;
16
- /**
17
- * Check if the cache is empty.
18
- */
19
- isEmpty(): boolean;
20
- }
@@ -1,20 +0,0 @@
1
- import { ILatenciesCacheSync } from '../types';
2
- export declare class LatenciesCacheInMemory implements ILatenciesCacheSync {
3
- private counters;
4
- /**
5
- * Add latencies.
6
- */
7
- track(metricName: string, latency: number): boolean;
8
- /**
9
- * Clear the collector
10
- */
11
- clear(): void;
12
- /**
13
- * Get the collected data, used as payload for posting.
14
- */
15
- state(): Record<string, number[]>;
16
- /**
17
- * Check if the cache is empty.
18
- */
19
- isEmpty(): boolean;
20
- }
@@ -1,9 +0,0 @@
1
- import { ICountsCacheAsync } from '../types';
2
- import { KeyBuilderSS } from '../KeyBuilderSS';
3
- import { Redis } from 'ioredis';
4
- export declare class CountsCacheInRedis implements ICountsCacheAsync {
5
- private readonly redis;
6
- private readonly keys;
7
- constructor(keys: KeyBuilderSS, redis: Redis);
8
- track(metricName: string): Promise<boolean>;
9
- }
@@ -1,9 +0,0 @@
1
- import { ILatenciesCacheAsync } from '../types';
2
- import { KeyBuilderSS } from '../KeyBuilderSS';
3
- import { Redis } from 'ioredis';
4
- export declare class LatenciesCacheInRedis implements ILatenciesCacheAsync {
5
- private readonly redis;
6
- private readonly keys;
7
- constructor(keys: KeyBuilderSS, redis: Redis);
8
- track(metricName: string, latency: number): Promise<boolean>;
9
- }
@@ -1,2 +0,0 @@
1
- import { SplitIO } from '../../types';
2
- export declare function LocalhostFromFile(): SplitIO.LocalhostFactory;
@@ -1,2 +0,0 @@
1
- import { ISplitsParser } from './types';
2
- export declare function splitsParserFromFileFactory(): ISplitsParser;
@@ -1,8 +0,0 @@
1
- import { IEventsCacheSync } from '../../storages/types';
2
- import { IPostEventsBulk } from '../../services/types';
3
- import { ISyncTask, ITimeTracker } from '../types';
4
- import { ILogger } from '../../logger/types';
5
- /**
6
- * Sync task that periodically posts tracked events
7
- */
8
- export declare function eventsSyncTaskFactory(log: ILogger, postEventsBulk: IPostEventsBulk, eventsCache: IEventsCacheSync, eventsPushRate: number, eventsFirstPushWindow: number, latencyTracker?: ITimeTracker): ISyncTask;
@@ -1,5 +0,0 @@
1
- import { ISdkFactoryContextSync } from '../../sdkFactory/types';
2
- /**
3
- * Submitter that periodically posts impression counts
4
- */
5
- export declare function impressionCountsSubmitterInRedisFactory(params: ISdkFactoryContextSync): import("../types").ISyncTask<[], void>;
@@ -1,13 +0,0 @@
1
- import { ISyncTask, ITimeTracker } from '../types';
2
- import { IPostTestImpressionsCount } from '../../services/types';
3
- import { IImpressionCountsCacheSync } from '../../storages/types';
4
- import { ImpressionCountsPayload } from './types';
5
- import { ILogger } from '../../logger/types';
6
- /**
7
- * Converts `impressionCounts` data from cache into request payload.
8
- */
9
- export declare function fromImpressionCountsCollector(impressionsCount: Record<string, number>): ImpressionCountsPayload;
10
- /**
11
- * Sync task that periodically posts impression counts
12
- */
13
- export declare function impressionCountsSyncTaskFactory(log: ILogger, postTestImpressionsCount: IPostTestImpressionsCount, impressionCountsCache: IImpressionCountsCacheSync, latencyTracker?: ITimeTracker): ISyncTask;
@@ -1,14 +0,0 @@
1
- import { ISyncTask, ITimeTracker } from '../types';
2
- import { IPostTestImpressionsBulk } from '../../services/types';
3
- import { IImpressionsCacheSync } from '../../storages/types';
4
- import { ImpressionDTO } from '../../types';
5
- import { ImpressionsPayload } from './types';
6
- import { ILogger } from '../../logger/types';
7
- /**
8
- * Converts `impressions` data from cache into request payload.
9
- */
10
- export declare function fromImpressionsCollector(sendLabels: boolean, data: ImpressionDTO[]): ImpressionsPayload;
11
- /**
12
- * Sync task that periodically posts impressions data
13
- */
14
- export declare function impressionsSyncTaskFactory(log: ILogger, postTestImpressionsBulk: IPostTestImpressionsBulk, impressionsCache: IImpressionsCacheSync, impressionsRefreshRate: number, sendLabels?: boolean, latencyTracker?: ITimeTracker): ISyncTask;
@@ -1,12 +0,0 @@
1
- import { ICountsCacheSync, ILatenciesCacheSync } from '../../storages/types';
2
- import { IPostMetricsCounters, IPostMetricsTimes } from '../../services/types';
3
- import { ISyncTask, ITimeTracker } from '../types';
4
- import { ILogger } from '../../logger/types';
5
- /**
6
- * Sync task that periodically posts telemetry counts
7
- */
8
- export declare function countsSyncTaskFactory(log: ILogger, postMetricsCounters: IPostMetricsCounters, countsCache: ICountsCacheSync, metricsRefreshRate: number, latencyTracker?: ITimeTracker): ISyncTask;
9
- /**
10
- * Sync task that periodically posts telemetry latencies
11
- */
12
- export declare function latenciesSyncTaskFactory(log: ILogger, postMetricsLatencies: IPostMetricsTimes, latenciesCache: ILatenciesCacheSync, metricsRefreshRate: number, latencyTracker?: ITimeTracker): ISyncTask;
@@ -1,10 +0,0 @@
1
- import { ISyncTask, ITimeTracker } from '../types';
2
- import { IRecorderCacheProducerSync } from '../../storages/types';
3
- import { ILogger } from '../../logger/types';
4
- import { IResponse } from '../../services/types';
5
- /**
6
- * Base function to create submitter sync tasks, such as ImpressionsSyncTask and EventsSyncTask
7
- */
8
- export declare function submitterSyncTaskFactory<TState extends {
9
- length?: number;
10
- }>(log: ILogger, postClient: (body: string) => Promise<IResponse>, sourceCache: IRecorderCacheProducerSync<TState>, postRate: number, dataName: string, latencyTracker?: ITimeTracker, fromCacheToPayload?: (cacheData: TState) => any, maxRetries?: number, debugLogs?: boolean): ISyncTask<[], void>;
@@ -1,5 +0,0 @@
1
- import { ISdkFactoryContextSync } from '../../sdkFactory/types';
2
- /**
3
- * Submitter that periodically posts impression counts
4
- */
5
- export declare function uniqueKeysSubmitterInRedisFactory(params: ISdkFactoryContextSync): import("../types").ISyncTask<[], void>;
@@ -1,5 +0,0 @@
1
- import { ISyncTask } from './types';
2
- /**
3
- * Composite Sync Task: group of sync tasks that are treated as a single one.
4
- */
5
- export declare function syncTaskComposite(syncTasks: ISyncTask[]): ISyncTask;
@@ -1,10 +0,0 @@
1
- import { IFilter } from './types';
2
- export declare class BloomFilterImp implements IFilter {
3
- private spectedInsertions;
4
- private errorRate;
5
- private filter;
6
- constructor(spectedInsertions: number, errorRate: number);
7
- add(data: string): boolean;
8
- contains(data: string): boolean;
9
- clear(): void;
10
- }
@@ -1,8 +0,0 @@
1
- import { IFilter } from './types';
2
- export declare class DictionaryFilter implements IFilter {
3
- private filter;
4
- constructor();
5
- add(data: string): boolean;
6
- contains(data: string): boolean;
7
- clear(): void;
8
- }
@@ -1,5 +0,0 @@
1
- export interface IFilter {
2
- add(data: string): boolean;
3
- contains(data: string): boolean;
4
- clear(): void;
5
- }
@@ -1,70 +0,0 @@
1
- import { ILogger } from '../../logger/types';
2
- import { IResponse } from '../../services/types';
3
- interface MetricsCollector {
4
- countException(): void;
5
- count(status: number): void;
6
- latency(ms: number): void;
7
- ready(ms: number): void;
8
- getTreatment(ms: number): void;
9
- getTreatments(ms: number): void;
10
- getTreatmentWithConfig(ms: number): void;
11
- getTreatmentsWithConfig(ms: number): void;
12
- [method: string]: (ms: number) => void;
13
- }
14
- export declare const TrackerAPI: {
15
- /**
16
- * "Private" method, used to attach count/countException and stop callbacks to a promise.
17
- *
18
- * @param {ILogger} log - Logger.
19
- * @param {Promise} promise - The promise we want to attach the callbacks.
20
- * @param {string} task - The name of the task.
21
- * @param {number | string} modifier - (optional) The modifier for the task, if any.
22
- */
23
- __attachToPromise(log: ILogger, promise: Promise<IResponse>, task: string, collector: false | MetricsCollector, modifier?: string | number | undefined): Promise<IResponse>;
24
- /**
25
- * Starts tracking the time for a given task. All tasks tracked are considered "unique" because
26
- * there may be multiple SDK instances tracking a "generic" task, making any task non-generic.
27
- *
28
- * @param {ILogger} log - Logger.
29
- * @param {string} task - The task we are starting.
30
- * @param {Object} collectors - The collectors map.
31
- * @param {Promise} promise - (optional) The promise we are tracking.
32
- * @return {Function | Promise} The stop function for this specific task or the promise received with the callbacks registered.
33
- */
34
- start(log: ILogger, task: string, collectors?: Record<string, MetricsCollector> | undefined, promise?: Promise<IResponse> | undefined, now?: (() => number) | undefined): Promise<IResponse> | (() => number);
35
- /**
36
- * Setup the collector for a task that reports metrics.
37
- *
38
- * @param {string} task - The task name
39
- * @param {number | string} taskUniqueId - The unique identifier for this task
40
- * @param {Object} collectors - The collectors map.
41
- */
42
- setCollectorForTask(task: string, taskUniqueId: number | string, collectors: Record<string, MetricsCollector>): void;
43
- /**
44
- * Stops the tracking of a given task.
45
- *
46
- * @param {ILogger} log - Logger.
47
- * @param {string} task - The task we are starting.
48
- * @param {number | string} modifier - (optional) The modifier for that specific task.
49
- */
50
- stop(log: ILogger, task: string, modifier?: string | number | undefined): number | undefined;
51
- /**
52
- * The constants shortcut for the task names.
53
- */
54
- TaskNames: {
55
- SDK_READY: string;
56
- SDK_GET_TREATMENT: string;
57
- SDK_GET_TREATMENTS: string;
58
- SDK_GET_TREATMENT_WITH_CONFIG: string;
59
- SDK_GET_TREATMENTS_WITH_CONFIG: string;
60
- SPLITS_READY: string;
61
- SEGMENTS_READY: string;
62
- METRICS_PUSH: string;
63
- IMPRESSIONS_PUSH: string;
64
- EVENTS_PUSH: string;
65
- MY_SEGMENTS_FETCH: string;
66
- SEGMENTS_FETCH: string;
67
- SPLITS_FETCH: string;
68
- };
69
- };
70
- export {};