diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 3870a1f..a281849 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -49,7 +49,7 @@ jobs: run: echo "VERSION=$(cat package.json | jq -r .version)" >> $GITHUB_ENV - name: SonarQube Scan (Push) - if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development') + if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/refactor_type_definitions') uses: SonarSource/sonarcloud-github-action@v1.9 env: SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }} @@ -77,7 +77,7 @@ jobs: -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }} - name: Store assets - if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development') + if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/refactor_type_definitions') uses: actions/upload-artifact@v3 with: name: assets @@ -88,7 +88,7 @@ jobs: name: Upload assets runs-on: ubuntu-latest needs: build - if: github.event_name == 'push' && github.ref == 'refs/heads/development' + if: github.event_name == 'push' && github.ref == 'refs/heads/refactor_type_definitions' strategy: matrix: environment: diff --git a/CHANGES.txt b/CHANGES.txt index ce3ba6c..f4c99ca 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,6 @@ 2.0.0 (October XX, 2024) - Added support for targeting rules based on large segments. - - Added support for passing factory instances to the `factory` prop of the `SplitFactoryProvider` component from other SDK packages that extends the `SplitIO.ISDK` interface, such as `@splitsoftware/splitio-react-native`, `@splitsoftware/splitio-browserjs` and `@splitsoftware/browser-suite` packages. + - Added support for passing factory instances to the `factory` prop of the `SplitFactoryProvider` component from other SDK packages that extends the `SplitIO.IBrowserSDK` interface, such as `@splitsoftware/splitio-react-native`, `@splitsoftware/splitio-browserjs` and `@splitsoftware/browser-suite` packages. - 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. - Bugfixing - When the `config` prop is provided, the `SplitFactoryProvider` now makes the SDK factory and client instances available in the context immediately during the initial render, instead of waiting for the first SDK event (Related to https://github.com/splitio/react-client/issues/198). This change fixes a bug in the `useTrack` hook, which was not retrieving the client's `track` method during the initial render. @@ -8,7 +8,7 @@ - Updated error handling: using the library modules without wrapping them in a `SplitFactoryProvider` component will now throw an error instead of logging it, as the modules requires the `SplitContext` to work properly. - Removed the `core.trafficType` configuration option and the `trafficType` parameter from the SDK `client()` method, `useSplitClient`, `useTrack`, and `SplitClient` component. 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 first argument in the `track` method calls. - Removed deprecated modules: `SplitFactory` component, `useClient`, `useTreatments` and `useManager` hooks, and `withSplitFactory`, `withSplitClient` and `withSplitTreatments` high-order components. Refer to ./MIGRATION-GUIDE.md for instructions on how to migrate to the new alternatives. - - Renamed some TypeScript interfaces: `SplitIO.IBrowserSDK` to `SplitIO.ISDK`, `ISplitFactoryProps` to `ISplitFactoryProviderProps`, and `ISplitFactoryChildProps` to `ISplitFactoryProviderChildProps`. + - Renamed some TypeScript interfaces: `ISplitFactoryProps` to `ISplitFactoryProviderProps`, and `ISplitFactoryChildProps` to `ISplitFactoryProviderChildProps`. - Renamed `SplitSdk` to `SplitFactory` function, which is the underlying Split SDK factory, i.e., `import { SplitFactory } from '@splitsoftware/splitio'`. - Dropped support for React below 16.8.0, as the library components where rewritten using the React Hooks API available in React v16.8.0 and above. This refactor simplifies code maintenance and reduces bundle size. diff --git a/package-lock.json b/package-lock.json index 8ea51aa..daceee8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-react", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.2", "license": "Apache-2.0", "dependencies": { - "@splitsoftware/splitio": "11.0.0-rc.4", + "@splitsoftware/splitio": "11.0.0-rc.5", "memoize-one": "^5.1.1", "shallowequal": "^1.1.0", "tslib": "^2.3.1" @@ -1589,11 +1589,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.0-rc.5", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-11.0.0-rc.5.tgz", + "integrity": "sha512-n8nDEKtGir4sb5n0vYSoORnK+nFXYCYvGFH55aBNEpUhjMlqu9ocEPtdvtBeuz30yIb18eiiSFAr74WgnPfZHA==", "dependencies": { - "@splitsoftware/splitio-commons": "2.0.0-rc.5", + "@splitsoftware/splitio-commons": "2.0.0-rc.6", "bloom-filters": "^3.0.0", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -1606,9 +1606,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-rc.6", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.0-rc.6.tgz", + "integrity": "sha512-A4Dk02ShJBjXqtPro6ylBAPc344Unnyk7YmEmvQqv1x4VUKloLw76PI7FgUgG7bM2UH079jSIeUg8HePW2PL1g==", "dependencies": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" @@ -12150,11 +12150,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.0-rc.5", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio/-/splitio-11.0.0-rc.5.tgz", + "integrity": "sha512-n8nDEKtGir4sb5n0vYSoORnK+nFXYCYvGFH55aBNEpUhjMlqu9ocEPtdvtBeuz30yIb18eiiSFAr74WgnPfZHA==", "requires": { - "@splitsoftware/splitio-commons": "2.0.0-rc.5", + "@splitsoftware/splitio-commons": "2.0.0-rc.6", "bloom-filters": "^3.0.0", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -12164,9 +12164,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-rc.6", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.0-rc.6.tgz", + "integrity": "sha512-A4Dk02ShJBjXqtPro6ylBAPc344Unnyk7YmEmvQqv1x4VUKloLw76PI7FgUgG7bM2UH079jSIeUg8HePW2PL1g==", "requires": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" diff --git a/package.json b/package.json index d2c9bea..2aae76b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.2", "description": "A React library to easily integrate and use Split JS SDK", "main": "cjs/index.js", "module": "esm/index.js", @@ -63,7 +63,7 @@ }, "homepage": "https://github.com/splitio/react-client#readme", "dependencies": { - "@splitsoftware/splitio": "11.0.0-rc.4", + "@splitsoftware/splitio": "11.0.0-rc.5", "memoize-one": "^5.1.1", "shallowequal": "^1.1.0", "tslib": "^2.3.1" diff --git a/src/__tests__/SplitClient.test.tsx b/src/__tests__/SplitClient.test.tsx index d2bdade..74078d9 100644 --- a/src/__tests__/SplitClient.test.tsx +++ b/src/__tests__/SplitClient.test.tsx @@ -15,7 +15,7 @@ import { SplitFactoryProvider } from '../SplitFactoryProvider'; import { SplitClient } from '../SplitClient'; import { SplitContext } from '../SplitContext'; import { INITIAL_STATUS, testAttributesBinding, TestComponentProps } from './testUtils/utils'; -import { IClientWithContext } from '../utils'; +import { IBrowserClientWithContext } from '../utils'; import { EXCEPTION_NO_SFP } from '../constants'; describe('SplitClient', () => { @@ -56,7 +56,7 @@ describe('SplitClient', () => { client: outerFactory.client(), isReady: true, isReadyFromCache: true, - lastUpdate: (outerFactory.client() as IClientWithContext).__getStatus().lastUpdate + lastUpdate: (outerFactory.client() as IBrowserClientWithContext).__getStatus().lastUpdate }); return null; diff --git a/src/__tests__/SplitFactoryProvider.test.tsx b/src/__tests__/SplitFactoryProvider.test.tsx index def463b..cae3c84 100644 --- a/src/__tests__/SplitFactoryProvider.test.tsx +++ b/src/__tests__/SplitFactoryProvider.test.tsx @@ -15,7 +15,7 @@ import { ISplitFactoryProviderChildProps } from '../types'; import { SplitFactoryProvider } from '../SplitFactoryProvider'; import { SplitClient } from '../SplitClient'; import { SplitContext } from '../SplitContext'; -import { __factories, IClientWithContext } from '../utils'; +import { __factories, IBrowserClientWithContext } from '../utils'; import { WARN_SF_CONFIG_AND_FACTORY } from '../constants'; import { INITIAL_STATUS } from './testUtils/utils'; @@ -52,9 +52,9 @@ describe('SplitFactoryProvider', () => { client: outerFactory.client(), isReady: true, isReadyFromCache: true, - lastUpdate: (outerFactory.client() as IClientWithContext).__getStatus().lastUpdate + lastUpdate: (outerFactory.client() as IBrowserClientWithContext).__getStatus().lastUpdate }); - expect((childProps.factory as SplitIO.ISDK).settings.version).toBe(outerFactory.settings.version); + expect((childProps.factory as SplitIO.IBrowserSDK).settings.version).toBe(outerFactory.settings.version); return null; }} @@ -337,7 +337,7 @@ describe('SplitFactoryProvider', () => { test('cleans up on update and unmount if config prop is provided.', () => { let renderTimes = 0; - const createdFactories = new Set(); + const createdFactories = new Set(); const clientDestroySpies: jest.SpyInstance[] = []; const outerFactory = SplitFactory(sdkBrowser); diff --git a/src/__tests__/SplitTreatments.test.tsx b/src/__tests__/SplitTreatments.test.tsx index 9193b15..54d786b 100644 --- a/src/__tests__/SplitTreatments.test.tsx +++ b/src/__tests__/SplitTreatments.test.tsx @@ -8,7 +8,7 @@ jest.mock('@splitsoftware/splitio/client', () => { }); import { SplitFactory } from '@splitsoftware/splitio/client'; import { sdkBrowser } from './testUtils/sdkConfigs'; -import { getStatus, IClientWithContext } from '../utils'; +import { getStatus, IBrowserClientWithContext } from '../utils'; import { newSplitFactoryLocalhostInstance } from './testUtils/utils'; import { CONTROL_WITH_CONFIG, EXCEPTION_NO_SFP } from '../constants'; @@ -70,7 +70,7 @@ describe('SplitTreatments', () => { expect(clientMock.getTreatmentsWithConfig.mock.calls.length).toBe(1); expect(treatments).toBe(clientMock.getTreatmentsWithConfig.mock.results[0].value); expect(featureFlagNames).toBe(clientMock.getTreatmentsWithConfig.mock.calls[0][0]); - expect([isReady2, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate]).toStrictEqual([true, false, false, false, false, (outerFactory.client() as IClientWithContext).__getStatus().lastUpdate]); + expect([isReady2, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate]).toStrictEqual([true, false, false, false, false, (outerFactory.client() as IBrowserClientWithContext).__getStatus().lastUpdate]); return null; }} diff --git a/src/__tests__/testUtils/utils.tsx b/src/__tests__/testUtils/utils.tsx index 9c3171e..36a0c5f 100644 --- a/src/__tests__/testUtils/utils.tsx +++ b/src/__tests__/testUtils/utils.tsx @@ -8,7 +8,7 @@ export interface TestComponentProps { attributesClient: SplitIO.Attributes, splitKey: SplitIO.SplitKey, testSwitch: (done: jest.DoneCallback, splitKey?: SplitIO.SplitKey) => void, - factory: SplitIO.ISDK + factory: SplitIO.IBrowserSDK } export function newSplitFactoryLocalhostInstance() { diff --git a/src/types.ts b/src/types.ts index 730758f..b77f29f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -49,7 +49,7 @@ export interface ISplitContextValues extends ISplitStatus { * * NOTE: This property is not recommended for direct use, as better alternatives are available. */ - factory?: SplitIO.ISDK; + factory?: SplitIO.IBrowserSDK; /** * Split client instance. @@ -58,7 +58,7 @@ export interface ISplitContextValues extends ISplitStatus { * * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#2-instantiate-the-sdk-and-create-a-new-split-client} */ - client?: SplitIO.IClient; + client?: SplitIO.IBrowserClient; } /** @@ -120,7 +120,7 @@ export interface ISplitFactoryProviderProps extends IUpdateProps { * * If both `factory` and `config` are provided, the `config` option is ignored. */ - factory?: SplitIO.ISDK; + factory?: SplitIO.IBrowserSDK; /** * An object of type Attributes used to evaluate the feature flags. diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts index 2f75aef..8b1b66a 100644 --- a/src/useSplitClient.ts +++ b/src/useSplitClient.ts @@ -1,6 +1,6 @@ import React from 'react'; import { useSplitContext } from './SplitContext'; -import { getSplitClient, initAttributes, IClientWithContext, getStatus } from './utils'; +import { getSplitClient, initAttributes, IBrowserClientWithContext, getStatus } from './utils'; import { ISplitContextValues, IUseSplitClientOptions } from './types'; export const DEFAULT_UPDATE_OPTIONS = { @@ -31,7 +31,7 @@ export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextV const context = useSplitContext(); const { client: contextClient, factory } = context; - let client = contextClient as IClientWithContext; + let client = contextClient as IBrowserClientWithContext; if (splitKey && factory) { // @TODO `getSplitClient` starts client sync. Move side effects to useEffect client = getSplitClient(factory, splitKey); diff --git a/src/useTrack.ts b/src/useTrack.ts index 965601b..4e7fc73 100644 --- a/src/useTrack.ts +++ b/src/useTrack.ts @@ -12,7 +12,7 @@ const noOpFalse = () => false; * * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#track} */ -export function useTrack(splitKey?: SplitIO.SplitKey): SplitIO.IClient['track'] { +export function useTrack(splitKey?: SplitIO.SplitKey): SplitIO.IBrowserClient['track'] { // All update options are false to avoid re-renders. The track method doesn't need the client to be operational. const { client } = useSplitClient({ splitKey, updateOnSdkReady: false, updateOnSdkReadyFromCache: false }); return client ? client.track : noOpFalse; diff --git a/src/utils.ts b/src/utils.ts index e22b5aa..a43a2f8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -9,7 +9,7 @@ import { ISplitStatus } from './types'; /** * ClientWithContext interface. */ -export interface IClientWithContext extends SplitIO.IClient { +export interface IBrowserClientWithContext extends SplitIO.IBrowserClient { __getStatus(): { isReady: boolean; isReadyFromCache: boolean; @@ -24,13 +24,13 @@ export interface IClientWithContext extends SplitIO.IClient { /** * FactoryWithClientInstances interface. */ -export interface IFactoryWithClients extends SplitIO.ISDK { +export interface IFactoryWithLazyInit extends SplitIO.IBrowserSDK { config: SplitIO.IBrowserSettings; init(): void; } // exported for testing purposes -export const __factories: Map = new Map(); +export const __factories: Map = new Map(); // idempotent operation export function getSplitFactory(config: SplitIO.IBrowserSettings) { @@ -40,17 +40,17 @@ export function getSplitFactory(config: SplitIO.IBrowserSettings) { const newFactory = SplitFactory(config, (modules) => { modules.settings.version = VERSION; modules.lazyInit = true; - }) as IFactoryWithClients; + }) as IFactoryWithLazyInit; newFactory.config = config; __factories.set(config, newFactory); } - return __factories.get(config) as IFactoryWithClients; + return __factories.get(config) as IFactoryWithLazyInit; } // idempotent operation -export function getSplitClient(factory: SplitIO.ISDK, key?: SplitIO.SplitKey): IClientWithContext { +export function getSplitClient(factory: SplitIO.IBrowserSDK, key?: SplitIO.SplitKey): IBrowserClientWithContext { // factory.client is an idempotent operation - const client = (key !== undefined ? factory.client(key) : factory.client()) as IClientWithContext; + const client = (key !== undefined ? factory.client(key) : factory.client()) as IBrowserClientWithContext; // Remove EventEmitter warning emitted when using multiple SDK hooks or components. // Unlike JS SDK, users don't need to access the client directly, making the warning irrelevant. @@ -59,15 +59,15 @@ export function getSplitClient(factory: SplitIO.ISDK, key?: SplitIO.SplitKey): I return client; } -export function destroySplitFactory(factory: IFactoryWithClients): Promise | undefined { +export function destroySplitFactory(factory: IFactoryWithLazyInit): Promise | undefined { __factories.delete(factory.config); return factory.destroy(); } // Util used to get client status. // It might be removed in the future, if the JS SDK extends its public API with a `getStatus` method -export function getStatus(client?: SplitIO.IClient): ISplitStatus { - const status = client && (client as IClientWithContext).__getStatus(); +export function getStatus(client?: SplitIO.IBrowserClient): ISplitStatus { + const status = client && (client as IBrowserClientWithContext).__getStatus(); return { isReady: status ? status.isReady : false, @@ -82,7 +82,7 @@ export function getStatus(client?: SplitIO.IClient): ISplitStatus { /** * Manage client attributes binding */ -export function initAttributes(client?: SplitIO.IClient, attributes?: SplitIO.Attributes) { +export function initAttributes(client?: SplitIO.IBrowserClient, attributes?: SplitIO.Attributes) { if (client && attributes) client.setAttributes(attributes); } @@ -176,10 +176,10 @@ function argsAreEqual(newArgs: any[], lastArgs: any[]): boolean { shallowEqual(newArgs[5], lastArgs[5]); // flagSets } -function evaluateFeatureFlags(client: SplitIO.IClient | undefined, _lastUpdate: number, names?: SplitIO.SplitNames, attributes?: SplitIO.Attributes, _clientAttributes?: SplitIO.Attributes, flagSets?: string[]) { +function evaluateFeatureFlags(client: SplitIO.IBrowserClient | undefined, _lastUpdate: number, names?: SplitIO.SplitNames, attributes?: SplitIO.Attributes, _clientAttributes?: SplitIO.Attributes, flagSets?: string[]) { if (names && flagSets) console.log(WARN_NAMES_AND_FLAGSETS); - return client && (client as IClientWithContext).__getStatus().isOperational && (names || flagSets) ? + return client && (client as IBrowserClientWithContext).__getStatus().isOperational && (names || flagSets) ? names ? client.getTreatmentsWithConfig(names, attributes) : client.getTreatmentsWithConfigByFlagSets(flagSets!, attributes) :