diff --git a/CHANGES.txt b/CHANGES.txt index 9163d52f..8f6e73d9 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ -2.8.0 (October XX, 2025) +2.8.0 (October 28, 2025) + - Added `client.getStatus()` method to retrieve the client readiness status properties (`isReady`, `isReadyFromCache`, etc). - Added `client.whenReady()` and `client.whenReadyFromCache()` methods to replace the deprecated `client.ready()` method, which has an issue causing the returned promise to hang when using async/await syntax if it was rejected. - Updated the SDK_READY_FROM_CACHE event to be emitted alongside the SDK_READY event if it hasn’t already been emitted. diff --git a/src/readiness/__tests__/sdkReadinessManager.spec.ts b/src/readiness/__tests__/sdkReadinessManager.spec.ts index 4d47d12f..5861942f 100644 --- a/src/readiness/__tests__/sdkReadinessManager.spec.ts +++ b/src/readiness/__tests__/sdkReadinessManager.spec.ts @@ -66,8 +66,7 @@ describe('SDK Readiness Manager - Event emitter', () => { expect(typeof sdkStatus.whenReady).toBe('function'); // The sdkStatus exposes a .whenReady() function. expect(typeof sdkStatus.whenReadyFromCache).toBe('function'); // The sdkStatus exposes a .whenReadyFromCache() function. - expect(typeof sdkStatus.__getStatus).toBe('function'); // The sdkStatus exposes a .__getStatus() function. - expect(sdkStatus.__getStatus()).toEqual({ + expect(sdkStatus.getStatus()).toEqual({ // The sdkStatus exposes a .getStatus() function. isReady: false, isReadyFromCache: false, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: false, lastUpdate: 0 }); diff --git a/src/readiness/sdkReadinessManager.ts b/src/readiness/sdkReadinessManager.ts index 64e518b3..d3b841de 100644 --- a/src/readiness/sdkReadinessManager.ts +++ b/src/readiness/sdkReadinessManager.ts @@ -72,6 +72,17 @@ export function sdkReadinessManagerFactory( return promise; } + function getStatus() { + return { + isReady: readinessManager.isReady(), + isReadyFromCache: readinessManager.isReadyFromCache(), + isTimedout: readinessManager.isTimedout(), + hasTimedout: readinessManager.hasTimedout(), + isDestroyed: readinessManager.isDestroyed(), + isOperational: readinessManager.isOperational(), + lastUpdate: readinessManager.lastUpdate(), + }; + } return { readinessManager, @@ -134,17 +145,9 @@ export function sdkReadinessManagerFactory( }); }, - __getStatus() { - return { - isReady: readinessManager.isReady(), - isReadyFromCache: readinessManager.isReadyFromCache(), - isTimedout: readinessManager.isTimedout(), - hasTimedout: readinessManager.hasTimedout(), - isDestroyed: readinessManager.isDestroyed(), - isOperational: readinessManager.isOperational(), - lastUpdate: readinessManager.lastUpdate(), - }; - }, + getStatus, + // @TODO: remove in next major + __getStatus: getStatus } ) }; diff --git a/src/readiness/types.ts b/src/readiness/types.ts index df3c2603..2de99b43 100644 --- a/src/readiness/types.ts +++ b/src/readiness/types.ts @@ -1,4 +1,3 @@ -import { IStatusInterface } from '../types'; import SplitIO from '../../types/splitio'; /** Splits data emitter */ @@ -72,7 +71,7 @@ export interface IReadinessManager { export interface ISdkReadinessManager { readinessManager: IReadinessManager - sdkStatus: IStatusInterface + sdkStatus: SplitIO.IStatusInterface /** * Increment internalReadyCbCount, an offset value of SDK_READY listeners that are added/removed internally diff --git a/src/types.ts b/src/types.ts index ad3fa04c..5f6c7e39 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,21 +14,6 @@ export interface ISettings extends SplitIO.ISettings { readonly initialRolloutPlan?: RolloutPlan; } -/** - * SplitIO.IStatusInterface interface extended with private properties for internal use - */ -export interface IStatusInterface extends SplitIO.IStatusInterface { - // Expose status for internal purposes only. Not considered part of the public API, and might be updated eventually. - __getStatus(): { - isReady: boolean; - isReadyFromCache: boolean; - isTimedout: boolean; - hasTimedout: boolean; - isDestroyed: boolean; - isOperational: boolean; - lastUpdate: number; - }; -} /** * SplitIO.IBasicClient interface extended with private properties for internal use */ diff --git a/types/splitio.d.ts b/types/splitio.d.ts index 49f70c62..1c9df313 100644 --- a/types/splitio.d.ts +++ b/types/splitio.d.ts @@ -691,6 +691,52 @@ declare namespace SplitIO { [status in ConsentStatus]: ConsentStatus; }; } + /** + * Readiness Status interface. It represents the readiness state of an SDK client. + */ + interface ReadinessStatus { + + /** + * `isReady` indicates if the client has triggered an `SDK_READY` event and + * thus is ready to evaluate with cached data synchronized with the backend. + */ + isReady: boolean; + + /** + * `isReadyFromCache` indicates if the client has triggered an `SDK_READY_FROM_CACHE` event and + * thus is ready to evaluate with cached data, although the data in cache might be stale, not synchronized with the backend. + */ + isReadyFromCache: boolean; + + /** + * `isTimedout` indicates if the client has triggered an `SDK_READY_TIMED_OUT` event and is not ready to evaluate. + * In other words, `isTimedout` is equivalent to `hasTimedout && !isReady`. + */ + isTimedout: boolean; + + /** + * `hasTimedout` indicates if the client has ever triggered an `SDK_READY_TIMED_OUT` event. + * It's meant to keep a reference that the SDK emitted a timeout at some point, not the current state. + */ + hasTimedout: boolean; + + /** + * `isDestroyed` indicates if the client has been destroyed, i.e., `destroy` method has been called. + */ + isDestroyed: boolean; + + /** + * `isOperational` indicates if the client can evaluate feature flags. + * In this state, `getTreatment` calls will not return `CONTROL` due to the SDK being unready or destroyed. + * It's equivalent to `isReadyFromCache && !isDestroyed`. + */ + isOperational: boolean; + + /** + * `lastUpdate` indicates the timestamp of the most recent status event. + */ + lastUpdate: number; + } /** * Common API for entities that expose status handlers. */ @@ -699,6 +745,12 @@ declare namespace SplitIO { * Constant object containing the SDK events for you to use. */ Event: EventConsts; + /** + * Gets the readiness status. + * + * @returns The current readiness status. + */ + getStatus(): ReadinessStatus; /** * Returns a promise that resolves when the SDK has finished initial synchronization with the backend (`SDK_READY` event emitted), or rejected if the SDK has timedout (`SDK_READY_TIMED_OUT` event emitted). * As it's meant to provide similar flexibility to the event approach, given that the SDK might be eventually ready after a timeout event, the `ready` method will return a resolved promise once the SDK is ready.