From 565349539e17528d6ca773e73cb0b5e897c7b138 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 20 Sep 2024 14:54:59 -0300 Subject: [PATCH 01/15] Upgrade JS SDK dependency, which includes large segments and factory destroy method --- CHANGES.txt | 6 ++++ package-lock.json | 34 +++++++++++----------- package.json | 4 +-- src/__tests__/utils/mockBrowserSplitSdk.ts | 6 ++++ src/__tests__/utils/mockNodeSplitSdk.ts | 6 ++++ src/asyncActions.ts | 9 ++---- 6 files changed, 40 insertions(+), 25 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 441f867..59c7999 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,9 @@ +1.15.0 (September XX, 2024) + - Updated @splitsoftware/splitio package to version 10.29.0 that includes minor updates: + - Added `factory.destroy()` method, which invokes the `destroy` method on all SDK clients created by the factory. + - Added support for targeting rules based on large segments for browsers. + - Updated some transitive dependencies for vulnerability fixes. + 1.14.0 (September 13, 2024) - Added `status` property to Split reducer's slice of state to track the SDK events of non-default clients (Related to https://github.com/splitio/redux-client/issues/113). - Added `lastUpdate` and `isTimedout` properties to the object returned by the `getStatus` helper and `selectTreatmentAndStatus` and `selectTreatmentWithConfigAndStatus` selectors, to expose the last event timestamp and the timedout status of the SDK clients (Related to https://github.com/splitio/redux-client/issues/113). diff --git a/package-lock.json b/package-lock.json index 0df10ce..3feb19e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@splitsoftware/splitio-redux", - "version": "1.14.0", + "version": "1.14.1-rc.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-redux", - "version": "1.14.0", + "version": "1.14.1-rc.0", "license": "Apache-2.0", "dependencies": { - "@splitsoftware/splitio": "10.28.0", + "@splitsoftware/splitio": "10.28.1-rc.2", "tslib": "^2.3.1" }, "devDependencies": { @@ -1502,11 +1502,11 @@ } }, "node_modules/@splitsoftware/splitio": { - "version": "10.28.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-10.28.0.tgz", - "integrity": "sha512-hzBnBZHmUTXvyMBbVTDUYtspLHjyjb/YqKtetNh7pAvkmj37vOXyXfF50Of5jr3Qmvdo0YFbKvMIOEXlXSGWaQ==", + "version": "10.28.1-rc.2", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-10.28.1-rc.2.tgz", + "integrity": "sha512-UwRlu3aBY/e2cDQUxDXZCnLisleOCSUgCQSIN8gGdAKO9QQHG1Vt2cxsxMIGRIIBWUIuuUJ2phVKHM/0M2ZPhw==", "dependencies": { - "@splitsoftware/splitio-commons": "1.17.0", + "@splitsoftware/splitio-commons": "1.17.1-rc.1", "@types/google.analytics": "0.0.40", "@types/ioredis": "^4.28.0", "bloom-filters": "^3.0.0", @@ -1522,9 +1522,9 @@ } }, "node_modules/@splitsoftware/splitio-commons": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.17.0.tgz", - "integrity": "sha512-rvP+0LGUN92bcTytiqyVxq9UzBG5kTkIYjU7b7AU2awBUYgM0bqT3xhQ9/MJ/2fsBbqC6QIsxoKDOz9pMgbAQw==", + "version": "1.17.1-rc.1", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.17.1-rc.1.tgz", + "integrity": "sha512-mmDcWW2iyqQF/FzLgPoRA3KXpvswk/sDIhQGWTg3WPkapnA+e4WXb+U/TSGGB/Ig88NlM76FlxMDkrHnBayDXg==", "dependencies": { "tslib": "^2.3.1" }, @@ -11043,11 +11043,11 @@ } }, "@splitsoftware/splitio": { - "version": "10.28.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-10.28.0.tgz", - "integrity": "sha512-hzBnBZHmUTXvyMBbVTDUYtspLHjyjb/YqKtetNh7pAvkmj37vOXyXfF50Of5jr3Qmvdo0YFbKvMIOEXlXSGWaQ==", + "version": "10.28.1-rc.2", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-10.28.1-rc.2.tgz", + "integrity": "sha512-UwRlu3aBY/e2cDQUxDXZCnLisleOCSUgCQSIN8gGdAKO9QQHG1Vt2cxsxMIGRIIBWUIuuUJ2phVKHM/0M2ZPhw==", "requires": { - "@splitsoftware/splitio-commons": "1.17.0", + "@splitsoftware/splitio-commons": "1.17.1-rc.1", "@types/google.analytics": "0.0.40", "@types/ioredis": "^4.28.0", "bloom-filters": "^3.0.0", @@ -11059,9 +11059,9 @@ } }, "@splitsoftware/splitio-commons": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.17.0.tgz", - "integrity": "sha512-rvP+0LGUN92bcTytiqyVxq9UzBG5kTkIYjU7b7AU2awBUYgM0bqT3xhQ9/MJ/2fsBbqC6QIsxoKDOz9pMgbAQw==", + "version": "1.17.1-rc.1", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.17.1-rc.1.tgz", + "integrity": "sha512-mmDcWW2iyqQF/FzLgPoRA3KXpvswk/sDIhQGWTg3WPkapnA+e4WXb+U/TSGGB/Ig88NlM76FlxMDkrHnBayDXg==", "requires": { "tslib": "^2.3.1" } diff --git a/package.json b/package.json index a1715c3..48d77cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-redux", - "version": "1.14.0", + "version": "1.14.1-rc.0", "description": "A library to easily use Split JS SDK with Redux and React Redux", "main": "lib/index.js", "module": "es/index.js", @@ -59,7 +59,7 @@ }, "homepage": "https://github.com/splitio/redux-client#readme", "dependencies": { - "@splitsoftware/splitio": "10.28.0", + "@splitsoftware/splitio": "10.28.1-rc.2", "tslib": "^2.3.1" }, "devDependencies": { diff --git a/src/__tests__/utils/mockBrowserSplitSdk.ts b/src/__tests__/utils/mockBrowserSplitSdk.ts index 37c6107..148445f 100644 --- a/src/__tests__/utils/mockBrowserSplitSdk.ts +++ b/src/__tests__/utils/mockBrowserSplitSdk.ts @@ -138,6 +138,11 @@ export function mockSdk() { return __clients__[instanceId] || (__clients__[instanceId] = mockClient(key)); }); + // Factory destroy + const destroy = jest.fn(() => { + return Promise.all(Object.keys(__clients__).map(instanceId => __clients__[instanceId].destroy())); + }); + const modules = { settings: { version: 'javascript-10.18.0' } }; if (__updateModules) __updateModules(modules); @@ -145,6 +150,7 @@ export function mockSdk() { const factory = { client, manager, + destroy, settings: modules.settings, __names__: names, __split__: split, diff --git a/src/__tests__/utils/mockNodeSplitSdk.ts b/src/__tests__/utils/mockNodeSplitSdk.ts index 874c32a..1e9f9f7 100644 --- a/src/__tests__/utils/mockNodeSplitSdk.ts +++ b/src/__tests__/utils/mockNodeSplitSdk.ts @@ -92,6 +92,11 @@ export function mockSdk() { return __client__; }); + // Factory destroy + const destroy = jest.fn(() => { + return __client__.destroy(); + }); + const modules = { settings: { version: 'nodejs-10.18.0' } }; if (__updateModules) __updateModules(modules); @@ -99,6 +104,7 @@ export function mockSdk() { const factory = { client, manager, + destroy, settings: modules.settings, __names__: names, __split__: split, diff --git a/src/asyncActions.ts b/src/asyncActions.ts index d2cff5e..ebae676 100644 --- a/src/asyncActions.ts +++ b/src/asyncActions.ts @@ -294,15 +294,12 @@ export function destroySplitSdk(params: IDestroySplitSdkParams = {}): (dispatch: // Destroy the client(s) outside the thunk action, since on server-side the action is not dispatched // because stores have a life-span per session/request and there may not be one when server shuts down. const mainClient = splitSdk.factory.client(); - // in node, `splitSdk.sharedClients` is an empty object - const sharedClients = splitSdk.sharedClients; - const destroyPromises = Object.keys(sharedClients).map((clientKey) => sharedClients[clientKey].destroy()); - destroyPromises.push(mainClient.destroy()); + const destroyPromise = splitSdk.factory.destroy(); // Add onDestroy callback listener. It is important for server-side, where the thunk action is not dispatched // and so the user cannot access the promise as follows: `store.dispatch(destroySplitSdk()).then(...)` let dispatched = false; - if (params.onDestroy) Promise.all(destroyPromises).then(() => { + if (params.onDestroy) destroyPromise.then(() => { // condition to avoid calling the callback twice, since it should be called preferably after the action has been dispatched if (!dispatched) params.onDestroy(); }); @@ -310,7 +307,7 @@ export function destroySplitSdk(params: IDestroySplitSdkParams = {}): (dispatch: // Return Thunk (async) action return (dispatch: Dispatch): Promise => { dispatched = true; - return Promise.all(destroyPromises).then(function () { + return destroyPromise.then(function () { dispatch(splitDestroy(__getStatus(mainClient).lastUpdate)); if (params.onDestroy) params.onDestroy(); }); From 2ac5530dc8d1387b2ee60725368217c6eef95f79 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 29 Oct 2024 16:06:54 -0300 Subject: [PATCH 02/15] Rename build folders for consistency with other packages --- .gitignore | 16 ++++++++-------- CHANGES.txt | 3 +++ package.json | 10 +++++----- tsconfig.json | 2 +- version_replace.sh | 2 +- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 3c9ac65..d53333b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,9 @@ .DS_Store -node_modules -lib -es -types -coverage -examples -.vscode -.scannerwork +/node_modules +/cjs +/esm +/types +/coverage +/examples +/.vscode +/.scannerwork diff --git a/CHANGES.txt b/CHANGES.txt index 08c1acc..b6bca5a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +2.0.0 (September XX, 2024) + - Renamed distribution folders from `/lib` to `/cjs` for CommonJS build, and `/es` to `/esm` for ECMAScript Modules build. + 1.14.1 (October 15, 2024) - Bugfixing - Fixed error in `splitReducer` when handling actions with a `null` payload, preventing crashes caused by accessing undefined payload properties (Related to https://github.com/splitio/redux-client/issues/121). diff --git a/package.json b/package.json index cb9b2fb..f285086 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "name": "@splitsoftware/splitio-redux", "version": "1.14.1", "description": "A library to easily use Split JS SDK with Redux and React Redux", - "main": "lib/index.js", - "module": "es/index.js", + "main": "cjs/index.js", + "module": "esm/index.js", "types": "types/index.d.ts", "files": [ "README.md", @@ -11,12 +11,12 @@ "LICENSE", "CHANGES.txt", "src", - "lib", - "es", + "cjs", + "esm", "types" ], "scripts": { - "build": "rimraf lib/* es/* types/* && tsc && tsc -m commonjs --outDir lib -d true --declarationDir types", + "build": "rimraf cjs/* esm/* types/* && tsc && tsc -m commonjs --outDir cjs -d true --declarationDir types", "postbuild": "./version_replace.sh", "check": "npm run check:lint && npm run check:types", "check:lint": "eslint 'src/**/*.ts'", diff --git a/tsconfig.json b/tsconfig.json index 52a0e77..147dcc1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ "sourceMap": false, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "es", /* Redirect output structure to the directory. */ + "outDir": "esm", /* Redirect output structure to the directory. */ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "composite": true, /* Enable project compilation */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ diff --git a/version_replace.sh b/version_replace.sh index fc9d0db..f801b9c 100755 --- a/version_replace.sh +++ b/version_replace.sh @@ -2,7 +2,7 @@ VERSION=$(node -e "(function () { console.log(require('./package.json').version) })()") -replace 'REDUX_SDK_VERSION_NUMBER' $VERSION ./lib/constants.js ./es/constants.js +replace 'REDUX_SDK_VERSION_NUMBER' $VERSION ./cjs/constants.js ./esm/constants.js if [ $? -eq 0 ] then From 434a0f0eccbe466bd5af84f347a88c3a9aedbfac Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 29 Oct 2024 16:54:43 -0300 Subject: [PATCH 03/15] Upgrade JS SDK to v11 --- CHANGES.txt | 6 ++- package-lock.json | 49 ++++++++-------------- package.json | 4 +- src/__tests__/helpers.browser.test.ts | 33 +++------------ src/__tests__/reducer.test.ts | 1 - src/__tests__/utils/mockBrowserSplitSdk.ts | 24 +++++------ src/__tests__/utils/mockNodeSplitSdk.ts | 9 ++-- src/asyncActions.ts | 2 +- src/helpers.ts | 6 +-- src/types.ts | 5 +-- 10 files changed, 50 insertions(+), 89 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index b6bca5a..d2814f3 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,9 @@ -2.0.0 (September XX, 2024) +2.0.0 (November XX, 2024) + - Added support for targeting rules based on large segments. + - Updated @splitsoftware/splitio package to version 11.0.0 that includes major updates, and updated some transitive dependencies for vulnerability fixes. - Renamed distribution folders from `/lib` to `/cjs` for CommonJS build, and `/es` to `/esm` for ECMAScript Modules build. + - BREAKING CHANGES: + - Removed the `core.trafficType` configuration option and made required the `trafficType` argument when calling the `track` helper function. This is because traffic types can no longer be bound to SDK clients in JavaScript SDK v11.0.0, and so the traffic type must be provided as argument in the `track` method calls. 1.14.1 (October 15, 2024) - Bugfixing - Fixed error in `splitReducer` when handling actions with a `null` payload, preventing crashes caused by accessing undefined payload properties (Related to https://github.com/splitio/redux-client/issues/121). diff --git a/package-lock.json b/package-lock.json index 2be4f73..b1fa516 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.14.1", "license": "Apache-2.0", "dependencies": { - "@splitsoftware/splitio": "10.28.1-rc.2", + "@splitsoftware/splitio": "11.0.0-rc.4", "tslib": "^2.3.1" }, "devDependencies": { @@ -1502,13 +1502,11 @@ } }, "node_modules/@splitsoftware/splitio": { - "version": "10.28.1-rc.2", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-10.28.1-rc.2.tgz", - "integrity": "sha512-UwRlu3aBY/e2cDQUxDXZCnLisleOCSUgCQSIN8gGdAKO9QQHG1Vt2cxsxMIGRIIBWUIuuUJ2phVKHM/0M2ZPhw==", + "version": "11.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-11.0.0-rc.4.tgz", + "integrity": "sha512-hQmeTf6tEWglbZwHvfdC4j0aSzGppfizcIKs+bOhXQf2Z52SVflO0cSuu6hxnLzDFtIbnDiOses12GhUceFBkg==", "dependencies": { - "@splitsoftware/splitio-commons": "1.17.1-rc.1", - "@types/google.analytics": "0.0.40", - "@types/ioredis": "^4.28.0", + "@splitsoftware/splitio-commons": "2.0.0-rc.5", "bloom-filters": "^3.0.0", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -1517,15 +1515,15 @@ "unfetch": "^4.2.0" }, "engines": { - "node": ">=6", - "npm": ">=3" + "node": ">=14.0.0" } }, "node_modules/@splitsoftware/splitio-commons": { - "version": "1.17.1-rc.1", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.17.1-rc.1.tgz", - "integrity": "sha512-mmDcWW2iyqQF/FzLgPoRA3KXpvswk/sDIhQGWTg3WPkapnA+e4WXb+U/TSGGB/Ig88NlM76FlxMDkrHnBayDXg==", + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.0-rc.5.tgz", + "integrity": "sha512-hNLA3cfVj5yGSHpOyTQVzcU2kIceJtJOdatcuue2ENOesjwDHfpvEy/YkIgLcLwXpvUxTFKpZd1BRej8gSbWoA==", "dependencies": { + "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" }, "peerDependencies": { @@ -1789,11 +1787,6 @@ "@babel/types": "^7.3.0" } }, - "node_modules/@types/google.analytics": { - "version": "0.0.40", - "resolved": "https://registry.npmjs.org/@types/google.analytics/-/google.analytics-0.0.40.tgz", - "integrity": "sha512-R3HpnLkqmKxhUAf8kIVvDVGJqPtaaZlW4yowNwjOZUTmYUQEgHh8Nh5wkSXKMroNAuQM8gbXJHmNbbgA8tdb7Q==" - }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -11043,13 +11036,11 @@ } }, "@splitsoftware/splitio": { - "version": "10.28.1-rc.2", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-10.28.1-rc.2.tgz", - "integrity": "sha512-UwRlu3aBY/e2cDQUxDXZCnLisleOCSUgCQSIN8gGdAKO9QQHG1Vt2cxsxMIGRIIBWUIuuUJ2phVKHM/0M2ZPhw==", + "version": "11.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-11.0.0-rc.4.tgz", + "integrity": "sha512-hQmeTf6tEWglbZwHvfdC4j0aSzGppfizcIKs+bOhXQf2Z52SVflO0cSuu6hxnLzDFtIbnDiOses12GhUceFBkg==", "requires": { - "@splitsoftware/splitio-commons": "1.17.1-rc.1", - "@types/google.analytics": "0.0.40", - "@types/ioredis": "^4.28.0", + "@splitsoftware/splitio-commons": "2.0.0-rc.5", "bloom-filters": "^3.0.0", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -11059,10 +11050,11 @@ } }, "@splitsoftware/splitio-commons": { - "version": "1.17.1-rc.1", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.17.1-rc.1.tgz", - "integrity": "sha512-mmDcWW2iyqQF/FzLgPoRA3KXpvswk/sDIhQGWTg3WPkapnA+e4WXb+U/TSGGB/Ig88NlM76FlxMDkrHnBayDXg==", + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.0-rc.5.tgz", + "integrity": "sha512-hNLA3cfVj5yGSHpOyTQVzcU2kIceJtJOdatcuue2ENOesjwDHfpvEy/YkIgLcLwXpvUxTFKpZd1BRej8gSbWoA==", "requires": { + "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" } }, @@ -11265,11 +11257,6 @@ "@babel/types": "^7.3.0" } }, - "@types/google.analytics": { - "version": "0.0.40", - "resolved": "https://registry.npmjs.org/@types/google.analytics/-/google.analytics-0.0.40.tgz", - "integrity": "sha512-R3HpnLkqmKxhUAf8kIVvDVGJqPtaaZlW4yowNwjOZUTmYUQEgHh8Nh5wkSXKMroNAuQM8gbXJHmNbbgA8tdb7Q==" - }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", diff --git a/package.json b/package.json index 4e46c6c..0f92ff1 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "check": "npm run check:lint && npm run check:types", "check:lint": "eslint 'src/**/*.ts'", "check:types": "tsc --noEmit", - "test": "jest src", + "test": "jest src --silent", "test:watch": "npm test -- --watch", "test:coverage": "jest src --coverage", "test:debug": "node --inspect node_modules/.bin/jest --runInBand", @@ -59,7 +59,7 @@ }, "homepage": "https://github.com/splitio/redux-client#readme", "dependencies": { - "@splitsoftware/splitio": "10.28.1-rc.2", + "@splitsoftware/splitio": "11.0.0-rc.4", "tslib": "^2.3.1" }, "devDependencies": { diff --git a/src/__tests__/helpers.browser.test.ts b/src/__tests__/helpers.browser.test.ts index 0cbdd09..b0bd0f9 100644 --- a/src/__tests__/helpers.browser.test.ts +++ b/src/__tests__/helpers.browser.test.ts @@ -122,11 +122,11 @@ describe('track', () => { it('logs error and returns false if the SDK was not initialized', () => { const errorSpy = jest.spyOn(console, 'error'); - expect(track({ eventType: 'event' })).toBe(false); + expect(track({ eventType: 'event', trafficType: 'user' })).toBe(false); expect(errorSpy).toBeCalledWith(ERROR_TRACK_NO_INITSPLITSDK); }); - it('should invoke the track method of the main client (no traffic type in config)', () => { + it('should invoke the track method of the main client', () => { initSplitSdk({ config: sdkBrowserConfig }); expect(track({ eventType: 'event', trafficType: 'user' })).toBe(true); @@ -134,22 +134,11 @@ describe('track', () => { expect((splitSdk.factory as any).client().track.mock.calls[0][0]).toBe('user'); expect((splitSdk.factory as any).client().track.mock.calls[0][1]).toBe('event'); - // TT must be provided if not included in the config + // @ts-expect-error TT must be provided expect(track({ eventType: 'event' })).toBe(false); }); - it('should invoke the track method of the main client (traffic type in config)', () => { - initSplitSdk({ config: { ...sdkBrowserConfig, core: { ...sdkBrowserConfig.core, trafficType: 'user' } } }); - - expect(track({ eventType: 'event' })).toBe(true); - expect((splitSdk.factory as any).client().track.mock.calls.length).toBe(1); - expect((splitSdk.factory as any).client().track.mock.calls[0][0]).toBe('event'); - - // TT is ignored if included in the config - expect(track({ eventType: 'event', trafficType: 'user' })).toBe(true); - }); - - it('should invoke the track method of a shared client (no traffic type in config)', () => { + it('should invoke the track method of a shared client', () => { initSplitSdk({ config: sdkBrowserConfig }); expect(track({ eventType: 'event', key: 'user1', trafficType: 'user' })).toBe(true); @@ -157,19 +146,7 @@ describe('track', () => { expect((splitSdk.factory as any).client('user1').track.mock.calls[0][0]).toBe('user'); expect((splitSdk.factory as any).client('user1').track.mock.calls[0][1]).toBe('event'); - // TT must be provided if key is provided - expect(track({ eventType: 'event', key: 'user1' })).toBe(false); - }); - - it('should invoke the track method of a shared client (traffic type in config)', () => { - initSplitSdk({ config: { ...sdkBrowserConfig, core: { ...sdkBrowserConfig.core, trafficType: 'user' } } }); - - expect(track({ eventType: 'event', key: 'user1', trafficType: 'user' })).toBe(true); - expect((splitSdk.factory as any).client('user1').track.mock.calls.length).toBe(1); - expect((splitSdk.factory as any).client('user1').track.mock.calls[0][0]).toBe('user'); - expect((splitSdk.factory as any).client('user1').track.mock.calls[0][1]).toBe('event'); - - // TT must be provided if key is provided, no matter if present in the config, since that TT is for main client + // @ts-expect-error TT must be provided expect(track({ eventType: 'event', key: 'user1' })).toBe(false); }); diff --git a/src/__tests__/reducer.test.ts b/src/__tests__/reducer.test.ts index 10ef362..780fe4f 100644 --- a/src/__tests__/reducer.test.ts +++ b/src/__tests__/reducer.test.ts @@ -1,7 +1,6 @@ import { initialStatus, splitReducer } from '../reducer'; import { splitReady, splitReadyWithEvaluations, splitReadyFromCache, splitReadyFromCacheWithEvaluations, splitTimedout, splitUpdate, splitUpdateWithEvaluations, splitDestroy, addTreatments } from '../actions'; import { ISplitState } from '../types'; -import SplitIO from '@splitsoftware/splitio/types/splitio'; import { AnyAction } from 'redux'; const initialState: ISplitState = { diff --git a/src/__tests__/utils/mockBrowserSplitSdk.ts b/src/__tests__/utils/mockBrowserSplitSdk.ts index 148445f..137d3ba 100644 --- a/src/__tests__/utils/mockBrowserSplitSdk.ts +++ b/src/__tests__/utils/mockBrowserSplitSdk.ts @@ -1,6 +1,5 @@ import { EventEmitter } from 'events'; import promiseWrapper from './promiseWrapper'; -import SplitIO from '@splitsoftware/splitio/types/splitio'; export const Event = { SDK_READY_TIMED_OUT: 'init::timeout', @@ -22,7 +21,7 @@ function parseKey(key: SplitIO.SplitKey): SplitIO.SplitKey { }; } } -function buildInstanceId(key: any, trafficType: string | undefined) { +function buildInstanceId(key: any, trafficType?: string) { return `${key.matchingKey ? key.matchingKey : key}-${key.bucketingKey ? key.bucketingKey : key}-${trafficType !== undefined ? trafficType : ''}`; } @@ -33,7 +32,7 @@ export function mockSdk() { // ATM, isReadyFromCache is shared among clients let isReadyFromCache = false; - function mockClient(key?: SplitIO.SplitKey) { + function mockClient(_key?: SplitIO.SplitKey) { // Readiness let isReady = false; let hasTimedout = false; @@ -51,14 +50,10 @@ export function mockSdk() { __emitter__.once(Event.SDK_READY_TIMED_OUT, () => { hasTimedout = true; syncLastUpdate(); }); __emitter__.on(Event.SDK_UPDATE, () => { syncLastUpdate(); }); + let attributesCache = {}; + // Client methods const track: jest.Mock = jest.fn((tt, et, v, p) => { - if (!(key || !config.core.trafficType)) { - p = v; - v = et; - et = tt; - tt = config.core.trafficType; - } return typeof tt === 'string' && typeof et === 'string' && (typeof v === 'number' || typeof v === 'undefined') && @@ -76,14 +71,16 @@ export function mockSdk() { return acc; }, {}); }); - const setAttributes: jest.Mock = jest.fn(() => { + const setAttributes: jest.Mock = jest.fn((attributes) => { + attributesCache = Object.assign(attributesCache, attributes); return true; }); const clearAttributes: jest.Mock = jest.fn(() => { + attributesCache = {}; return true; }); const getAttributes: jest.Mock = jest.fn(() => { - return true; + return attributesCache; }); const ready: jest.Mock = jest.fn(() => { return promiseWrapper(new Promise((res, rej) => { @@ -130,11 +127,10 @@ export function mockSdk() { const manager: jest.Mock = jest.fn().mockReturnValue({ names, split, splits }); // Cache of clients - const __clients__: { [key: string]: any } = {}; + const __clients__: { [instanceId: string]: any } = {}; const client = jest.fn((key?: SplitIO.SplitKey) => { const clientKey = key || parseKey(config.core.key); - const clientTT = key ? undefined : config.core.trafficType; - const instanceId = buildInstanceId(clientKey, clientTT); + const instanceId = buildInstanceId(clientKey); return __clients__[instanceId] || (__clients__[instanceId] = mockClient(key)); }); diff --git a/src/__tests__/utils/mockNodeSplitSdk.ts b/src/__tests__/utils/mockNodeSplitSdk.ts index 1e9f9f7..35941eb 100644 --- a/src/__tests__/utils/mockNodeSplitSdk.ts +++ b/src/__tests__/utils/mockNodeSplitSdk.ts @@ -1,6 +1,5 @@ import { EventEmitter } from 'events'; import promiseWrapper from './promiseWrapper'; -import SplitIO from '@splitsoftware/splitio/types/splitio'; export const Event = { SDK_READY_TIMED_OUT: 'init::timeout', @@ -26,8 +25,12 @@ function mockClient() { __emitter__.on(Event.SDK_UPDATE, () => { syncLastUpdate(); }); // Client methods - const track: jest.Mock = jest.fn(() => { - return true; + const track: jest.Mock = jest.fn((key, tt, et, v, p) => { + return typeof key === 'string' && + typeof tt === 'string' && + typeof et === 'string' && + (typeof v === 'number' || typeof v === 'undefined') && + (typeof p === 'object' || typeof p === 'undefined'); }); const getTreatmentsWithConfig: jest.Mock = jest.fn((key, featureFlagNames) => { return featureFlagNames.reduce((acc: SplitIO.TreatmentsWithConfig, featureFlagName: string) => { diff --git a/src/asyncActions.ts b/src/asyncActions.ts index 2507797..25be2c6 100644 --- a/src/asyncActions.ts +++ b/src/asyncActions.ts @@ -173,7 +173,7 @@ export function getTreatments(params: IGetTreatmentsParams): Action | (() => voi } else { // Split SDK running in Node // Evaluate Split and return redux action. - const client = splitSdk.factory.client(); + const client = splitSdk.factory.client() as unknown as SplitIO.INodeClient; const treatments = splitNames ? client.getTreatmentsWithConfig(params.key, splitNames, params.attributes) : client.getTreatmentsWithConfigByFlagSets(params.key, flagSets, params.attributes); diff --git a/src/helpers.ts b/src/helpers.ts index 4b658ac..b1028e3 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -27,11 +27,7 @@ export function track(params: ITrackParams): boolean { } else { // Browser // client is a shared or main client whether or not the key is provided client = getClient(splitSdk, params.key); - - // TT is required if the key is provided (shared client) or if not present in config (main client) - if (params.key || !(splitSdk.config.core as SplitIO.IBrowserSettings['core']).trafficType) { - trackParams.unshift(params.trafficType); - } + trackParams.unshift(params.trafficType); } return client.track(...trackParams as [string, any]); diff --git a/src/types.ts b/src/types.ts index 4b2d6ab..64095b8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -173,10 +173,9 @@ export interface ITrackParams { key?: SplitIO.SplitKey; /** - * the traffic type of the key in the track call. If not provided, it defaults to the traffic type defined in the SDK - * config object. If not provided either in the SDK setting, the function logs an error message and returns false. + * the traffic type of the key in the track call. If not provided, the function logs an error message and returns false. */ - trafficType?: string; + trafficType: string; /** * The event type that this event should correspond to. The expected data type is String. From adb9a68dd72aa2b781a4f765b32354e121f564ad Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 29 Oct 2024 17:18:48 -0300 Subject: [PATCH 04/15] Update types --- src/asyncActions.ts | 2 +- src/helpers.ts | 16 ++++++++-------- src/types.ts | 2 +- src/utils.ts | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/asyncActions.ts b/src/asyncActions.ts index 25be2c6..6c3f9ea 100644 --- a/src/asyncActions.ts +++ b/src/asyncActions.ts @@ -14,7 +14,7 @@ import { matching, __getStatus, validateGetTreatmentsParams, isMainClient } from export interface ISplitSdk { config: SplitIO.IBrowserSettings | SplitIO.INodeSettings; splitio: ISplitFactoryBuilder; - factory: SplitIO.ISDK; + factory: SplitIO.ISDK | SplitIO.INodeSDK; sharedClients: { [stringKey: string]: SplitIO.IClient }; isDetached: boolean; // true: server-side, false: client-side (i.e., client with bound key) dispatch: Dispatch; diff --git a/src/helpers.ts b/src/helpers.ts index b1028e3..a586f9d 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -17,20 +17,20 @@ export function track(params: ITrackParams): boolean { console.error(ERROR_TRACK_NO_INITSPLITSDK); return false; } - const trackParams = [params.eventType, params.value, params.properties]; - let client; // Client getting variates depending on browser or node. + + const { key, trafficType, eventType, value, properties } = params; if (splitSdk.isDetached) { // Node // In node, user must always provide key and TT as params - client = splitSdk.factory.client(); - trackParams.unshift(params.key, params.trafficType); + const client = splitSdk.factory.client() as SplitIO.INodeClient; + + return client.track(key, trafficType, eventType, value, properties); } else { // Browser // client is a shared or main client whether or not the key is provided - client = getClient(splitSdk, params.key); - trackParams.unshift(params.trafficType); - } + const client = getClient(splitSdk, params.key); - return client.track(...trackParams as [string, any]); + return client.track(trafficType, eventType, value, properties); + } } /** diff --git a/src/types.ts b/src/types.ts index 64095b8..b2ca769 100644 --- a/src/types.ts +++ b/src/types.ts @@ -193,7 +193,7 @@ export interface ITrackParams { properties?: SplitIO.Properties; } -export type ISplitFactoryBuilder = (settings: SplitIO.IBrowserSettings | SplitIO.INodeSettings) => SplitIO.ISDK; +export type ISplitFactoryBuilder = ((settings: SplitIO.IBrowserSettings) => SplitIO.ISDK) | ((settings: SplitIO.INodeSettings) => SplitIO.INodeSDK); export type ISplitAction = { type: string; diff --git a/src/utils.ts b/src/utils.ts index ca53411..9e09fbc 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -52,7 +52,7 @@ export interface IClientStatus { } // The following util might be removed in the future, if the JS SDK extends its public API with a "getStatus" method -export function __getStatus(client: SplitIO.IClient): IClientStatus { +export function __getStatus(client: SplitIO.IBasicClient): IClientStatus { // @ts-expect-error, function exists but it is not part of JS SDK type definitions return client.__getStatus(); } From edbc8c1fbcef64430f229e24f5f053e329f65e3b Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 29 Oct 2024 17:31:42 -0300 Subject: [PATCH 05/15] Add TSDoc linter rules --- .eslintrc.js | 7 + package-lock.json | 199 +++++++++++++++++++++++--- package.json | 1 + src/__tests__/utils/promiseWrapper.ts | 4 +- src/asyncActions.ts | 14 +- src/helpers.ts | 14 +- src/react-redux/connectSplit.ts | 2 +- src/react-redux/connectToggler.ts | 27 ++-- src/selectors.ts | 38 ++--- src/types.ts | 8 +- 10 files changed, 235 insertions(+), 79 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 798635b..695bae4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -17,6 +17,7 @@ module.exports = { 'plugins': [ 'react', '@typescript-eslint', + 'eslint-plugin-tsdoc', 'import' ], 'rules': { @@ -56,5 +57,11 @@ module.exports = { 'import/no-self-import': 'error', 'import/no-default-export': 'error', } + }, { + // Enable TSDoc rules for TypeScript files, allowing the use of JSDoc in JS files. + 'files': ['**/*.ts'], + 'rules': { + 'tsdoc/syntax': 'warn' + } }], }; diff --git a/package-lock.json b/package-lock.json index b1fa516..1bfd950 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "eslint-plugin-compat": "^4.1.2", "eslint-plugin-import": "^2.27.5", "eslint-plugin-react": "^7.32.2", + "eslint-plugin-tsdoc": "^0.3.0", "husky": "^3.1.0", "jest": "^27.2.3", "react": "^18.0.0", @@ -1448,6 +1449,46 @@ "integrity": "sha512-vC+UDAsQti7Cv2oBahPfgnTXT7n0XZk8e7UFucNMmkauszdiiEsNFI0elmMMrh2u+IaMOvAAHo3DDzMx7y80Cw==", "dev": true }, + "node_modules/@microsoft/tsdoc": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz", + "integrity": "sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==", + "dev": true + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.17.0.tgz", + "integrity": "sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.15.0", + "ajv": "~8.12.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3788,6 +3829,16 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-tsdoc": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.3.0.tgz", + "integrity": "sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.15.0", + "@microsoft/tsdoc-config": "0.17.0" + } + }, "node_modules/eslint-scope": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", @@ -4436,10 +4487,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -4727,6 +4781,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -5088,12 +5154,15 @@ "dev": true }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7405,6 +7474,12 @@ "node": ">=8" } }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, "node_modules/js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -8674,6 +8749,15 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -8687,12 +8771,12 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -10991,6 +11075,44 @@ "integrity": "sha512-vC+UDAsQti7Cv2oBahPfgnTXT7n0XZk8e7UFucNMmkauszdiiEsNFI0elmMMrh2u+IaMOvAAHo3DDzMx7y80Cw==", "dev": true }, + "@microsoft/tsdoc": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz", + "integrity": "sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==", + "dev": true + }, + "@microsoft/tsdoc-config": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.17.0.tgz", + "integrity": "sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==", + "dev": true, + "requires": { + "@microsoft/tsdoc": "0.15.0", + "ajv": "~8.12.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -13019,6 +13141,16 @@ } } }, + "eslint-plugin-tsdoc": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.3.0.tgz", + "integrity": "sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==", + "dev": true, + "requires": { + "@microsoft/tsdoc": "0.15.0", + "@microsoft/tsdoc-config": "0.17.0" + } + }, "eslint-scope": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", @@ -13262,9 +13394,9 @@ "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, "function.prototype.name": { @@ -13463,6 +13595,15 @@ "has-symbols": "^1.0.2" } }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -13723,12 +13864,12 @@ } }, "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "requires": { - "has": "^1.0.3" + "hasown": "^2.0.2" } }, "is-date-object": { @@ -15429,6 +15570,12 @@ } } }, + "jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, "js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -16389,6 +16536,12 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -16402,12 +16555,12 @@ "dev": true }, "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "requires": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } diff --git a/package.json b/package.json index 0f92ff1..230c62b 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "eslint-plugin-compat": "^4.1.2", "eslint-plugin-import": "^2.27.5", "eslint-plugin-react": "^7.32.2", + "eslint-plugin-tsdoc": "^0.3.0", "husky": "^3.1.0", "jest": "^27.2.3", "react": "^18.0.0", diff --git a/src/__tests__/utils/promiseWrapper.ts b/src/__tests__/utils/promiseWrapper.ts index ee36a2f..3c4a3da 100644 --- a/src/__tests__/utils/promiseWrapper.ts +++ b/src/__tests__/utils/promiseWrapper.ts @@ -8,8 +8,8 @@ * - setting an `onFinally` handler as the first handler (e.g. `promiseWrapper(Promise.reject()).finally(...)`) * - setting more than one handler with at least one of them being an onRejected handler * - * @param customPromise promise to wrap - * @param defaultOnRejected default onRejected function + * @param customPromise - Promise to wrap + * @param defaultOnRejected - Default onRejected function * @returns a promise that doesn't need to be handled for rejection (except when using async/await syntax). */ export default function promiseWrapper(customPromise: Promise, defaultOnRejected: (_: any) => any): Promise { diff --git a/src/asyncActions.ts b/src/asyncActions.ts index 6c3f9ea..a16a345 100644 --- a/src/asyncActions.ts +++ b/src/asyncActions.ts @@ -32,7 +32,7 @@ export const splitSdk: ISplitSdk = { /** * This action creator initializes the Split SDK. It dispatches a Thunk (async) action. * - * @param {IInitSplitSdkParams} params + * @param params - Parameter object to initialize the SDK. */ export function initSplitSdk(params: IInitSplitSdkParams): (dispatch: Dispatch) => Promise { @@ -86,8 +86,8 @@ export function initSplitSdk(params: IInitSplitSdkParams): (dispatch: Dispatch { @@ -102,9 +102,9 @@ function __getTreatments(client: IClientNotDetached, evalParams: IGetTreatmentsP } /** - * This action creator performs a treatment evaluation, i.e., it invokes the actual `client.getTreatment*` methods. + * This action creator performs a feature flag evaluation, i.e., it invokes the actual `client.getTreatment*` methods. * - * @param {IGetTreatmentsParams} params + * @param params - Parameter object to evaluate feature flags. */ export function getTreatments(params: IGetTreatmentsParams): Action | (() => void) { @@ -208,8 +208,8 @@ interface IClientNotDetached extends SplitIO.IClient { * These lists are used by `getTreatments` action creator to schedule evaluation of feature flags on SDK_UPDATE, SDK_READY and SDK_READY_FROM_CACHE events. * It is exported for testing purposes only. * - * @param splitSdk it contains the Split factory, the store dispatch function, and other internal properties - * @param key optional user key + * @param splitSdk - It contains the Split factory, the store dispatch function, and other internal properties + * @param key - Optional user key * @returns SDK client with `evalOnUpdate`, `evalOnReady` and `evalOnReadyFromCache` action lists. */ export function getClient(splitSdk: ISplitSdk, key?: SplitIO.SplitKey): IClientNotDetached { diff --git a/src/helpers.ts b/src/helpers.ts index a586f9d..314041f 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -8,7 +8,7 @@ import { initialStatus } from './reducer'; * This function track events, i.e., it invokes the actual `client.track*` methods. * This function is not an action creator, but rather a simple access to `client.track()`. * - * @param {ITrackParams} params + * @param params - Parameter object to track an event. * * @see {@link https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK#track} */ @@ -36,7 +36,7 @@ export function track(params: ITrackParams): boolean { /** * Gets the array of feature flag names. * - * @returns {string[]} The list of feature flag names. The list might be empty if the SDK was not initialized or if it's not ready yet. + * @returns The list of feature flag names. The list might be empty if the SDK was not initialized or if it's not ready yet. * * @see {@link https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK#manager} */ @@ -52,8 +52,8 @@ export function getSplitNames(): string[] { /** * Gets the data of a split in SplitView format. * - * @param {string} featureFlagName The name of the split we wan't to get info of. - * @returns {SplitView} The SplitIO.SplitView of the given split, or null if split does not exist or the SDK was not initialized or is not ready. + * @param featureFlagName - The name of the feature flag we wan't to get info of. + * @returns The SplitIO.SplitView of the given split, or null if split does not exist or the SDK was not initialized or is not ready. * * @see {@link https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK#manager} */ @@ -69,7 +69,7 @@ export function getSplit(featureFlagName: string): SplitIO.SplitView { /** * Gets the array of feature flags data in SplitView format. * - * @returns {SplitViews} The list of SplitIO.SplitView. The list might be empty if the SDK was not initialized or if it's not ready yet + * @returns The list of SplitIO.SplitView. The list might be empty if the SDK was not initialized or if it's not ready yet * * @see {@link https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK#manager} */ @@ -88,10 +88,10 @@ export function getSplits(): SplitIO.SplitViews { * This function is similar to the `selectStatus` selector, but it does not require the Split state as a parameter since it uses the global `splitSdk` object. * Consider using the `selectStatus` selector instead for a more Redux-friendly approach. * - * @param {SplitIO.SplitKey} key To use only on client-side. Ignored in server-side. If a key is provided and a client associated to that key has been used, the status of that client is returned. + * @param key - To use only on client-side. Ignored in server-side. If a key is provided and a client associated to that key has been used, the status of that client is returned. * If no key is provided, the status of the main client and manager is returned (the main client shares the status with the manager). * - * @returns {IStatus} The status of the SDK client or manager. + * @returns The status of the SDK client or manager. * * @see {@link https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK#subscribe-to-events} */ diff --git a/src/react-redux/connectSplit.ts b/src/react-redux/connectSplit.ts index b0d48e1..3398c1a 100644 --- a/src/react-redux/connectSplit.ts +++ b/src/react-redux/connectSplit.ts @@ -8,7 +8,7 @@ import { defaultGetSplitState } from '../selectors'; * - The Split state at Redux, under the prop key `split`. * - The action creator `getTreatments`, bound to the `dispatch` of your store. * - * @param {IGetSplitState} getSplitState optional function that takes the entire Redux state and returns + * @param getSplitState - Optional function that takes the entire Redux state and returns * the state slice which corresponds to where the Split reducer was mounted. This functionality is rarely * needed, and defaults to assuming that the reducer is mounted under the `splitio` key. */ diff --git a/src/react-redux/connectToggler.ts b/src/react-redux/connectToggler.ts index e0997ab..c5421f3 100644 --- a/src/react-redux/connectToggler.ts +++ b/src/react-redux/connectToggler.ts @@ -9,10 +9,6 @@ const NullRenderComponent: React.ComponentType = () => null; /** * To avoid passing down dispatch property, merge props override default * behaviour from connect. Here dispatchProps are not passing down. - * - * @param {any} stateProps - * @param {any} dispatchProps - * @param {any} ownProps */ const mergeProps = (stateProps: any, dispatchProps: any, ownProps: any) => ({ ...stateProps, @@ -20,11 +16,8 @@ const mergeProps = (stateProps: any, dispatchProps: any, ownProps: any) => ({ }); /** - * This toggler just returns a react component that decides which component to render + * This toggler just returns a react component that decides which component to render * regarding it props. - * - * @param {React.ComponentType} ComponentOn - * @param {React.ComponentType} ComponentDefault */ const toggler = (ComponentOn: React.ComponentType, ComponentDefault: React.ComponentType = NullRenderComponent) => ({ isFeatureOn, ...props }: { isFeatureOn: boolean }) => @@ -34,9 +27,9 @@ const toggler = (ComponentOn: React.ComponentType, ComponentDefault: React.Compo * Looks on the features of the Split piece of state, and maps to isFeatureOn * depending if this feature is ON or not * - * @param {string} featureFlagName feature flag name - * @param {SplitIO.SplitKey} key user key - * @param {IGetSplitState} getSplitState function that extract the Split piece of state from the Redux state. + * @param featureFlagName - The feature flag name. + * @param key - The user key. + * @param getSplitState - Function that extract the Split piece of state from the Redux state. */ export function mapIsFeatureOnToProps(featureFlagName: string, key?: SplitIO.SplitKey, getSplitState: IGetSplitState = defaultGetSplitState) { return (state: any) => { @@ -51,9 +44,9 @@ export function mapIsFeatureOnToProps(featureFlagName: string, key?: SplitIO.Spl * Looks on the features of the Split piece of state, and maps to feature * the value of this feature * - * @param {string} featureFlagName feature flag name - * @param {SplitIO.SplitKey} key user key - * @param {IGetSplitState} getSplitState function that extract the Split piece of state from the Redux state. + * @param featureFlagName - The feature flag name. + * @param key - The user key. + * @param getSplitState - Function that extract the Split piece of state from the Redux state. */ export function mapTreatmentToProps(featureFlagName: string, key?: SplitIO.SplitKey, getSplitState: IGetSplitState = defaultGetSplitState): (state: any) => { feature: string } { return (state: any) => { @@ -71,9 +64,9 @@ export function mapTreatmentToProps(featureFlagName: string, key?: SplitIO.Split * * So connect send the global state and the toggler decide which to render * - * @param {string} featureFlagtName feature flag name - * @param {SplitIO.SplitKey} key user key - * @param {IGetSplitState} getSplitState function that extract the Split piece of state from the Redux state. + * @param featureFlagtName - The feature flag name. + * @param key - The user key. + * @param getSplitState - Function that extract the Split piece of state from the Redux state. */ export function connectToggler(featureFlagName: string, key?: SplitIO.SplitKey, getSplitState: IGetSplitState = defaultGetSplitState) { return (ComponentOn: React.ComponentType, ComponentDefault?: React.ComponentType) => diff --git a/src/selectors.ts b/src/selectors.ts index ed1411e..1f19da6 100644 --- a/src/selectors.ts +++ b/src/selectors.ts @@ -12,10 +12,10 @@ export const defaultGetSplitState = getStateSlice(DEFAULT_SPLIT_STATE_SLICE); * If a treatment is not found, it returns the default value, which is `'control'` if not specified. * A treatment is not found if an invalid Split state is passed or if a `getTreatments` action has not been dispatched for the provided feature flag name and key. * - * @param {ISplitState} splitState - * @param {string} featureFlagName - * @param {SplitIO.SplitKey} key - * @param {string} defaultValue + * @param splitState - The Split piece of state. + * @param featureFlagName - The feature flag name. + * @param key - The user key. + * @param defaultValue - The default value to return if the treatment is not found. */ export function selectTreatmentValue(splitState: ISplitState, featureFlagName: string, key?: SplitIO.SplitKey, defaultValue: string = CONTROL): string { return selectTreatmentWithConfig(splitState, featureFlagName, key, { treatment: defaultValue, config: null }).treatment; @@ -26,10 +26,10 @@ export function selectTreatmentValue(splitState: ISplitState, featureFlagName: s * If a treatment is not found, it returns the default value, which is `{ treatment: 'control', configuration: null }` if not specified. * A treatment is not found if an invalid Split state is passed or if a `getTreatments` action has not been dispatched for the provided feature flag name and key. * - * @param {ISplitState} splitState - * @param {string} featureFlagName - * @param {SplitIO.SplitKey} key - * @param {SplitIO.TreatmentWithConfig} defaultValue + * @param splitState - The Split piece of state. + * @param featureFlagName - The feature flag name. + * @param key - The user key. + * @param defaultValue - The default value to return if the treatment is not found. */ export function selectTreatmentWithConfig(splitState: ISplitState, featureFlagName: string, key?: SplitIO.SplitKey, defaultValue: SplitIO.TreatmentWithConfig = CONTROL_WITH_CONFIG): SplitIO.TreatmentWithConfig { const splitTreatments = splitState && splitState.treatments ? splitState.treatments[featureFlagName] : console.error(ERROR_SELECTOR_NO_SPLITSTATE); @@ -48,10 +48,10 @@ export function selectTreatmentWithConfig(splitState: ISplitState, featureFlagNa * If a treatment is not found, it returns the default value, which is `'control'` if not specified. * A treatment is not found if an invalid Split state is passed or if a `getTreatments` action has not been dispatched for the provided feature flag name and key. * - * @param {ISplitState} splitState - * @param {string} featureFlagName - * @param {SplitIO.SplitKey} key - * @param {string} defaultValue + * @param splitState - The Split piece of state. + * @param featureFlagName - The feature flag name. + * @param key - The user key. + * @param defaultValue - The default value to return if the treatment is not found. */ export function selectTreatmentAndStatus(splitState: ISplitState, featureFlagName: string, key?: SplitIO.SplitKey, defaultValue: string = CONTROL): { treatment: string @@ -66,10 +66,10 @@ export function selectTreatmentAndStatus(splitState: ISplitState, featureFlagNam * If a treatment is not found, it returns the default value as treatment, which is `{ treatment: 'control', configuration: null }` if not specified. * A treatment is not found if an invalid Split state is passed or if a `getTreatments` action has not been dispatched for the provided feature flag name and key. * - * @param {ISplitState} splitState - * @param {string} featureFlagName - * @param {SplitIO.SplitKey} key - * @param {SplitIO.TreatmentWithConfig} defaultValue + * @param splitState - The Split piece of state. + * @param featureFlagName - The feature flag name. + * @param key - The user key. + * @param defaultValue - The default value to return if the treatment is not found. */ export function selectTreatmentWithConfigAndStatus(splitState: ISplitState, featureFlagName: string, key?: SplitIO.SplitKey, defaultValue: SplitIO.TreatmentWithConfig = CONTROL_WITH_CONFIG): { treatment: SplitIO.TreatmentWithConfig @@ -87,11 +87,11 @@ export function selectTreatmentWithConfigAndStatus(splitState: ISplitState, feat /** * Extracts an object with the status properties of the SDK client or manager from the Split state. * - * @param {ISplitState} splitState - * @param {SplitIO.SplitKey} key To use only on client-side. Ignored in server-side. If a key is provided and a client associated to that key has been used, the status of that client is returned. + * @param splitState - The Split piece of state. + * @param key - To use only on client-side. Ignored in server-side. If a key is provided and a client associated to that key has been used, the status of that client is returned. * If no key is provided, the status of the main client and manager is returned (the main client shares the status with the manager). * - * @returns {IStatus} The status of the SDK client or manager. + * @returns The status of the SDK client or manager. * * @see {@link https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK#subscribe-to-events} */ diff --git a/src/types.ts b/src/types.ts index b2ca769..91b2578 100644 --- a/src/types.ts +++ b/src/types.ts @@ -77,7 +77,7 @@ export interface IInitSplitSdkParams { config: SplitIO.IBrowserSettings | SplitIO.INodeSettings; /** - * Optional param to provide a Split factory initializer to use instead of SplitFactory from '@splitsoftware/splitio'. + * Optional param to provide a Split factory initializer to use instead of SplitFactory from `'@splitsoftware/splitio'`. * It can be useful when the Split factory is imported from the UMD bundle in a HTML script. */ splitio?: ISplitFactoryBuilder; @@ -125,14 +125,16 @@ export type IGetTreatmentsParams = { * the desired behaviour for permission toggles or operation toggles, such as a kill switch, that you want to * inmediately reflect in your app. A `false` value might be useful for experiment or release toggles, where * you want to keep the treatment unchanged during the sesion of the user. - * @default false + * + * @defaultValue `false` */ evalOnUpdate?: boolean; /** * This param indicates to evaluate the feature flags if the SDK is ready from cache (i.e., it emits SDK_READY_FROM_CACHE event). * This params is only relevant when using 'LOCALSTORAGE' as storage type, since otherwise the event is never emitted. - * @default false + * + * @defaultValue `false` */ evalOnReadyFromCache?: boolean; } & ({ From 05f3f95a6158b7584bed7f596a891cdb7b98b324 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 11 Nov 2024 15:06:43 -0300 Subject: [PATCH 06/15] Upgrade JS SDK to v11.0.1 --- CHANGES.txt | 2 +- package-lock.json | 30 +++++++++++++++--------------- package.json | 2 +- src/asyncActions.ts | 8 ++++---- src/helpers.ts | 2 +- src/types.ts | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index d2814f3..df021d3 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,6 @@ 2.0.0 (November XX, 2024) - Added support for targeting rules based on large segments. - - Updated @splitsoftware/splitio package to version 11.0.0 that includes major updates, and updated some transitive dependencies for vulnerability fixes. + - Updated @splitsoftware/splitio package to version 11.0.1 that includes major updates, and updated some transitive dependencies for vulnerability fixes. - Renamed distribution folders from `/lib` to `/cjs` for CommonJS build, and `/es` to `/esm` for ECMAScript Modules build. - BREAKING CHANGES: - Removed the `core.trafficType` configuration option and made required the `trafficType` argument when calling the `track` helper function. This is because traffic types can no longer be bound to SDK clients in JavaScript SDK v11.0.0, and so the traffic type must be provided as argument in the `track` method calls. diff --git a/package-lock.json b/package-lock.json index b1fa516..6a18447 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.14.1", "license": "Apache-2.0", "dependencies": { - "@splitsoftware/splitio": "11.0.0-rc.4", + "@splitsoftware/splitio": "11.0.1", "tslib": "^2.3.1" }, "devDependencies": { @@ -1502,11 +1502,11 @@ } }, "node_modules/@splitsoftware/splitio": { - "version": "11.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-11.0.0-rc.4.tgz", - "integrity": "sha512-hQmeTf6tEWglbZwHvfdC4j0aSzGppfizcIKs+bOhXQf2Z52SVflO0cSuu6hxnLzDFtIbnDiOses12GhUceFBkg==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-11.0.1.tgz", + "integrity": "sha512-s6DF8h/ftP+vj2mpe46cDWDMy2DeEWlHLDmBGP3Rw4yOr57hdWwstg7b5mti2NLivObgVs8gKj1eoSxJK5Eb0A==", "dependencies": { - "@splitsoftware/splitio-commons": "2.0.0-rc.5", + "@splitsoftware/splitio-commons": "2.0.0", "bloom-filters": "^3.0.0", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -1519,9 +1519,9 @@ } }, "node_modules/@splitsoftware/splitio-commons": { - "version": "2.0.0-rc.5", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.0-rc.5.tgz", - "integrity": "sha512-hNLA3cfVj5yGSHpOyTQVzcU2kIceJtJOdatcuue2ENOesjwDHfpvEy/YkIgLcLwXpvUxTFKpZd1BRej8gSbWoA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.0.tgz", + "integrity": "sha512-Sz4+vFacl29xw3451z9IUgB4zBFKUWZdCnmOB0DDXA803YKPqjXphdAwN6nV+1vsX9pXV/OS6UaNC4oUICa6PA==", "dependencies": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" @@ -11036,11 +11036,11 @@ } }, "@splitsoftware/splitio": { - "version": "11.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-11.0.0-rc.4.tgz", - "integrity": "sha512-hQmeTf6tEWglbZwHvfdC4j0aSzGppfizcIKs+bOhXQf2Z52SVflO0cSuu6hxnLzDFtIbnDiOses12GhUceFBkg==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-11.0.1.tgz", + "integrity": "sha512-s6DF8h/ftP+vj2mpe46cDWDMy2DeEWlHLDmBGP3Rw4yOr57hdWwstg7b5mti2NLivObgVs8gKj1eoSxJK5Eb0A==", "requires": { - "@splitsoftware/splitio-commons": "2.0.0-rc.5", + "@splitsoftware/splitio-commons": "2.0.0", "bloom-filters": "^3.0.0", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -11050,9 +11050,9 @@ } }, "@splitsoftware/splitio-commons": { - "version": "2.0.0-rc.5", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.0-rc.5.tgz", - "integrity": "sha512-hNLA3cfVj5yGSHpOyTQVzcU2kIceJtJOdatcuue2ENOesjwDHfpvEy/YkIgLcLwXpvUxTFKpZd1BRej8gSbWoA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.0.tgz", + "integrity": "sha512-Sz4+vFacl29xw3451z9IUgB4zBFKUWZdCnmOB0DDXA803YKPqjXphdAwN6nV+1vsX9pXV/OS6UaNC4oUICa6PA==", "requires": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" diff --git a/package.json b/package.json index 0f92ff1..a6d12b5 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ }, "homepage": "https://github.com/splitio/redux-client#readme", "dependencies": { - "@splitsoftware/splitio": "11.0.0-rc.4", + "@splitsoftware/splitio": "11.0.1", "tslib": "^2.3.1" }, "devDependencies": { diff --git a/src/asyncActions.ts b/src/asyncActions.ts index 6c3f9ea..7d30059 100644 --- a/src/asyncActions.ts +++ b/src/asyncActions.ts @@ -14,8 +14,8 @@ import { matching, __getStatus, validateGetTreatmentsParams, isMainClient } from export interface ISplitSdk { config: SplitIO.IBrowserSettings | SplitIO.INodeSettings; splitio: ISplitFactoryBuilder; - factory: SplitIO.ISDK | SplitIO.INodeSDK; - sharedClients: { [stringKey: string]: SplitIO.IClient }; + factory: SplitIO.IBrowserSDK | SplitIO.ISDK; + sharedClients: { [stringKey: string]: SplitIO.IBrowserClient }; isDetached: boolean; // true: server-side, false: client-side (i.e., client with bound key) dispatch: Dispatch; } @@ -173,7 +173,7 @@ export function getTreatments(params: IGetTreatmentsParams): Action | (() => voi } else { // Split SDK running in Node // Evaluate Split and return redux action. - const client = splitSdk.factory.client() as unknown as SplitIO.INodeClient; + const client = splitSdk.factory.client() as unknown as SplitIO.IClient; const treatments = splitNames ? client.getTreatmentsWithConfig(params.key, splitNames, params.attributes) : client.getTreatmentsWithConfigByFlagSets(params.key, flagSets, params.attributes); @@ -185,7 +185,7 @@ export function getTreatments(params: IGetTreatmentsParams): Action | (() => voi /** * Interface of SDK client for not detached execution (browser). */ -interface IClientNotDetached extends SplitIO.IClient { +interface IClientNotDetached extends SplitIO.IBrowserClient { _trackingStatus?: boolean; /** * stored evaluations to execute on SDK update. It is an object because we might diff --git a/src/helpers.ts b/src/helpers.ts index a586f9d..405438f 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -22,7 +22,7 @@ export function track(params: ITrackParams): boolean { if (splitSdk.isDetached) { // Node // In node, user must always provide key and TT as params - const client = splitSdk.factory.client() as SplitIO.INodeClient; + const client = splitSdk.factory.client() as SplitIO.IClient; return client.track(key, trafficType, eventType, value, properties); } else { // Browser diff --git a/src/types.ts b/src/types.ts index b2ca769..c2733ad 100644 --- a/src/types.ts +++ b/src/types.ts @@ -193,7 +193,7 @@ export interface ITrackParams { properties?: SplitIO.Properties; } -export type ISplitFactoryBuilder = ((settings: SplitIO.IBrowserSettings) => SplitIO.ISDK) | ((settings: SplitIO.INodeSettings) => SplitIO.INodeSDK); +export type ISplitFactoryBuilder = ((settings: SplitIO.IBrowserSettings) => SplitIO.IBrowserSDK) | ((settings: SplitIO.INodeSettings) => SplitIO.ISDK); export type ISplitAction = { type: string; From 91e268cad63f5f561016a9fa590b23be45b38475 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 11 Nov 2024 17:55:26 -0300 Subject: [PATCH 07/15] Rename Node.js --- CHANGES.txt | 2 +- README.md | 2 +- src/__tests__/utils/mockNodeSplitSdk.ts | 2 +- src/asyncActions.ts | 4 ++-- src/helpers.ts | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index df021d3..828749e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -62,7 +62,7 @@ - Updated linter dependencies and rules. The deprecated TSLint package was replaced by ESLint. - Updated some transitive dependencies for vulnerability fixes. - Updated @splitsoftware/splitio package to version 10.22.4 that includes minor improvements. - - Bugfixing - Fixed error when using the SDK in localhost mode for testing with NodeJS test runners such as Jest (See https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK#localhost-mode). + - Bugfixing - Fixed error when using the SDK in localhost mode for testing with Node.js test runners such as Jest (See https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK#localhost-mode). 1.7.1 (November 15, 2022) - Updated React Redux peer dependency range to include React-redux@8.x.x and React@18.x.x. diff --git a/README.md b/README.md index 9041027..78d0a7c 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ Split has built and maintains SDKs for: * Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK) * JavaScript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK) * JavaScript for Browser [Github](https://github.com/splitio/javascript-browser-client) [Docs](https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK) -* Node [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK) +* Node.js [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK) * PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK) * PHP thin-client [Github](https://github.com/splitio/php-thin-client) [Docs](https://help.split.io/hc/en-us/articles/18305128673933-PHP-Thin-Client-SDK) * Python [Github](https://github.com/splitio/python-client) [Docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK) diff --git a/src/__tests__/utils/mockNodeSplitSdk.ts b/src/__tests__/utils/mockNodeSplitSdk.ts index 35941eb..757955c 100644 --- a/src/__tests__/utils/mockNodeSplitSdk.ts +++ b/src/__tests__/utils/mockNodeSplitSdk.ts @@ -89,7 +89,7 @@ export function mockSdk() { const splits: jest.Mock = jest.fn().mockReturnValue([]); const manager: jest.Mock = jest.fn().mockReturnValue({ names, split, splits }); - // Client (only one client on Node SDK) + // Client (only one client on Node.js) const __client__ = mockClient(); const client = jest.fn(() => { return __client__; diff --git a/src/asyncActions.ts b/src/asyncActions.ts index ab5e033..1b47dd9 100644 --- a/src/asyncActions.ts +++ b/src/asyncActions.ts @@ -39,7 +39,7 @@ export function initSplitSdk(params: IInitSplitSdkParams): (dispatch: Dispatch voi return addTreatments(params.key || (splitSdk.config as SplitIO.IBrowserSettings).core.key, splitNames ? getControlTreatmentsWithConfig(splitNames) : {}); } - } else { // Split SDK running in Node + } else { // Split SDK running in Node.js // Evaluate Split and return redux action. const client = splitSdk.factory.client() as unknown as SplitIO.IClient; diff --git a/src/helpers.ts b/src/helpers.ts index bed0cbf..d9a1c09 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -20,8 +20,8 @@ export function track(params: ITrackParams): boolean { const { key, trafficType, eventType, value, properties } = params; - if (splitSdk.isDetached) { // Node - // In node, user must always provide key and TT as params + if (splitSdk.isDetached) { // Node.js + // In Node.js, user must always provide key and TT as params const client = splitSdk.factory.client() as SplitIO.IClient; return client.track(key, trafficType, eventType, value, properties); From d3056c7c1c95bffeea716d3616919bfced5b299e Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 12 Nov 2024 16:17:04 -0300 Subject: [PATCH 08/15] Polishing --- src/__tests__/reducer.test.ts | 1 + src/__tests__/utils/mockBrowserSplitSdk.ts | 1 + src/__tests__/utils/mockNodeSplitSdk.ts | 1 + src/asyncActions.ts | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/__tests__/reducer.test.ts b/src/__tests__/reducer.test.ts index 780fe4f..10ef362 100644 --- a/src/__tests__/reducer.test.ts +++ b/src/__tests__/reducer.test.ts @@ -1,6 +1,7 @@ import { initialStatus, splitReducer } from '../reducer'; import { splitReady, splitReadyWithEvaluations, splitReadyFromCache, splitReadyFromCacheWithEvaluations, splitTimedout, splitUpdate, splitUpdateWithEvaluations, splitDestroy, addTreatments } from '../actions'; import { ISplitState } from '../types'; +import SplitIO from '@splitsoftware/splitio/types/splitio'; import { AnyAction } from 'redux'; const initialState: ISplitState = { diff --git a/src/__tests__/utils/mockBrowserSplitSdk.ts b/src/__tests__/utils/mockBrowserSplitSdk.ts index 137d3ba..46b628f 100644 --- a/src/__tests__/utils/mockBrowserSplitSdk.ts +++ b/src/__tests__/utils/mockBrowserSplitSdk.ts @@ -1,5 +1,6 @@ import { EventEmitter } from 'events'; import promiseWrapper from './promiseWrapper'; +import SplitIO from '@splitsoftware/splitio/types/splitio'; export const Event = { SDK_READY_TIMED_OUT: 'init::timeout', diff --git a/src/__tests__/utils/mockNodeSplitSdk.ts b/src/__tests__/utils/mockNodeSplitSdk.ts index 35941eb..4c4a8f7 100644 --- a/src/__tests__/utils/mockNodeSplitSdk.ts +++ b/src/__tests__/utils/mockNodeSplitSdk.ts @@ -1,5 +1,6 @@ import { EventEmitter } from 'events'; import promiseWrapper from './promiseWrapper'; +import SplitIO from '@splitsoftware/splitio/types/splitio'; export const Event = { SDK_READY_TIMED_OUT: 'init::timeout', diff --git a/src/asyncActions.ts b/src/asyncActions.ts index 7d30059..d89f42d 100644 --- a/src/asyncActions.ts +++ b/src/asyncActions.ts @@ -173,7 +173,7 @@ export function getTreatments(params: IGetTreatmentsParams): Action | (() => voi } else { // Split SDK running in Node // Evaluate Split and return redux action. - const client = splitSdk.factory.client() as unknown as SplitIO.IClient; + const client = splitSdk.factory.client() as SplitIO.IClient; const treatments = splitNames ? client.getTreatmentsWithConfig(params.key, splitNames, params.attributes) : client.getTreatmentsWithConfigByFlagSets(params.key, flagSets, params.attributes); From 9dbfcbc130f0cd4501a8917a7e24d8cf155347ed Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 12 Nov 2024 16:35:07 -0300 Subject: [PATCH 09/15] Update changelog --- CHANGES.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 828749e..dcd9169 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,9 +1,9 @@ -2.0.0 (November XX, 2024) +2.0.0 (November 15, 2024) - Added support for targeting rules based on large segments. - Updated @splitsoftware/splitio package to version 11.0.1 that includes major updates, and updated some transitive dependencies for vulnerability fixes. - Renamed distribution folders from `/lib` to `/cjs` for CommonJS build, and `/es` to `/esm` for ECMAScript Modules build. - BREAKING CHANGES: - - Removed the `core.trafficType` configuration option and made required the `trafficType` argument when calling the `track` helper function. This is because traffic types can no longer be bound to SDK clients in JavaScript SDK v11.0.0, and so the traffic type must be provided as argument in the `track` method calls. + - Removed the `core.trafficType` option from the `config` object accepted by the `initSplitSdk` action creator, and made the `trafficType` argument of the `track` helper function mandatory. This is because traffic types can no longer be bound to SDK clients since JavaScript SDK v11.0.0, so the traffic type must now be provided as an argument in `track` method calls. 1.14.1 (October 15, 2024) - Bugfixing - Fixed error in `splitReducer` when handling actions with a `null` payload, preventing crashes caused by accessing undefined payload properties (Related to https://github.com/splitio/redux-client/issues/121). From e39e0d6c1d97eea3e0c8ce118bbb907488ed2206 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 12 Nov 2024 16:56:27 -0300 Subject: [PATCH 10/15] Fix typos --- src/__tests__/reducer.test.ts | 4 ++-- src/react-redux/connectToggler.ts | 2 +- src/types.ts | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/__tests__/reducer.test.ts b/src/__tests__/reducer.test.ts index 10ef362..6f44306 100644 --- a/src/__tests__/reducer.test.ts +++ b/src/__tests__/reducer.test.ts @@ -2,7 +2,7 @@ import { initialStatus, splitReducer } from '../reducer'; import { splitReady, splitReadyWithEvaluations, splitReadyFromCache, splitReadyFromCacheWithEvaluations, splitTimedout, splitUpdate, splitUpdateWithEvaluations, splitDestroy, addTreatments } from '../actions'; import { ISplitState } from '../types'; import SplitIO from '@splitsoftware/splitio/types/splitio'; -import { AnyAction } from 'redux'; +import { Action } from 'redux'; const initialState: ISplitState = { isReady: false, @@ -179,7 +179,7 @@ describe('Split reducer', () => { }); }); - const actionCreatorsWithEvaluations: Array<[string, (key: SplitIO.SplitKey, treatments: SplitIO.TreatmentsWithConfig, timestamp: number, nonDefaultKey?: boolean) => AnyAction, boolean, boolean]> = [ + const actionCreatorsWithEvaluations: Array<[string, (key: SplitIO.SplitKey, treatments: SplitIO.TreatmentsWithConfig, timestamp: number, nonDefaultKey?: boolean) => Action, boolean, boolean]> = [ ['ADD_TREATMENTS', addTreatments, false, false], ['SPLIT_READY_WITH_EVALUATIONS', splitReadyWithEvaluations, true, false], ['SPLIT_READY_FROM_CACHE_WITH_EVALUATIONS', splitReadyFromCacheWithEvaluations, false, true], diff --git a/src/react-redux/connectToggler.ts b/src/react-redux/connectToggler.ts index c5421f3..3c072fa 100644 --- a/src/react-redux/connectToggler.ts +++ b/src/react-redux/connectToggler.ts @@ -8,7 +8,7 @@ const NullRenderComponent: React.ComponentType = () => null; /** * To avoid passing down dispatch property, merge props override default - * behaviour from connect. Here dispatchProps are not passing down. + * behavior from connect. Here dispatchProps are not passing down. */ const mergeProps = (stateProps: any, dispatchProps: any, ownProps: any) => ({ ...stateProps, diff --git a/src/types.ts b/src/types.ts index d4db8d2..cf287c6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -122,9 +122,9 @@ export type IGetTreatmentsParams = { /** * This param indicates to re-evaluate the feature flags if the SDK is updated. For example, a `true` value might be - * the desired behaviour for permission toggles or operation toggles, such as a kill switch, that you want to - * inmediately reflect in your app. A `false` value might be useful for experiment or release toggles, where - * you want to keep the treatment unchanged during the sesion of the user. + * the desired behavior for permission toggles or operation toggles, such as a kill switch, that you want to + * immediately reflect in your app. A `false` value might be useful for experiment or release toggles, where + * you want to keep the treatment unchanged during the session of the user. * * @defaultValue `false` */ From 947925dd10b25a233151662774d19deb5fa887e9 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 12 Nov 2024 18:55:36 -0300 Subject: [PATCH 11/15] Added MIGRATION-GUIDE.md file --- CHANGES.txt | 4 +++- MIGRATION-GUIDE.md | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 MIGRATION-GUIDE.md diff --git a/CHANGES.txt b/CHANGES.txt index dcd9169..d93f835 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -3,7 +3,9 @@ - Updated @splitsoftware/splitio package to version 11.0.1 that includes major updates, and updated some transitive dependencies for vulnerability fixes. - Renamed distribution folders from `/lib` to `/cjs` for CommonJS build, and `/es` to `/esm` for ECMAScript Modules build. - BREAKING CHANGES: - - Removed the `core.trafficType` option from the `config` object accepted by the `initSplitSdk` action creator, and made the `trafficType` argument of the `track` helper function mandatory. This is because traffic types can no longer be bound to SDK clients since JavaScript SDK v11.0.0, so the traffic type must now be provided as an argument in `track` method calls. + - Removed the `core.trafficType` option from the `config` object accepted by the `initSplitSdk` action creator, and made the `trafficType` argument of the `track` helper function mandatory. + This is because traffic types can no longer be bound to SDK clients since JavaScript SDK v11.0.0, so the traffic type must now be provided as an argument in `track` function calls. + Refer to ./MIGRATION-GUIDE.md for more details. 1.14.1 (October 15, 2024) - Bugfixing - Fixed error in `splitReducer` when handling actions with a `null` payload, preventing crashes caused by accessing undefined payload properties (Related to https://github.com/splitio/redux-client/issues/121). diff --git a/MIGRATION-GUIDE.md b/MIGRATION-GUIDE.md new file mode 100644 index 0000000..944b7fc --- /dev/null +++ b/MIGRATION-GUIDE.md @@ -0,0 +1,40 @@ + +# Migrating to Redux SDK v2.0.0 + +Redux SDK v2.0.0 introduces a breaking change that you should consider when migrating from a previous version. + +If you were passing the `core.trafficType` option to the SDK configuration object, you should remove it since it is no longer supported. +The `trafficType` must be passed as an argument of the `track` helper function. For example: + +```js +import { initSplitSdk, track } from '@splitsoftware/splitio-redux' + +const CONFIG = { + core: { + authorizationKey: YOUR_CLIENT_SIDE_SDK_KEY, + key: USER_KEY, + trafficType: 'user' + } +} + +store.dispatch(initSplitSdk({ config: CONFIG })) + +track({ eventType: 'my_event' }); +``` + +should be refactored to: + +```js +import { initSplitSdk, track } from '@splitsoftware/splitio-redux' + +const CONFIG = { + core: { + authorizationKey: YOUR_CLIENT_SIDE_SDK_KEY, + key: USER_KEY + } +} + +store.dispatch(initSplitSdk({ config: CONFIG })) + +track({ eventType: 'my_event', trafficType: 'user' }); +``` From 5e2967f2815d76614597776d75501155df5af232 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 12 Nov 2024 18:57:58 -0300 Subject: [PATCH 12/15] Updated 'getTreatments' action creator to not dispatch an action when called while the SDK is not operational --- CHANGES.txt | 1 + src/__tests__/asyncActions.browser.test.ts | 45 ++++++++-------------- src/asyncActions.ts | 7 +--- src/constants.ts | 7 ---- 4 files changed, 20 insertions(+), 40 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index d93f835..cfee9bd 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,7 @@ 2.0.0 (November 15, 2024) - Added support for targeting rules based on large segments. - Updated @splitsoftware/splitio package to version 11.0.1 that includes major updates, and updated some transitive dependencies for vulnerability fixes. + - Updated `getTreatments` action creator to not dispatch an action when called while the SDK is not ready or ready from cache, to avoid unnecessary updates in the state. - Renamed distribution folders from `/lib` to `/cjs` for CommonJS build, and `/es` to `/esm` for ECMAScript Modules build. - BREAKING CHANGES: - Removed the `core.trafficType` option from the `config` object accepted by the `initSplitSdk` action creator, and made the `trafficType` argument of the `track` helper function mandatory. diff --git a/src/__tests__/asyncActions.browser.test.ts b/src/__tests__/asyncActions.browser.test.ts index 4d23117..6f004a3 100644 --- a/src/__tests__/asyncActions.browser.test.ts +++ b/src/__tests__/asyncActions.browser.test.ts @@ -13,7 +13,7 @@ import { sdkBrowserConfig } from './utils/sdkConfigs'; import { SPLIT_READY, SPLIT_READY_WITH_EVALUATIONS, SPLIT_READY_FROM_CACHE, SPLIT_READY_FROM_CACHE_WITH_EVALUATIONS, SPLIT_UPDATE, SPLIT_UPDATE_WITH_EVALUATIONS, SPLIT_TIMEDOUT, SPLIT_DESTROY, ADD_TREATMENTS, - ERROR_GETT_NO_INITSPLITSDK, ERROR_DESTROY_NO_INITSPLITSDK, getControlTreatmentsWithConfig, ERROR_GETT_NO_PARAM_OBJECT, + ERROR_GETT_NO_INITSPLITSDK, ERROR_DESTROY_NO_INITSPLITSDK, ERROR_GETT_NO_PARAM_OBJECT, } from '../constants'; /** Test targets */ @@ -323,7 +323,7 @@ describe('getTreatments', () => { } }); - it('stores control treatments (without calling SDK client) and registers pending evaluations if Split SDK is not operational, to dispatch it when ready (Using action result promise)', (done) => { + it('registers evaluations if Split SDK is not operational, to dispatch it when ready (Using action result promise)', (done) => { const store = mockStore(STATE_INITIAL); const actionResult = store.dispatch(initSplitSdk({ config: sdkBrowserConfig, onReadyFromCache: onReadyFromCacheCb })); @@ -332,10 +332,7 @@ describe('getTreatments', () => { // If SDK is not operational, ADD_TREATMENTS actions are dispatched, with control treatments for provided feature flag names, and no treatments for provided flag sets. - expect(store.getActions()).toEqual([ - { type: ADD_TREATMENTS, payload: { key: sdkBrowserConfig.core.key, treatments: getControlTreatmentsWithConfig(['split2']) } }, - { type: ADD_TREATMENTS, payload: { key: sdkBrowserConfig.core.key, treatments: {} } }, - ]); + expect(store.getActions().length).toBe(0); // SDK client is not called, but items are added to 'evalOnReady' list. expect(splitSdk.factory.client().getTreatmentsWithConfig).toBeCalledTimes(0); expect(splitSdk.factory.client().getTreatmentsWithConfigByFlagSets).toBeCalledTimes(0); @@ -345,8 +342,8 @@ describe('getTreatments', () => { // When the SDK is ready from cache, the SPLIT_READY_FROM_CACHE_WITH_EVALUATIONS action is not dispatched if the `getTreatments` action was dispatched with `evalOnReadyFromCache` false (splitSdk.factory as any).client().__emitter__.emit(Event.SDK_READY_FROM_CACHE); function onReadyFromCacheCb() { - expect(store.getActions().length).toBe(3); - const action = store.getActions()[2]; + expect(store.getActions().length).toBe(1); + const action = store.getActions()[0]; expect(action).toEqual({ type: SPLIT_READY_FROM_CACHE, payload: { @@ -359,7 +356,7 @@ describe('getTreatments', () => { actionResult.then(() => { // The SPLIT_READY_WITH_EVALUATIONS action is dispatched if the SDK is ready and there are pending evaluations. - const action = store.getActions()[3]; + const action = store.getActions()[1]; expect(action).toEqual({ type: SPLIT_READY_WITH_EVALUATIONS, payload: { @@ -392,7 +389,7 @@ describe('getTreatments', () => { }); }); - it('stores control treatments (without calling SDK client) and registers pending evaluations if Split SDK is not operational, to dispatch it when ready from cache, ready, and updated (Using callbacks to assert that registered evaluations are not affected when SDK timeout)', (done) => { + it('registers pending evaluations if Split SDK is not operational, to dispatch it when ready from cache, ready, and updated (Using callbacks to assert that registered evaluations are not affected when SDK timeout)', (done) => { const store = mockStore(STATE_INITIAL); store.dispatch(initSplitSdk({ config: sdkBrowserConfig, onTimedout: onTimedoutCb, onReadyFromCache: onReadyFromCacheCb, onReady: onReadyCb })); @@ -401,15 +398,7 @@ describe('getTreatments', () => { store.dispatch(getTreatments({ splitNames: 'split3', attributes, evalOnUpdate: true, evalOnReadyFromCache: true })); // If SDK is not ready, an ADD_TREATMENTS action is dispatched with control treatments without calling SDK client - expect(store.getActions().length).toBe(1); - let action = store.getActions()[0]; - expect(action).toEqual({ - type: ADD_TREATMENTS, - payload: { - key: sdkBrowserConfig.core.key, - treatments: getControlTreatmentsWithConfig(['split3']) - } - }); + expect(store.getActions().length).toBe(0); expect(splitSdk.factory.client().getTreatmentsWithConfig).toBeCalledTimes(0); // the item is added for evaluation on SDK_READY, and also on SDK_READY_FROM_CACHE and SDK_UPDATE events @@ -421,7 +410,7 @@ describe('getTreatments', () => { // When the SDK has timedout, the SPLIT_TIMEDOUT action is dispatched. It doesn't affect registered evaluations for other SDK events. (splitSdk.factory as any).client().__emitter__.emit(Event.SDK_READY_TIMED_OUT); function onTimedoutCb() { - action = store.getActions()[1]; + const action = store.getActions()[0]; expect(action).toEqual({ type: SPLIT_TIMEDOUT, payload: { @@ -434,7 +423,7 @@ describe('getTreatments', () => { // SPLIT_READY_FROM_CACHE, because of the `evalOnReadyFromCache` param in `getTreatments` action (splitSdk.factory as any).client().__emitter__.emit(Event.SDK_READY_FROM_CACHE); function onReadyFromCacheCb() { - action = store.getActions()[2]; + const action = store.getActions()[1]; expect(action).toEqual({ type: SPLIT_READY_FROM_CACHE_WITH_EVALUATIONS, payload: { @@ -456,7 +445,7 @@ describe('getTreatments', () => { // Using cb for ready event, because action result is rejected due to SDK timeout function onReadyCb() { // The SPLIT_READY_WITH_EVALUATIONS action is dispatched if the SDK is ready and there are pending evaluations. - action = store.getActions()[3]; + let action = store.getActions()[2]; expect(action).toEqual({ type: SPLIT_READY_WITH_EVALUATIONS, payload: { @@ -476,7 +465,7 @@ describe('getTreatments', () => { // Triggering an update dispatches SPLIT_UPDATE_WITH_EVALUATIONS (splitSdk.factory as any).client().__emitter__.emit(Event.SDK_UPDATE); - action = store.getActions()[4]; + action = store.getActions()[3]; expect(action).toEqual({ type: SPLIT_UPDATE_WITH_EVALUATIONS, payload: { @@ -496,7 +485,7 @@ describe('getTreatments', () => { // We deregister the item from evalOnUpdate. store.dispatch(getTreatments({ splitNames: 'split3', evalOnUpdate: false, key: { matchingKey: sdkBrowserConfig.core.key as string, bucketingKey: 'bucket' } })); - action = store.getActions()[5]; + action = store.getActions()[4]; expect(action).toEqual({ type: ADD_TREATMENTS, payload: { @@ -508,7 +497,7 @@ describe('getTreatments', () => { // Now, SDK_UPDATE events do not trigger SPLIT_UPDATE_WITH_EVALUATIONS but SPLIT_UPDATE instead (splitSdk.factory as any).client().__emitter__.emit(Event.SDK_UPDATE); - action = store.getActions()[6]; + action = store.getActions()[5]; expect(action).toEqual({ type: SPLIT_UPDATE, payload: { @@ -516,14 +505,14 @@ describe('getTreatments', () => { } }); - expect(store.getActions().length).toBe(7); // control assertion - no more actions after the update. + expect(store.getActions().length).toBe(6); // control assertion - no more actions after the update. expect(splitSdk.factory.client().getTreatmentsWithConfig).toBeCalledTimes(4); // control assertion - called 4 times, in actions SPLIT_READY_FROM_CACHE_WITH_EVALUATIONS, SPLIT_READY_WITH_EVALUATIONS, SPLIT_UPDATE_WITH_EVALUATIONS and ADD_TREATMENTS. done(); } }); - it('for non-default clients, it stores control treatments (without calling SDK client) and registers pending evaluations if the client is not operational, to dispatch it when ready from cache, ready, and updated (Using callbacks to assert that registered evaluations are not affected when the client timeouts)', (done) => { + it('for non-default clients, registers pending evaluations if the client is not operational, to dispatch it when ready from cache, ready, and updated (Using callbacks to assert that registered evaluations are not affected when the client timeouts)', (done) => { // Init SDK and set ready const store = mockStore(STATE_INITIAL); @@ -676,7 +665,7 @@ describe('destroySplitSdk', () => { const actionResult = store.dispatch(destroySplitSdk()); actionResult.then(() => { - const action = store.getActions()[3]; + const action = store.getActions()[1]; expect(action).toEqual({ type: SPLIT_DESTROY, payload: { diff --git a/src/asyncActions.ts b/src/asyncActions.ts index 84268c0..0bab016 100644 --- a/src/asyncActions.ts +++ b/src/asyncActions.ts @@ -3,7 +3,7 @@ import { SplitFactory as SplitFactoryForLocalhost } from '@splitsoftware/splitio import { Dispatch, Action } from 'redux'; import { IInitSplitSdkParams, IGetTreatmentsParams, IDestroySplitSdkParams, ISplitFactoryBuilder } from './types'; import { splitReady, splitReadyWithEvaluations, splitReadyFromCache, splitReadyFromCacheWithEvaluations, splitTimedout, splitUpdate, splitUpdateWithEvaluations, splitDestroy, addTreatments } from './actions'; -import { VERSION, ERROR_GETT_NO_INITSPLITSDK, ERROR_DESTROY_NO_INITSPLITSDK, getControlTreatmentsWithConfig } from './constants'; +import { VERSION, ERROR_GETT_NO_INITSPLITSDK, ERROR_DESTROY_NO_INITSPLITSDK } from './constants'; import { matching, __getStatus, validateGetTreatmentsParams, isMainClient } from './utils'; /** @@ -164,10 +164,7 @@ export function getTreatments(params: IGetTreatmentsParams): Action | (() => voi splitReadyFromCacheWithEvaluations(params.key, treatments, status.lastUpdate, true) : addTreatments(params.key || (splitSdk.config as SplitIO.IBrowserSettings).core.key, treatments); } else { - // Otherwise, it adds control treatments to the store, without calling the SDK (no impressions sent) - // With flag sets, an empty object is passed since we don't know their feature flag names - // @TODO remove eventually to minimize state changes - return addTreatments(params.key || (splitSdk.config as SplitIO.IBrowserSettings).core.key, splitNames ? getControlTreatmentsWithConfig(splitNames) : {}); + return () => { }; } } else { // Split SDK running in Node.js diff --git a/src/constants.ts b/src/constants.ts index a2d00cb..f0e9eaa 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -15,13 +15,6 @@ export const CONTROL_WITH_CONFIG: SplitIO.TreatmentWithConfig = { config: null, }; -export const getControlTreatmentsWithConfig = (featureFlagNames: string[]): SplitIO.TreatmentsWithConfig => { - return featureFlagNames.reduce((pValue: SplitIO.TreatmentsWithConfig, cValue: string) => { - pValue[cValue] = CONTROL_WITH_CONFIG; - return pValue; - }, {}); -}; - // Action types export const SPLIT_READY = 'SPLIT_READY'; From f01b764982dfb2b13f9f3be77516ed089e840485 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 13 Nov 2024 15:51:56 -0300 Subject: [PATCH 13/15] Updated redux peer-dependency to >=3.0.0 --- CHANGES.txt | 3 ++- package-lock.json | 2 +- package.json | 2 +- src/types.ts | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index cfee9bd..cbf8f19 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,4 @@ -2.0.0 (November 15, 2024) +2.0.0 (November 14, 2024) - Added support for targeting rules based on large segments. - Updated @splitsoftware/splitio package to version 11.0.1 that includes major updates, and updated some transitive dependencies for vulnerability fixes. - Updated `getTreatments` action creator to not dispatch an action when called while the SDK is not ready or ready from cache, to avoid unnecessary updates in the state. @@ -7,6 +7,7 @@ - Removed the `core.trafficType` option from the `config` object accepted by the `initSplitSdk` action creator, and made the `trafficType` argument of the `track` helper function mandatory. This is because traffic types can no longer be bound to SDK clients since JavaScript SDK v11.0.0, so the traffic type must now be provided as an argument in `track` function calls. Refer to ./MIGRATION-GUIDE.md for more details. + - Updated peer dependencies to drop support for Redux library below v3.0.0. 1.14.1 (October 15, 2024) - Bugfixing - Fixed error in `splitReducer` when handling actions with a `null` payload, preventing crashes caused by accessing undefined payload properties (Related to https://github.com/splitio/redux-client/issues/121). diff --git a/package-lock.json b/package-lock.json index 66643ab..0777f0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ }, "peerDependencies": { "react-redux": ">=4.0.0", - "redux": ">=2.0.0", + "redux": ">=3.0.0", "redux-thunk": ">=2.0.0" }, "peerDependenciesMeta": { diff --git a/package.json b/package.json index 1f3bba0..134ebb9 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ }, "peerDependencies": { "react-redux": ">=4.0.0", - "redux": ">=2.0.0", + "redux": ">=3.0.0", "redux-thunk": ">=2.0.0" }, "peerDependenciesMeta": { diff --git a/src/types.ts b/src/types.ts index cf287c6..7c10731 100644 --- a/src/types.ts +++ b/src/types.ts @@ -109,7 +109,7 @@ export interface IInitSplitSdkParams { export type IGetTreatmentsParams = { /** - * user key used to evaluate. It is mandatory for node but optional for browser. If not provided in browser, + * user key used to evaluate. It is mandatory for Node.js but optional for browser. If not provided in browser, * it defaults to the key defined in the SDK config, i.e., the config object passed to `initSplitSdk`. */ key?: SplitIO.SplitKey; @@ -169,7 +169,7 @@ export interface IDestroySplitSdkParams { export interface ITrackParams { /** - * user key used to track event. It is mandatory for node but optional for browser. If not provided in browser, + * user key used to track event. It is mandatory for Node.js but optional for browser. If not provided in browser, * it defaults to the key defined in the SDK config object. */ key?: SplitIO.SplitKey; From b2d88cb752d4b505acf45c1e2daf3438da516a44 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 13 Nov 2024 16:01:24 -0300 Subject: [PATCH 14/15] rc --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0777f0a..d85eb48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio-redux", - "version": "1.14.1", + "version": "2.0.0-rc.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-redux", - "version": "1.14.1", + "version": "2.0.0-rc.0", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio": "11.0.1", diff --git a/package.json b/package.json index 134ebb9..bb98ec2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-redux", - "version": "1.14.1", + "version": "2.0.0-rc.0", "description": "A library to easily use Split JS SDK with Redux and React Redux", "main": "cjs/index.js", "module": "esm/index.js", From 8a993672784e3c9e54c5e2c2714adc0e88c28a1f Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 13 Nov 2024 16:35:36 -0300 Subject: [PATCH 15/15] stable version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d85eb48..f176b5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio-redux", - "version": "2.0.0-rc.0", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-redux", - "version": "2.0.0-rc.0", + "version": "2.0.0", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio": "11.0.1", diff --git a/package.json b/package.json index bb98ec2..154503f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-redux", - "version": "2.0.0-rc.0", + "version": "2.0.0", "description": "A library to easily use Split JS SDK with Redux and React Redux", "main": "cjs/index.js", "module": "esm/index.js",