@splitsoftware/splitio-commons 3.1.1-rc.11 → 3.1.1-rc.12
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.
- package/CHANGES.txt +1 -0
- package/cjs/services/authProvider.js +2 -2
- package/cjs/{sync/streaming/AuthClient/index.js → services/fetchAuth.js} +2 -2
- package/cjs/services/splitApi.js +2 -2
- package/cjs/storages/inLocalStorage/DefinitionsCacheInLocal.js +2 -1
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +2 -1
- package/cjs/storages/inMemory/DefinitionsCacheInMemory.js +2 -1
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +2 -1
- package/cjs/storages/inRedis/DefinitionsCacheInRedis.js +3 -1
- package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +3 -1
- package/cjs/storages/pluggable/DefinitionsCachePluggable.js +3 -1
- package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +3 -1
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +1 -1
- package/cjs/sync/polling/updaters/definitionChangesUpdater.js +14 -4
- package/cjs/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.js +5 -3
- package/cjs/sync/streaming/parseUtils.js +4 -4
- package/cjs/sync/streaming/pushManager.js +4 -3
- package/esm/services/authProvider.js +1 -1
- package/esm/{sync/streaming/AuthClient/index.js → services/fetchAuth.js} +2 -2
- package/esm/services/splitApi.js +1 -1
- package/esm/storages/inLocalStorage/DefinitionsCacheInLocal.js +2 -1
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +2 -1
- package/esm/storages/inMemory/DefinitionsCacheInMemory.js +2 -1
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +2 -1
- package/esm/storages/inRedis/DefinitionsCacheInRedis.js +3 -1
- package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +3 -1
- package/esm/storages/pluggable/DefinitionsCachePluggable.js +3 -1
- package/esm/storages/pluggable/RBSegmentsCachePluggable.js +3 -1
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +1 -1
- package/esm/sync/polling/updaters/definitionChangesUpdater.js +14 -4
- package/esm/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.js +6 -4
- package/esm/sync/streaming/parseUtils.js +2 -2
- package/esm/sync/streaming/pushManager.js +4 -3
- package/package.json +1 -1
- package/src/dtos/types.ts +4 -4
- package/src/services/authProvider.ts +2 -2
- package/src/{sync/streaming/AuthClient/index.ts → services/fetchAuth.ts} +3 -4
- package/src/services/splitApi.ts +1 -1
- package/src/services/types.ts +21 -4
- package/src/storages/AbstractDefinitionsCacheAsync.ts +3 -3
- package/src/storages/AbstractDefinitionsCacheSync.ts +2 -2
- package/src/storages/inLocalStorage/DefinitionsCacheInLocal.ts +2 -2
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +3 -3
- package/src/storages/inMemory/DefinitionsCacheInMemory.ts +2 -2
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +2 -2
- package/src/storages/inRedis/DefinitionsCacheInRedis.ts +6 -4
- package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +7 -5
- package/src/storages/pluggable/DefinitionsCachePluggable.ts +4 -2
- package/src/storages/pluggable/RBSegmentsCachePluggable.ts +5 -3
- package/src/storages/types.ts +6 -6
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +5 -5
- package/src/sync/polling/types.ts +22 -1
- package/src/sync/polling/updaters/definitionChangesUpdater.ts +26 -20
- package/src/sync/streaming/SSEClient/index.ts +1 -1
- package/src/sync/streaming/SSEClient/types.ts +1 -1
- package/src/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.ts +15 -11
- package/src/sync/streaming/UpdateWorkers/types.ts +6 -0
- package/src/sync/streaming/parseUtils.ts +3 -4
- package/src/sync/streaming/pushManager.ts +4 -3
- package/cjs/sync/streaming/AuthClient/types.js +0 -2
- package/esm/sync/streaming/AuthClient/types.js +0 -1
- package/src/sync/streaming/AuthClient/types.ts +0 -19
package/CHANGES.txt
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
3.2.0 (XXX XX, 2026)
|
|
2
|
+
- Added support for streaming in the Configs SDK, handling CONFIG_UPDATE notifications. Unlike feature flag notifications, the previous change number of CONFIG_UPDATE and RB_SEGMENT_UPDATE notifications are scoped to the referenced entity rather than to the environment, and so instant updates are applied without updating the storage change number.
|
|
2
3
|
- Added support for AI configs.
|
|
3
4
|
- Added support for ioredis v6 (Related to issue https://github.com/splitio/javascript-client/issues/951). Note that ioredis v6 requires Node.js 20 or above; stay on ioredis v4 or v5 for older Node.js versions.
|
|
4
5
|
- Removed the `@types/ioredis` dependency, which is no longer required since the public type definitions don't depend on ioredis types. The `@types/node` dependency, previously installed transitively by `@types/ioredis`, is now declared explicitly, since the public type definitions use Node.js types for the `agent` and `tls` options.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.authProviderFactory = void 0;
|
|
4
|
-
var
|
|
4
|
+
var fetchAuth_1 = require("./fetchAuth");
|
|
5
5
|
var Backoff_1 = require("../utils/Backoff");
|
|
6
6
|
var constants_1 = require("../logger/constants");
|
|
7
7
|
var constants_2 = require("../utils/constants");
|
|
@@ -18,7 +18,7 @@ function noCachedCredentialError() {
|
|
|
18
18
|
*/
|
|
19
19
|
function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
|
|
20
20
|
var urls = settings.urls, log = settings.log;
|
|
21
|
-
var fetchAuth = (0,
|
|
21
|
+
var fetchAuth = (0, fetchAuth_1.fetchAuthFactory)(function () {
|
|
22
22
|
var url = "".concat(urls.auth, "/api/v3/auth?capabilities=config,aiconfig");
|
|
23
23
|
return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_2.TOKEN), false, true);
|
|
24
24
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.fetchAuthFactory = void 0;
|
|
4
|
-
var objectAssign_1 = require("
|
|
5
|
-
var jwt_1 = require("
|
|
4
|
+
var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
5
|
+
var jwt_1 = require("../utils/jwt");
|
|
6
6
|
/**
|
|
7
7
|
* Factory of authentication function.
|
|
8
8
|
*
|
package/cjs/services/splitApi.js
CHANGED
|
@@ -5,7 +5,7 @@ var splitHttpClient_1 = require("./splitHttpClient");
|
|
|
5
5
|
var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
6
6
|
var constants_1 = require("../utils/constants");
|
|
7
7
|
var constants_2 = require("../logger/constants");
|
|
8
|
-
var
|
|
8
|
+
var fetchAuth_1 = require("./fetchAuth");
|
|
9
9
|
var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
|
|
10
10
|
function userKeyToQueryParam(userKey) {
|
|
11
11
|
return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
|
|
@@ -24,7 +24,7 @@ function splitApiFactory(settings, platform, telemetryTracker) {
|
|
|
24
24
|
var SplitSDKImpressionsMode = settings.sync.impressionsMode;
|
|
25
25
|
var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
|
|
26
26
|
return {
|
|
27
|
-
fetchAuth: (0,
|
|
27
|
+
fetchAuth: (0, fetchAuth_1.fetchAuthFactory)(function (userMatchingKeys) {
|
|
28
28
|
var url = "".concat(urls.auth, "/v2/auth?s=").concat(settings.sync.flagSpecVersion);
|
|
29
29
|
if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
|
|
30
30
|
var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
|
|
@@ -98,7 +98,8 @@ var DefinitionsCacheInLocal = /** @class */ (function (_super) {
|
|
|
98
98
|
};
|
|
99
99
|
DefinitionsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
100
100
|
try {
|
|
101
|
-
|
|
101
|
+
if (changeNumber !== undefined)
|
|
102
|
+
this.storage.setItem(this.keys.buildDefinitionsTillKey(), changeNumber + '');
|
|
102
103
|
// update "last updated" timestamp with current time
|
|
103
104
|
this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
|
|
104
105
|
this.hasSync = true;
|
|
@@ -25,7 +25,8 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
25
25
|
};
|
|
26
26
|
RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
27
27
|
try {
|
|
28
|
-
|
|
28
|
+
if (changeNumber !== undefined)
|
|
29
|
+
this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
|
|
29
30
|
this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
|
|
30
31
|
}
|
|
31
32
|
catch (e) {
|
|
@@ -70,7 +70,8 @@ var DefinitionsCacheInMemory = /** @class */ (function (_super) {
|
|
|
70
70
|
return this.definitionsCache[name] || null;
|
|
71
71
|
};
|
|
72
72
|
DefinitionsCacheInMemory.prototype.setChangeNumber = function (changeNumber) {
|
|
73
|
-
|
|
73
|
+
if (changeNumber !== undefined)
|
|
74
|
+
this.changeNumber = changeNumber;
|
|
74
75
|
return true;
|
|
75
76
|
};
|
|
76
77
|
DefinitionsCacheInMemory.prototype.getChangeNumber = function () {
|
|
@@ -18,7 +18,8 @@ var RBSegmentsCacheInMemory = /** @class */ (function () {
|
|
|
18
18
|
var _this = this;
|
|
19
19
|
var updated = toAdd.map(function (toAdd) { return _this.add(toAdd); }).some(function (result) { return result; });
|
|
20
20
|
updated = toRemove.map(function (toRemove) { return _this.remove(toRemove); }).some(function (result) { return result; }) || updated;
|
|
21
|
-
|
|
21
|
+
if (changeNumber !== undefined)
|
|
22
|
+
this.changeNumber = changeNumber;
|
|
22
23
|
return updated;
|
|
23
24
|
};
|
|
24
25
|
RBSegmentsCacheInMemory.prototype.add = function (rbSegment) {
|
|
@@ -126,7 +126,9 @@ var DefinitionsCacheInRedis = /** @class */ (function (_super) {
|
|
|
126
126
|
* or rejected if it fails.
|
|
127
127
|
*/
|
|
128
128
|
DefinitionsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
|
|
129
|
-
|
|
129
|
+
if (changeNumber !== undefined) {
|
|
130
|
+
return this.redis.set(this.keys.buildDefinitionsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
|
|
131
|
+
}
|
|
130
132
|
};
|
|
131
133
|
/**
|
|
132
134
|
* Get till number or -1 if it's not defined.
|
|
@@ -43,7 +43,9 @@ var RBSegmentsCacheInRedis = /** @class */ (function () {
|
|
|
43
43
|
});
|
|
44
44
|
};
|
|
45
45
|
RBSegmentsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
|
|
46
|
-
|
|
46
|
+
if (changeNumber !== undefined) {
|
|
47
|
+
return this.redis.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
|
|
48
|
+
}
|
|
47
49
|
};
|
|
48
50
|
RBSegmentsCacheInRedis.prototype.getChangeNumber = function () {
|
|
49
51
|
var _this = this;
|
|
@@ -186,7 +186,9 @@ var DefinitionsCachePluggable = /** @class */ (function (_super) {
|
|
|
186
186
|
* or rejected if it fails (e.g., wrapper operation fails).
|
|
187
187
|
*/
|
|
188
188
|
DefinitionsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
|
|
189
|
-
|
|
189
|
+
if (changeNumber !== undefined) {
|
|
190
|
+
return this.wrapper.set(this.keys.buildDefinitionsTillKey(), changeNumber + '');
|
|
191
|
+
}
|
|
190
192
|
};
|
|
191
193
|
/**
|
|
192
194
|
* Get till number or -1 if it's not defined.
|
|
@@ -43,7 +43,9 @@ var RBSegmentsCachePluggable = /** @class */ (function () {
|
|
|
43
43
|
});
|
|
44
44
|
};
|
|
45
45
|
RBSegmentsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
|
|
46
|
-
|
|
46
|
+
if (changeNumber !== undefined) {
|
|
47
|
+
return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
|
|
48
|
+
}
|
|
47
49
|
};
|
|
48
50
|
RBSegmentsCachePluggable.prototype.getChangeNumber = function () {
|
|
49
51
|
var _this = this;
|
|
@@ -16,7 +16,7 @@ function isSplitChangesLegacyResponse(data) {
|
|
|
16
16
|
function partitionByStatus(items, till, since) {
|
|
17
17
|
var updated = [], removed = [];
|
|
18
18
|
items.forEach(function (item) { return item.status === 'ARCHIVED' ? removed.push(item.name) : updated.push(item); });
|
|
19
|
-
return { updated: updated, removed: removed, till: till, since: since };
|
|
19
|
+
return { updated: updated, removed: removed, till: till, since: since !== null && since !== void 0 ? since : undefined };
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* Factory of SplitChanges fetcher.
|
|
@@ -8,6 +8,7 @@ var lang_1 = require("../../../utils/lang");
|
|
|
8
8
|
var constants_3 = require("../../../utils/constants");
|
|
9
9
|
var sets_1 = require("../../../utils/lang/sets");
|
|
10
10
|
var constants_4 = require("../../streaming/constants");
|
|
11
|
+
var thenable_1 = require("../../../utils/promise/thenable");
|
|
11
12
|
/**
|
|
12
13
|
* Collect segments from a raw FF or RBS definition.
|
|
13
14
|
* Exported for testing purposes.
|
|
@@ -115,7 +116,7 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
|
|
|
115
116
|
* @param noCache - true to revalidate data to fetch
|
|
116
117
|
* @param till - query param to bypass CDN requests
|
|
117
118
|
*/
|
|
118
|
-
return function definitionChangesUpdater(noCache, till, instantUpdate) {
|
|
119
|
+
return function definitionChangesUpdater(noCache, till, instantUpdate, pcns) {
|
|
119
120
|
/**
|
|
120
121
|
* @param since - current changeNumber at definitionsCache
|
|
121
122
|
* @param retry - current number of retry attempts
|
|
@@ -123,8 +124,14 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
|
|
|
123
124
|
function _definitionChangesUpdater(sinces, retry) {
|
|
124
125
|
if (retry === void 0) { retry = 0; }
|
|
125
126
|
var since = sinces[0], rbSince = sinces[1];
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
// If provided, `since` and `rbSince` must not be higher than it, to avoid missing an update that the scoped `pcn` indicates hasn't been fetched yet.
|
|
128
|
+
if (pcns) {
|
|
129
|
+
if (pcns.since !== undefined && pcns.since < since)
|
|
130
|
+
since = pcns.since;
|
|
131
|
+
if (pcns.rbSince !== undefined && pcns.rbSince < rbSince)
|
|
132
|
+
rbSince = pcns.rbSince;
|
|
133
|
+
}
|
|
134
|
+
var definitionChangesRequest = instantUpdate ?
|
|
128
135
|
instantUpdate.type === constants_4.RB_SEGMENT_UPDATE ?
|
|
129
136
|
{ rbs: convertInstantUpdateToDefinitionChanges(instantUpdate) } :
|
|
130
137
|
// IFFU edge case: a change to definition that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
|
|
@@ -133,7 +140,10 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
|
|
|
133
140
|
{ d: convertInstantUpdateToDefinitionChanges(instantUpdate) } :
|
|
134
141
|
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
|
|
135
142
|
}) :
|
|
136
|
-
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator)
|
|
143
|
+
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
|
|
144
|
+
if ((0, thenable_1.thenable)(definitionChangesRequest))
|
|
145
|
+
log.debug(constants_2.SYNC_FETCH, [definitionChangesFetcher.type, since, rbSince]);
|
|
146
|
+
return Promise.resolve(definitionChangesRequest)
|
|
137
147
|
.then(function (definitionChanges) {
|
|
138
148
|
var usedSegments = new Set();
|
|
139
149
|
var updatedDefinitions = [];
|
|
@@ -9,9 +9,11 @@ var constants_4 = require("../constants");
|
|
|
9
9
|
var parseUtils_1 = require("../parseUtils");
|
|
10
10
|
var constants_5 = require("./constants");
|
|
11
11
|
/**
|
|
12
|
-
* DefinitionsUpdateWorker factory
|
|
12
|
+
* DefinitionsUpdateWorker factory for Flags SDKs, where notifications pcn and changeNumber are environment-scoped
|
|
13
13
|
*/
|
|
14
|
-
function DefinitionsUpdateWorker(
|
|
14
|
+
function DefinitionsUpdateWorker(params, pollingManager) {
|
|
15
|
+
var log = params.settings.log, storage = params.storage, telemetryTracker = params.telemetryTracker, definitionsEventEmitter = params.readiness.definitions;
|
|
16
|
+
var definitionsSyncTask = pollingManager.definitionsSyncTask;
|
|
15
17
|
var ff = DefinitionsUpdateWorker(storage.definitions);
|
|
16
18
|
var rbs = DefinitionsUpdateWorker(storage.rbSegments);
|
|
17
19
|
function DefinitionsUpdateWorker(cache) {
|
|
@@ -96,7 +98,7 @@ function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsE
|
|
|
96
98
|
put: function (parsedData) {
|
|
97
99
|
if (parsedData.d && parsedData.c !== undefined) {
|
|
98
100
|
try {
|
|
99
|
-
var payload = (0, parseUtils_1.
|
|
101
|
+
var payload = (0, parseUtils_1.parseUpdatePayload)(parsedData.c, parsedData.d);
|
|
100
102
|
if (payload) {
|
|
101
103
|
(parsedData.type === constants_4.RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData, payload);
|
|
102
104
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDelay = exports.
|
|
3
|
+
exports.getDelay = exports.parseUpdatePayload = exports.isInBitmap = exports.parseBitmap = exports.parseCompressedData = void 0;
|
|
4
4
|
var decompress_1 = require("../../utils/decompress");
|
|
5
5
|
var base64_1 = require("../../utils/base64");
|
|
6
6
|
var murmur3_1 = require("../../utils/murmur3/murmur3");
|
|
@@ -79,14 +79,14 @@ function isInBitmap(bitmap, hash64hex) {
|
|
|
79
79
|
}
|
|
80
80
|
exports.isInBitmap = isInBitmap;
|
|
81
81
|
/**
|
|
82
|
-
* Parse
|
|
82
|
+
* Parse notifications for instant updates
|
|
83
83
|
*/
|
|
84
|
-
function
|
|
84
|
+
function parseUpdatePayload(compression, data) {
|
|
85
85
|
return compression > 0 ?
|
|
86
86
|
parseCompressedData(data, compression, false) :
|
|
87
87
|
JSON.parse((0, base64_1.decodeFromBase64)(data));
|
|
88
88
|
}
|
|
89
|
-
exports.
|
|
89
|
+
exports.parseUpdatePayload = parseUpdatePayload;
|
|
90
90
|
var DEFAULT_MAX_INTERVAL = 60000;
|
|
91
91
|
function getDelay(parsedData, matchingKey) {
|
|
92
92
|
if (parsedData.h === 0)
|
|
@@ -21,8 +21,9 @@ var constants_3 = require("../../utils/constants");
|
|
|
21
21
|
* - for server-side if key is not provided in settings.
|
|
22
22
|
* - for client-side, with support for multiple clients, if key is provided in settings
|
|
23
23
|
*/
|
|
24
|
-
function pushManagerFactory(params, pollingManager) {
|
|
25
|
-
|
|
24
|
+
function pushManagerFactory(params, pollingManager, definitionsUpdateWorkerFactory) {
|
|
25
|
+
if (definitionsUpdateWorkerFactory === void 0) { definitionsUpdateWorkerFactory = DefinitionsUpdateWorker_1.DefinitionsUpdateWorker; }
|
|
26
|
+
var settings = params.settings, storage = params.storage, serviceApi = params.serviceApi, platform = params.platform, telemetryTracker = params.telemetryTracker;
|
|
26
27
|
// `userKey` is the matching key of main client in client-side SDK.
|
|
27
28
|
// It can be used to check if running on client-side or server-side SDK.
|
|
28
29
|
var userKey = (0, key_1.checkIfServerSide)(settings) ? undefined : (0, key_1.getMatching)(settings.core.key);
|
|
@@ -44,7 +45,7 @@ function pushManagerFactory(params, pollingManager) {
|
|
|
44
45
|
// MySegmentsUpdateWorker (client-side) are initiated in `add` method
|
|
45
46
|
var segmentsUpdateWorker = userKey ? undefined : (0, SegmentsUpdateWorker_1.SegmentsUpdateWorker)(log, pollingManager.segmentsSyncTask, storage.segments);
|
|
46
47
|
// For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
|
|
47
|
-
var definitionsUpdateWorker = (
|
|
48
|
+
var definitionsUpdateWorker = definitionsUpdateWorkerFactory(params, pollingManager);
|
|
48
49
|
// [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
|
|
49
50
|
// Hash64 is used to process membership update events and dispatch actions to the corresponding MySegmentsUpdateWorker.
|
|
50
51
|
var clients = {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { objectAssign } from '
|
|
2
|
-
import { decodeJWTtoken } from '
|
|
1
|
+
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
|
+
import { decodeJWTtoken } from '../utils/jwt';
|
|
3
3
|
/**
|
|
4
4
|
* Factory of authentication function.
|
|
5
5
|
*
|
package/esm/services/splitApi.js
CHANGED
|
@@ -2,7 +2,7 @@ import { splitHttpClientFactory } from './splitHttpClient';
|
|
|
2
2
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
3
3
|
import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MEMBERSHIPS } from '../utils/constants';
|
|
4
4
|
import { ERROR_TOO_MANY_SETS } from '../logger/constants';
|
|
5
|
-
import { fetchAuthFactory } from '
|
|
5
|
+
import { fetchAuthFactory } from './fetchAuth';
|
|
6
6
|
var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
|
|
7
7
|
function userKeyToQueryParam(userKey) {
|
|
8
8
|
return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
|
|
@@ -95,7 +95,8 @@ var DefinitionsCacheInLocal = /** @class */ (function (_super) {
|
|
|
95
95
|
};
|
|
96
96
|
DefinitionsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
97
97
|
try {
|
|
98
|
-
|
|
98
|
+
if (changeNumber !== undefined)
|
|
99
|
+
this.storage.setItem(this.keys.buildDefinitionsTillKey(), changeNumber + '');
|
|
99
100
|
// update "last updated" timestamp with current time
|
|
100
101
|
this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
|
|
101
102
|
this.hasSync = true;
|
|
@@ -22,7 +22,8 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
22
22
|
};
|
|
23
23
|
RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
24
24
|
try {
|
|
25
|
-
|
|
25
|
+
if (changeNumber !== undefined)
|
|
26
|
+
this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
|
|
26
27
|
this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
|
|
27
28
|
}
|
|
28
29
|
catch (e) {
|
|
@@ -67,7 +67,8 @@ var DefinitionsCacheInMemory = /** @class */ (function (_super) {
|
|
|
67
67
|
return this.definitionsCache[name] || null;
|
|
68
68
|
};
|
|
69
69
|
DefinitionsCacheInMemory.prototype.setChangeNumber = function (changeNumber) {
|
|
70
|
-
|
|
70
|
+
if (changeNumber !== undefined)
|
|
71
|
+
this.changeNumber = changeNumber;
|
|
71
72
|
return true;
|
|
72
73
|
};
|
|
73
74
|
DefinitionsCacheInMemory.prototype.getChangeNumber = function () {
|
|
@@ -15,7 +15,8 @@ var RBSegmentsCacheInMemory = /** @class */ (function () {
|
|
|
15
15
|
var _this = this;
|
|
16
16
|
var updated = toAdd.map(function (toAdd) { return _this.add(toAdd); }).some(function (result) { return result; });
|
|
17
17
|
updated = toRemove.map(function (toRemove) { return _this.remove(toRemove); }).some(function (result) { return result; }) || updated;
|
|
18
|
-
|
|
18
|
+
if (changeNumber !== undefined)
|
|
19
|
+
this.changeNumber = changeNumber;
|
|
19
20
|
return updated;
|
|
20
21
|
};
|
|
21
22
|
RBSegmentsCacheInMemory.prototype.add = function (rbSegment) {
|
|
@@ -123,7 +123,9 @@ var DefinitionsCacheInRedis = /** @class */ (function (_super) {
|
|
|
123
123
|
* or rejected if it fails.
|
|
124
124
|
*/
|
|
125
125
|
DefinitionsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
|
|
126
|
-
|
|
126
|
+
if (changeNumber !== undefined) {
|
|
127
|
+
return this.redis.set(this.keys.buildDefinitionsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
|
|
128
|
+
}
|
|
127
129
|
};
|
|
128
130
|
/**
|
|
129
131
|
* Get till number or -1 if it's not defined.
|
|
@@ -40,7 +40,9 @@ var RBSegmentsCacheInRedis = /** @class */ (function () {
|
|
|
40
40
|
});
|
|
41
41
|
};
|
|
42
42
|
RBSegmentsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
|
|
43
|
-
|
|
43
|
+
if (changeNumber !== undefined) {
|
|
44
|
+
return this.redis.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
|
|
45
|
+
}
|
|
44
46
|
};
|
|
45
47
|
RBSegmentsCacheInRedis.prototype.getChangeNumber = function () {
|
|
46
48
|
var _this = this;
|
|
@@ -183,7 +183,9 @@ var DefinitionsCachePluggable = /** @class */ (function (_super) {
|
|
|
183
183
|
* or rejected if it fails (e.g., wrapper operation fails).
|
|
184
184
|
*/
|
|
185
185
|
DefinitionsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
|
|
186
|
-
|
|
186
|
+
if (changeNumber !== undefined) {
|
|
187
|
+
return this.wrapper.set(this.keys.buildDefinitionsTillKey(), changeNumber + '');
|
|
188
|
+
}
|
|
187
189
|
};
|
|
188
190
|
/**
|
|
189
191
|
* Get till number or -1 if it's not defined.
|
|
@@ -40,7 +40,9 @@ var RBSegmentsCachePluggable = /** @class */ (function () {
|
|
|
40
40
|
});
|
|
41
41
|
};
|
|
42
42
|
RBSegmentsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
|
|
43
|
-
|
|
43
|
+
if (changeNumber !== undefined) {
|
|
44
|
+
return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
|
|
45
|
+
}
|
|
44
46
|
};
|
|
45
47
|
RBSegmentsCachePluggable.prototype.getChangeNumber = function () {
|
|
46
48
|
var _this = this;
|
|
@@ -13,7 +13,7 @@ function isSplitChangesLegacyResponse(data) {
|
|
|
13
13
|
function partitionByStatus(items, till, since) {
|
|
14
14
|
var updated = [], removed = [];
|
|
15
15
|
items.forEach(function (item) { return item.status === 'ARCHIVED' ? removed.push(item.name) : updated.push(item); });
|
|
16
|
-
return { updated: updated, removed: removed, till: till, since: since };
|
|
16
|
+
return { updated: updated, removed: removed, till: till, since: since !== null && since !== void 0 ? since : undefined };
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Factory of SplitChanges fetcher.
|
|
@@ -5,6 +5,7 @@ import { startsWith } from '../../../utils/lang';
|
|
|
5
5
|
import { IN_RULE_BASED_SEGMENT, IN_SEGMENT, RULE_BASED_SEGMENT, STANDARD_SEGMENT } from '../../../utils/constants';
|
|
6
6
|
import { setToArray } from '../../../utils/lang/sets';
|
|
7
7
|
import { RB_SEGMENT_UPDATE } from '../../streaming/constants';
|
|
8
|
+
import { thenable } from '../../../utils/promise/thenable';
|
|
8
9
|
/**
|
|
9
10
|
* Collect segments from a raw FF or RBS definition.
|
|
10
11
|
* Exported for testing purposes.
|
|
@@ -110,7 +111,7 @@ export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, s
|
|
|
110
111
|
* @param noCache - true to revalidate data to fetch
|
|
111
112
|
* @param till - query param to bypass CDN requests
|
|
112
113
|
*/
|
|
113
|
-
return function definitionChangesUpdater(noCache, till, instantUpdate) {
|
|
114
|
+
return function definitionChangesUpdater(noCache, till, instantUpdate, pcns) {
|
|
114
115
|
/**
|
|
115
116
|
* @param since - current changeNumber at definitionsCache
|
|
116
117
|
* @param retry - current number of retry attempts
|
|
@@ -118,8 +119,14 @@ export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, s
|
|
|
118
119
|
function _definitionChangesUpdater(sinces, retry) {
|
|
119
120
|
if (retry === void 0) { retry = 0; }
|
|
120
121
|
var since = sinces[0], rbSince = sinces[1];
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
// If provided, `since` and `rbSince` must not be higher than it, to avoid missing an update that the scoped `pcn` indicates hasn't been fetched yet.
|
|
123
|
+
if (pcns) {
|
|
124
|
+
if (pcns.since !== undefined && pcns.since < since)
|
|
125
|
+
since = pcns.since;
|
|
126
|
+
if (pcns.rbSince !== undefined && pcns.rbSince < rbSince)
|
|
127
|
+
rbSince = pcns.rbSince;
|
|
128
|
+
}
|
|
129
|
+
var definitionChangesRequest = instantUpdate ?
|
|
123
130
|
instantUpdate.type === RB_SEGMENT_UPDATE ?
|
|
124
131
|
{ rbs: convertInstantUpdateToDefinitionChanges(instantUpdate) } :
|
|
125
132
|
// IFFU edge case: a change to definition that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
|
|
@@ -128,7 +135,10 @@ export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, s
|
|
|
128
135
|
{ d: convertInstantUpdateToDefinitionChanges(instantUpdate) } :
|
|
129
136
|
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
|
|
130
137
|
}) :
|
|
131
|
-
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator)
|
|
138
|
+
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
|
|
139
|
+
if (thenable(definitionChangesRequest))
|
|
140
|
+
log.debug(SYNC_FETCH, [definitionChangesFetcher.type, since, rbSince]);
|
|
141
|
+
return Promise.resolve(definitionChangesRequest)
|
|
132
142
|
.then(function (definitionChanges) {
|
|
133
143
|
var usedSegments = new Set();
|
|
134
144
|
var updatedDefinitions = [];
|
|
@@ -3,12 +3,14 @@ import { SDK_DEFINITIONS_ARRIVED } from '../../../readiness/constants';
|
|
|
3
3
|
import { Backoff } from '../../../utils/Backoff';
|
|
4
4
|
import { SPLITS } from '../../../utils/constants';
|
|
5
5
|
import { RB_SEGMENT_UPDATE } from '../constants';
|
|
6
|
-
import {
|
|
6
|
+
import { parseUpdatePayload } from '../parseUtils';
|
|
7
7
|
import { FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT, FETCH_BACKOFF_MAX_RETRIES } from './constants';
|
|
8
8
|
/**
|
|
9
|
-
* DefinitionsUpdateWorker factory
|
|
9
|
+
* DefinitionsUpdateWorker factory for Flags SDKs, where notifications pcn and changeNumber are environment-scoped
|
|
10
10
|
*/
|
|
11
|
-
export function DefinitionsUpdateWorker(
|
|
11
|
+
export function DefinitionsUpdateWorker(params, pollingManager) {
|
|
12
|
+
var log = params.settings.log, storage = params.storage, telemetryTracker = params.telemetryTracker, definitionsEventEmitter = params.readiness.definitions;
|
|
13
|
+
var definitionsSyncTask = pollingManager.definitionsSyncTask;
|
|
12
14
|
var ff = DefinitionsUpdateWorker(storage.definitions);
|
|
13
15
|
var rbs = DefinitionsUpdateWorker(storage.rbSegments);
|
|
14
16
|
function DefinitionsUpdateWorker(cache) {
|
|
@@ -93,7 +95,7 @@ export function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, defin
|
|
|
93
95
|
put: function (parsedData) {
|
|
94
96
|
if (parsedData.d && parsedData.c !== undefined) {
|
|
95
97
|
try {
|
|
96
|
-
var payload =
|
|
98
|
+
var payload = parseUpdatePayload(parsedData.c, parsedData.d);
|
|
97
99
|
if (payload) {
|
|
98
100
|
(parsedData.type === RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData, payload);
|
|
99
101
|
return;
|
|
@@ -73,9 +73,9 @@ export function isInBitmap(bitmap, hash64hex) {
|
|
|
73
73
|
return (bitmap[internal] & 1 << offset) > 0;
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
|
-
* Parse
|
|
76
|
+
* Parse notifications for instant updates
|
|
77
77
|
*/
|
|
78
|
-
export function
|
|
78
|
+
export function parseUpdatePayload(compression, data) {
|
|
79
79
|
return compression > 0 ?
|
|
80
80
|
parseCompressedData(data, compression, false) :
|
|
81
81
|
JSON.parse(decodeFromBase64(data));
|
|
@@ -18,8 +18,9 @@ import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
|
|
|
18
18
|
* - for server-side if key is not provided in settings.
|
|
19
19
|
* - for client-side, with support for multiple clients, if key is provided in settings
|
|
20
20
|
*/
|
|
21
|
-
export function pushManagerFactory(params, pollingManager) {
|
|
22
|
-
|
|
21
|
+
export function pushManagerFactory(params, pollingManager, definitionsUpdateWorkerFactory) {
|
|
22
|
+
if (definitionsUpdateWorkerFactory === void 0) { definitionsUpdateWorkerFactory = DefinitionsUpdateWorker; }
|
|
23
|
+
var settings = params.settings, storage = params.storage, serviceApi = params.serviceApi, platform = params.platform, telemetryTracker = params.telemetryTracker;
|
|
23
24
|
// `userKey` is the matching key of main client in client-side SDK.
|
|
24
25
|
// It can be used to check if running on client-side or server-side SDK.
|
|
25
26
|
var userKey = checkIfServerSide(settings) ? undefined : getMatching(settings.core.key);
|
|
@@ -41,7 +42,7 @@ export function pushManagerFactory(params, pollingManager) {
|
|
|
41
42
|
// MySegmentsUpdateWorker (client-side) are initiated in `add` method
|
|
42
43
|
var segmentsUpdateWorker = userKey ? undefined : SegmentsUpdateWorker(log, pollingManager.segmentsSyncTask, storage.segments);
|
|
43
44
|
// For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
|
|
44
|
-
var definitionsUpdateWorker =
|
|
45
|
+
var definitionsUpdateWorker = definitionsUpdateWorkerFactory(params, pollingManager);
|
|
45
46
|
// [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
|
|
46
47
|
// Hash64 is used to process membership update events and dispatch actions to the corresponding MySegmentsUpdateWorker.
|
|
47
48
|
var clients = {};
|
package/package.json
CHANGED
package/src/dtos/types.ts
CHANGED
|
@@ -243,14 +243,14 @@ export interface IDefinition extends TargetingEntity {
|
|
|
243
243
|
/** Interface of the parsed JSON response of `/splitChanges` */
|
|
244
244
|
export interface IDefinitionChangesResponse {
|
|
245
245
|
d?: {
|
|
246
|
-
till
|
|
247
|
-
since?: number
|
|
246
|
+
till?: number,
|
|
247
|
+
since?: number,
|
|
248
248
|
updated: IDefinition[],
|
|
249
249
|
removed: string[],
|
|
250
250
|
},
|
|
251
251
|
rbs?: {
|
|
252
|
-
till
|
|
253
|
-
since?: number
|
|
252
|
+
till?: number,
|
|
253
|
+
since?: number,
|
|
254
254
|
updated: IRBSegment[],
|
|
255
255
|
removed: string[],
|
|
256
256
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ISplitHttpClient, NetworkError } from './types';
|
|
2
|
-
import { IJwtCredential } from '
|
|
3
|
-
import { fetchAuthFactory } from '
|
|
2
|
+
import { IJwtCredential } from './types';
|
|
3
|
+
import { fetchAuthFactory } from './fetchAuth';
|
|
4
4
|
import { Backoff } from '../utils/Backoff';
|
|
5
5
|
import { LOG_PREFIX_SYNC_AUTH } from '../logger/constants';
|
|
6
6
|
import { ISettings } from '../types';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { IJwtCredential, IFetchAuth } from './types';
|
|
2
|
-
import { objectAssign } from '
|
|
3
|
-
import { decodeJWTtoken } from '
|
|
4
|
-
import { IResponse } from '../../../services/types';
|
|
1
|
+
import { IJwtCredential, IFetchAuth, IResponse } from './types';
|
|
2
|
+
import { objectAssign } from '../utils/lang/objectAssign';
|
|
3
|
+
import { decodeJWTtoken } from '../utils/jwt';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Factory of authentication function.
|
package/src/services/splitApi.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
6
6
|
import { ITelemetryTracker } from '../trackers/types';
|
|
7
7
|
import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MEMBERSHIPS } from '../utils/constants';
|
|
8
8
|
import { ERROR_TOO_MANY_SETS } from '../logger/constants';
|
|
9
|
-
import { fetchAuthFactory } from '
|
|
9
|
+
import { fetchAuthFactory } from './fetchAuth';
|
|
10
10
|
|
|
11
11
|
const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
|
|
12
12
|
|