Skip to content

Commit e31343a

Browse files
Merge pull request #200 from splitio/development
Release v1.13.0
2 parents 7bf1b47 + eeffae2 commit e31343a

12 files changed

+412
-498
lines changed

CHANGES.txt

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
1.13.0 (September 6, 2024)
2+
- Updated @splitsoftware/splitio package to version 10.28.0 that includes minor updates:
3+
- Added `sync.requestOptions.getHeaderOverrides` configuration option to enhance SDK HTTP request Headers for Authorization Frameworks.
4+
- Updated some transitive dependencies for vulnerability fixes.
5+
16
1.12.1 (August 2, 2024)
27
- Updated @splitsoftware/splitio package to version 10.27.0 and some transitive dependencies for vulnerability fixes.
38

package-lock.json

+353-444
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@splitsoftware/splitio-react",
3-
"version": "1.12.1",
3+
"version": "1.13.0",
44
"description": "A React library to easily integrate and use Split JS SDK",
55
"main": "lib/index.js",
66
"module": "es/index.js",
@@ -63,7 +63,7 @@
6363
},
6464
"homepage": "https://github.com/splitio/react-client#readme",
6565
"dependencies": {
66-
"@splitsoftware/splitio": "10.27.0",
66+
"@splitsoftware/splitio": "10.28.0",
6767
"memoize-one": "^5.1.1",
6868
"shallowequal": "^1.1.0",
6969
"tslib": "^2.3.1"

src/SplitClient.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class SplitComponent extends React.Component<IUpdateProps & { factory: Sp
8686
}
8787

8888
update = () => {
89-
this.setState({ lastUpdate: (this.state.client as IClientWithContext).lastUpdate });
89+
this.setState({ lastUpdate: (this.state.client as IClientWithContext).__getStatus().lastUpdate });
9090
}
9191

9292
componentDidMount() {

src/__tests__/SplitClient.test.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { SplitFactoryProvider } from '../SplitFactoryProvider';
1515
import { SplitClient } from '../SplitClient';
1616
import { SplitContext } from '../SplitContext';
1717
import { testAttributesBinding, TestComponentProps } from './testUtils/utils';
18+
import { IClientWithContext } from '../utils';
1819

1920
describe('SplitClient', () => {
2021

@@ -55,7 +56,7 @@ describe('SplitClient', () => {
5556
expect(hasTimedout).toBe(false);
5657
expect(isTimedout).toBe(false);
5758
expect(isDestroyed).toBe(false);
58-
expect(lastUpdate).toBe(0);
59+
expect(lastUpdate).toBe((outerFactory.client() as IClientWithContext).__getStatus().lastUpdate);
5960

6061
return null;
6162
}}
@@ -212,7 +213,7 @@ describe('SplitClient', () => {
212213
count++;
213214

214215
// side effect in the render phase
215-
if (!(client as any).__getStatus().isReady) {
216+
if (!(client as IClientWithContext).__getStatus().isReady) {
216217
console.log('emit');
217218
(client as any).__emitter__.emit(Event.SDK_READY);
218219
}

src/__tests__/SplitFactory.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { ISplitFactoryChildProps } from '../types';
1515
import { SplitFactory } from '../SplitFactory';
1616
import { SplitClient } from '../SplitClient';
1717
import { SplitContext } from '../SplitContext';
18-
import { __factories } from '../utils';
18+
import { __factories, IClientWithContext } from '../utils';
1919
import { WARN_SF_CONFIG_AND_FACTORY, ERROR_SF_NO_CONFIG_AND_FACTORY } from '../constants';
2020

2121
describe('SplitFactory', () => {
@@ -54,7 +54,7 @@ describe('SplitFactory', () => {
5454
expect(hasTimedout).toBe(false);
5555
expect(isTimedout).toBe(false);
5656
expect(isDestroyed).toBe(false);
57-
expect(lastUpdate).toBe(0);
57+
expect(lastUpdate).toBe((outerFactory.client() as IClientWithContext).__getStatus().lastUpdate);
5858
expect((factory as SplitIO.ISDK).settings.version).toBe(outerFactory.settings.version);
5959
return null;
6060
}}

src/__tests__/SplitFactoryProvider.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { ISplitFactoryChildProps } from '../types';
1515
import { SplitFactoryProvider } from '../SplitFactoryProvider';
1616
import { SplitClient } from '../SplitClient';
1717
import { SplitContext } from '../SplitContext';
18-
import { __factories } from '../utils';
18+
import { __factories, IClientWithContext } from '../utils';
1919
import { WARN_SF_CONFIG_AND_FACTORY } from '../constants';
2020

2121
describe('SplitFactoryProvider', () => {
@@ -54,7 +54,7 @@ describe('SplitFactoryProvider', () => {
5454
expect(hasTimedout).toBe(false);
5555
expect(isTimedout).toBe(false);
5656
expect(isDestroyed).toBe(false);
57-
expect(lastUpdate).toBe(0);
57+
expect(lastUpdate).toBe((outerFactory.client() as IClientWithContext).__getStatus().lastUpdate);
5858
expect((factory as SplitIO.ISDK).settings.version).toBe(outerFactory.settings.version);
5959
return null;
6060
}}

src/__tests__/SplitTreatments.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jest.mock('@splitsoftware/splitio/client', () => {
88
});
99
import { SplitFactory as SplitSdk } from '@splitsoftware/splitio/client';
1010
import { sdkBrowser } from './testUtils/sdkConfigs';
11-
import { getStatus } from '../utils';
11+
import { getStatus, IClientWithContext } from '../utils';
1212
import { newSplitFactoryLocalhostInstance } from './testUtils/utils';
1313
import { CONTROL_WITH_CONFIG } from '../constants';
1414

@@ -70,7 +70,7 @@ describe('SplitTreatments', () => {
7070
expect(clientMock.getTreatmentsWithConfig.mock.calls.length).toBe(1);
7171
expect(treatments).toBe(clientMock.getTreatmentsWithConfig.mock.results[0].value);
7272
expect(featureFlagNames).toBe(clientMock.getTreatmentsWithConfig.mock.calls[0][0]);
73-
expect([isReady2, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate]).toStrictEqual([true, false, false, false, false, 0]);
73+
expect([isReady2, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate]).toStrictEqual([true, false, false, false, false, (outerFactory.client() as IClientWithContext).__getStatus().lastUpdate]);
7474
return null;
7575
}}
7676
</SplitTreatments>

src/__tests__/testUtils/mockSplitSdk.ts

+29-17
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export const reactSdkVersion = `react-${reactSdkPackageJson.version}`;
99
export const Event = {
1010
SDK_READY_TIMED_OUT: 'init::timeout',
1111
SDK_READY: 'init::ready',
12-
SDK_UPDATE: 'state::update',
1312
SDK_READY_FROM_CACHE: 'init::cache-ready',
13+
SDK_UPDATE: 'state::update',
1414
};
1515

1616
function parseKey(key: SplitIO.SplitKey): SplitIO.SplitKey {
@@ -32,14 +32,22 @@ function buildInstanceId(key: any, trafficType: string | undefined) {
3232

3333
function mockClient(_key: SplitIO.SplitKey, _trafficType?: string) {
3434
// Readiness
35-
let __isReady__: boolean | undefined;
36-
let __isReadyFromCache__: boolean | undefined;
37-
let __hasTimedout__: boolean | undefined;
38-
let __isDestroyed__: boolean | undefined;
35+
let isReady = false;
36+
let isReadyFromCache = false;
37+
let hasTimedout = false;
38+
let isDestroyed = false;
39+
let lastUpdate = 0;
40+
41+
function syncLastUpdate() {
42+
const dateNow = Date.now();
43+
lastUpdate = dateNow > lastUpdate ? dateNow : lastUpdate + 1;
44+
}
45+
3946
const __emitter__ = new EventEmitter();
40-
__emitter__.on(Event.SDK_READY, () => { __isReady__ = true; });
41-
__emitter__.on(Event.SDK_READY_FROM_CACHE, () => { __isReadyFromCache__ = true; });
42-
__emitter__.on(Event.SDK_READY_TIMED_OUT, () => { __hasTimedout__ = true; });
47+
__emitter__.on(Event.SDK_READY, () => { isReady = true; syncLastUpdate(); });
48+
__emitter__.on(Event.SDK_READY_FROM_CACHE, () => { isReadyFromCache = true; syncLastUpdate(); });
49+
__emitter__.on(Event.SDK_READY_TIMED_OUT, () => { hasTimedout = true; syncLastUpdate(); });
50+
__emitter__.on(Event.SDK_UPDATE, () => { syncLastUpdate(); });
4351

4452
let attributesCache = {};
4553

@@ -72,21 +80,24 @@ function mockClient(_key: SplitIO.SplitKey, _trafficType?: string) {
7280
});
7381
const ready: jest.Mock = jest.fn(() => {
7482
return new Promise<void>((res, rej) => {
75-
if (__isReady__) res();
83+
if (isReady) res();
7684
else { __emitter__.on(Event.SDK_READY, res); }
77-
if (__hasTimedout__) rej();
85+
if (hasTimedout) rej();
7886
else { __emitter__.on(Event.SDK_READY_TIMED_OUT, rej); }
7987
});
8088
});
8189
const __getStatus = () => ({
82-
isReady: __isReady__ || false,
83-
isReadyFromCache: __isReadyFromCache__ || false,
84-
hasTimedout: __hasTimedout__ || false,
85-
isDestroyed: __isDestroyed__ || false,
86-
isOperational: ((__isReady__ || __isReadyFromCache__) && !__isDestroyed__) || false,
90+
isReady,
91+
isReadyFromCache,
92+
isTimedout: hasTimedout && !isReady,
93+
hasTimedout,
94+
isDestroyed,
95+
isOperational: (isReady || isReadyFromCache) && !isDestroyed,
96+
lastUpdate,
8797
});
8898
const destroy: jest.Mock = jest.fn(() => {
89-
__isDestroyed__ = true;
99+
isDestroyed = true;
100+
syncLastUpdate();
90101
// __emitter__.removeAllListeners();
91102
return Promise.resolve();
92103
});
@@ -108,7 +119,8 @@ function mockClient(_key: SplitIO.SplitKey, _trafficType?: string) {
108119
// Restore the mock client to its initial NO-READY status.
109120
// Useful when you want to reuse the same mock between tests after emitting events or destroying the instance.
110121
__restore() {
111-
__isReady__ = __isReadyFromCache__ = __hasTimedout__ = __isDestroyed__ = undefined;
122+
isReady = isReadyFromCache = hasTimedout = isDestroyed = false;
123+
lastUpdate = 0;
112124
}
113125
});
114126
}

src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export interface ISplitStatus {
1919

2020
/**
2121
* isTimedout indicates if the Split SDK client has triggered an SDK_READY_TIMED_OUT event and is not ready to be consumed.
22+
* In other words, `isTimedout` is equivalent to `hasTimeout && !isReady`.
2223
*/
2324
isTimedout: boolean;
2425

src/useSplitClient.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextV
4545
React.useEffect(() => {
4646
if (!client) return;
4747

48-
const update = () => setLastUpdate(client.lastUpdate);
48+
const update = () => setLastUpdate(client.__getStatus().lastUpdate);
4949

5050
// Clients are created on the hook's call, so the status may have changed
5151
const statusOnEffect = getStatus(client);

src/utils.ts

+11-25
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ export interface IClientWithContext extends SplitIO.IBrowserClient {
1313
__getStatus(): {
1414
isReady: boolean;
1515
isReadyFromCache: boolean;
16-
isOperational: boolean;
16+
isTimedout: boolean;
1717
hasTimedout: boolean;
1818
isDestroyed: boolean;
19+
isOperational: boolean;
20+
lastUpdate: number;
1921
};
20-
lastUpdate: number;
2122
}
2223

2324
/**
@@ -51,23 +52,9 @@ export function getSplitClient(factory: SplitIO.IBrowserSDK, key?: SplitIO.Split
5152
// factory.client is an idempotent operation
5253
const client = (key !== undefined ? factory.client(key, trafficType) : factory.client()) as IClientWithContext;
5354

54-
// Handle client lastUpdate
55-
if (client.lastUpdate === undefined) {
56-
// Remove EventEmitter warning emitted when using multiple SDK hooks or components.
57-
// Unlike JS SDK, users can avoid using the client directly, making the warning irrelevant.
58-
client.setMaxListeners(0);
59-
60-
const updateLastUpdate = () => {
61-
const lastUpdate = Date.now();
62-
client.lastUpdate = lastUpdate > client.lastUpdate ? lastUpdate : client.lastUpdate + 1;
63-
}
64-
65-
client.lastUpdate = 0;
66-
client.on(client.Event.SDK_READY, updateLastUpdate);
67-
client.on(client.Event.SDK_READY_FROM_CACHE, updateLastUpdate);
68-
client.on(client.Event.SDK_READY_TIMED_OUT, updateLastUpdate);
69-
client.on(client.Event.SDK_UPDATE, updateLastUpdate);
70-
}
55+
// Remove EventEmitter warning emitted when using multiple SDK hooks or components.
56+
// Unlike JS SDK, users don't need to access the client directly, making the warning irrelevant.
57+
client.setMaxListeners(0);
7158

7259
if ((factory as IFactoryWithClients).clientInstances) {
7360
(factory as IFactoryWithClients).clientInstances.add(client);
@@ -89,15 +76,14 @@ export function destroySplitFactory(factory: IFactoryWithClients): Promise<void[
8976
// It might be removed in the future, if the JS SDK extends its public API with a `getStatus` method
9077
export function getStatus(client: SplitIO.IBrowserClient | null): ISplitStatus {
9178
const status = client && (client as IClientWithContext).__getStatus();
92-
const isReady = status ? status.isReady : false;
93-
const hasTimedout = status ? status.hasTimedout : false;
79+
9480
return {
95-
isReady,
81+
isReady: status ? status.isReady : false,
9682
isReadyFromCache: status ? status.isReadyFromCache : false,
97-
isTimedout: hasTimedout && !isReady,
98-
hasTimedout,
83+
isTimedout: status ? status.isTimedout : false,
84+
hasTimedout: status ? status.hasTimedout : false,
9985
isDestroyed: status ? status.isDestroyed : false,
100-
lastUpdate: client ? (client as IClientWithContext).lastUpdate || 0 : 0,
86+
lastUpdate: status ? status.lastUpdate : 0,
10187
};
10288
}
10389

0 commit comments

Comments
 (0)