Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
2.0.1 (November 25, 2024)
- Bugfixing - Fixed an issue with the SDK_UPDATE event on server-side, where it was not being emitted if there was an empty segment and the SDK received a feature flag update notification.

2.0.0 (November 1, 2024)
- Added support for targeting rules based on large segments.
- Added `factory.destroy()` method, which invokes the `destroy` method on all SDK clients created by the factory.
Expand All @@ -20,7 +23,7 @@
- Updated some transitive dependencies for vulnerability fixes.

1.16.0 (June 13, 2024)
- Added the `getOptions` method to the `IPlatform` interface to allow the SDK to pass request options to the `fetch` function and `EventSource` constructor when fetching data from the Split servers. The method is optional and, if provided, it is called twice: first for the `fetch` options and then for the `EventSource` options. Useful for advanced use cases like configuring a proxy or validating HTTPS certificates in NodeJS.
- Added the `getOptions` method to the `IPlatform` interface to allow the SDK to pass request options to the `fetch` function and `EventSource` constructor when fetching data from the Split servers. The method is optional and, if provided, it is called twice: first for the `fetch` options and then for the `EventSource` options. Useful for advanced use cases like configuring a proxy or validating HTTPS certificates in Node.js.
- Updated the Redis storage to lazily import the `ioredis` dependency when the storage is created. This prevents errors when the SDK is imported or bundled in a .mjs file, as `ioredis` is a CommonJS module.
- Bugfixing - Restored some input validation error logs that were removed in version 1.12.0. The logs inform the user when the `getTreatment(s)` methods are called with an invalid value as feature flag name or flag set name.
- Bugfixing - Fixed localhost mode to emit SDK_UPDATE when mocked feature flags are updated in the `features` object map of the config object (Related to issue https://github.com/splitio/javascript-browser-client/issues/119).
Expand Down Expand Up @@ -57,7 +60,7 @@
- Added a new optional Split Filter configuration option. This allows the SDK and Split services to only synchronize the flags in the specified flag sets, avoiding unused or unwanted flags from being synced on the SDK instance, bringing all the benefits from a reduced payload.
- Note: Only applicable when the SDK is in charge of the rollout data synchronization. When not applicable, the SDK will log a warning on init.
- Added `sets` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager to expose flag sets on flag views.
- Bugfixing - Fixed SDK key validation in NodeJS to ensure the SDK_READY_TIMED_OUT event is emitted when a client-side type SDK key is provided instead of a server-side one (Related to issue https://github.com/splitio/javascript-client/issues/768).
- Bugfixing - Fixed SDK key validation in Node.js to ensure the SDK_READY_TIMED_OUT event is emitted when a client-side type SDK key is provided instead of a server-side one (Related to issue https://github.com/splitio/javascript-client/issues/768).

1.10.0 (October 20, 2023)
- Added `defaultTreatment` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager (Related to issue https://github.com/splitio/javascript-commons/issues/225).
Expand Down Expand Up @@ -135,7 +138,7 @@
1.3.0 (April 6, 2022)
- Added user consent feature to allow delaying or disabling the data tracking from SDK until user consent is explicitly granted or declined. Read more in our docs.
- Added `scheduler.impressionsQueueSize` property to SDK configuration to limit the amount of impressions tracked in memory. Read more in our docs.
- Added support to accept TLS configuration options to the Redis storage in NodeJS. Read more in our docs.
- Added support to accept TLS configuration options to the Redis storage in Node.js. Read more in our docs.
- Updated format for MySegments keys in LocalStorage, keeping backwards compatibility (issue https://github.com/splitio/javascript-client/issues/638).
- Updated some modules due to general polishing and refactors, including updates in some log messages.
- Updated some dependencies for vulnerability fixes.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,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)
Expand Down
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@splitsoftware/splitio-commons",
"version": "2.0.0",
"version": "2.0.1",
"description": "Split JavaScript SDK common components",
"main": "cjs/index.js",
"module": "esm/index.js",
Expand Down
10 changes: 5 additions & 5 deletions src/listeners/__tests__/node.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const processOnSpy = jest.spyOn(process, 'on');
const processRemoveListenerSpy = jest.spyOn(process, 'removeListener');
const processKillSpy = jest.spyOn(process, 'kill').mockImplementation(() => true);

test('Node JS listener / Signal Listener class methods and start/stop functionality', () => {
test('NodeSignalListener / Signal Listener class methods and start/stop functionality', () => {

const syncManagerMock = { flush: jest.fn() }; // @ts-expect-error
const listener = new NodeSignalListener(syncManagerMock, fullSettings);
Expand All @@ -25,7 +25,7 @@ test('Node JS listener / Signal Listener class methods and start/stop functional
expect(processRemoveListenerSpy.mock.calls).toEqual([['SIGTERM', listener._sigtermHandler]]);
});

test('Node JS listener / Signal Listener SIGTERM callback with sync handler', () => {
test('NodeSignalListener / Signal Listener SIGTERM callback with sync handler', () => {

const syncManagerMock = { flush: jest.fn() }; // @ts-expect-error
const listener = new NodeSignalListener(syncManagerMock, fullSettings);
Expand Down Expand Up @@ -55,7 +55,7 @@ test('Node JS listener / Signal Listener SIGTERM callback with sync handler', ()
processKillSpy.mockClear();
});

test('Node JS listener / Signal Listener SIGTERM callback with sync handler that throws an error', () => {
test('NodeSignalListener / Signal Listener SIGTERM callback with sync handler that throws an error', () => {
const syncManagerMock = { flush: jest.fn(() => { throw 'some error'; }) }; // @ts-expect-error
const listener = new NodeSignalListener(syncManagerMock, fullSettings);

Expand Down Expand Up @@ -85,7 +85,7 @@ test('Node JS listener / Signal Listener SIGTERM callback with sync handler that
processKillSpy.mockClear();
});

test('Node JS listener / Signal Listener SIGTERM callback with async handler', async () => {
test('NodeSignalListener / Signal Listener SIGTERM callback with async handler', async () => {

const fakePromise = new Promise<void>(res => {
setTimeout(() => {
Expand Down Expand Up @@ -125,7 +125,7 @@ test('Node JS listener / Signal Listener SIGTERM callback with async handler', a
});
});

test('Node JS listener / Signal Listener SIGTERM callback with async handler that throws an error', async () => {
test('NodeSignalListener / Signal Listener SIGTERM callback with async handler that throws an error', async () => {

const fakePromise = new Promise<void>((res, rej) => {
setTimeout(() => {
Expand Down
4 changes: 2 additions & 2 deletions src/listeners/node.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// @TODO eventually migrate to JS-Node-SDK package.
// @TODO eventually migrate to Node.js SDK package.
import { ISignalListener } from './types';
import { thenable } from '../utils/promise/thenable';
import { MaybeThenable } from '../dtos/types';
Expand All @@ -25,7 +25,7 @@ export class NodeSignalListener implements ISignalListener {
syncManager: ISyncManager | undefined, // private handler: () => MaybeThenable<void>,
settings: ISettings
) {
// @TODO review handler logic when implementing Node SDK
// @TODO review handler logic when implementing Node.js SDK
this.handler = function () {
if (syncManager) {
// syncManager.stop();
Expand Down
10 changes: 3 additions & 7 deletions src/sdkClient/sdkClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,18 @@ export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: bo
// Mark the SDK as destroyed immediately
sdkReadinessManager.readinessManager.destroy();

// For main client, release the SDK Key and record stat before flushing data
// For main client, cleanup the SDK Key, listeners and scheduled jobs, and record stat before flushing data
if (!isSharedClient) {
releaseApiKey(settings.core.authorizationKey);
telemetryTracker.sessionLength();
signalListener && signalListener.stop();
uniqueKeysTracker && uniqueKeysTracker.stop();
}

// Stop background jobs
syncManager && syncManager.stop();

return __flush().then(() => {
// For main client, cleanup event listeners and scheduled jobs
if (!isSharedClient) {
signalListener && signalListener.stop();
uniqueKeysTracker && uniqueKeysTracker.stop();
}

// Cleanup storage
return storage.destroy();
});
Expand Down
4 changes: 2 additions & 2 deletions src/sdkFactory/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface IPlatform {
*/
getEventSource?: (settings: ISettings) => (IEventSourceConstructor | undefined)
/**
* EventEmitter constructor, like NodeJS.EventEmitter or a polyfill.
* EventEmitter constructor, like Node.js EventEmitter or a polyfill.
*/
EventEmitter: new () => SplitIO.IEventEmitter,
/**
Expand Down Expand Up @@ -104,7 +104,7 @@ export interface ISdkFactoryParams {
filterAdapterFactory?: () => IFilterAdapter

// Optional signal listener constructor. Used to handle special app states, like shutdown, app paused or resumed.
// Pass only if `syncManager` (used by Node listener) and `splitApi` (used by Browser listener) are passed.
// Pass only if `syncManager` (used by NodeSignalListener) and `splitApi` (used by Browser listener) are passed.
SignalListener?: new (
syncManager: ISyncManager | undefined, // Used by NodeSignalListener to flush data, and by BrowserSignalListener to close streaming connection.
settings: ISettings, // Used by BrowserSignalListener
Expand Down
2 changes: 1 addition & 1 deletion src/storages/AbstractMySegmentsCacheSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export abstract class AbstractMySegmentsCacheSync implements ISegmentsCacheSync
// @TODO for client-side it should be the number of clients, but it requires a refactor of MySegments caches to simplify the code.
abstract getKeysCount(): number

abstract getChangeNumber(name: string): number
abstract getChangeNumber(): number

/**
* For server-side synchronizer: the method is not used.
Expand Down
2 changes: 1 addition & 1 deletion src/storages/inMemory/SegmentsCacheInMemory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class SegmentsCacheInMemory implements ISegmentsCacheSync {
getChangeNumber(name: string) {
const value = this.segmentChangeNumber[name];

return isIntegerNumber(value) ? value : -1;
return isIntegerNumber(value) ? value : undefined;
}

// No-op. Not used in server-side
Expand Down
4 changes: 2 additions & 2 deletions src/storages/inRedis/SegmentsCacheInRedis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ export class SegmentsCacheInRedis implements ISegmentsCacheAsync {
return this.redis.get(this.keys.buildSegmentTillKey(name)).then((value: string | null) => {
const i = parseInt(value as string, 10);

return isNaNNumber(i) ? -1 : i;
return isNaNNumber(i) ? undefined : i;
}).catch((e) => {
this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e);
return -1;
return undefined;
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/storages/inRedis/SplitsCacheInRedis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function processPipelineAnswer(results: Array<[Error | null, string]>): string[]

/**
* ISplitsCacheAsync implementation that stores split definitions in Redis.
* Supported by Node.
* Supported by Node.js
*/
export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('SEGMENTS CACHE IN REDIS', () => {

expect(await cache.getChangeNumber('mocked-segment') === 1).toBe(true);

expect(await cache.getChangeNumber('inexistent-segment')).toBe(-1); // -1 if the segment doesn't exist
expect(await cache.getChangeNumber('inexistent-segment')).toBe(undefined); // -1 if the segment doesn't exist

await cache.update('mocked-segment', ['d', 'e'], [], 2);

Expand Down
2 changes: 1 addition & 1 deletion src/storages/inRedis/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface InRedisStorageOptions {
}

/**
* InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.
* InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.js
* @see {@link https://www.npmjs.com/package/ioredis}
*/
export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsyncFactory {
Expand Down
4 changes: 2 additions & 2 deletions src/storages/pluggable/SegmentsCachePluggable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ export class SegmentsCachePluggable implements ISegmentsCacheAsync {
return this.wrapper.get(this.keys.buildSegmentTillKey(name)).then((value: string | null) => {
const i = parseInt(value as string, 10);

return isNaNNumber(i) ? -1 : i;
return isNaNNumber(i) ? undefined : i;
}).catch((e) => {
this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e);
return -1;
return undefined;
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('SEGMENTS CACHE PLUGGABLE', () => {

expect(await cache.getChangeNumber('mocked-segment') === 1).toBe(true);

expect(await cache.getChangeNumber('inexistent-segment')).toBe(-1); // -1 if the segment doesn't exist
expect(await cache.getChangeNumber('inexistent-segment')).toBe(undefined); // -1 if the segment doesn't exist

await cache.update('mocked-segment', ['d', 'e'], [], 2);

Expand Down
6 changes: 3 additions & 3 deletions src/storages/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ export interface ISegmentsCacheBase {
isInSegment(name: string, key?: string): MaybeThenable<boolean> // different signature on Server and Client-Side
registerSegments(names: string[]): MaybeThenable<boolean | void> // only for Server-Side
getRegisteredSegments(): MaybeThenable<string[]> // only for Server-Side
getChangeNumber(name: string): MaybeThenable<number> // only for Server-Side
getChangeNumber(name: string): MaybeThenable<number | undefined> // only for Server-Side
update(name: string, addedKeys: string[], removedKeys: string[], changeNumber: number): MaybeThenable<boolean> // only for Server-Side
clear(): MaybeThenable<boolean | void>
}
Expand All @@ -248,7 +248,7 @@ export interface ISegmentsCacheSync extends ISegmentsCacheBase {
registerSegments(names: string[]): boolean
getRegisteredSegments(): string[]
getKeysCount(): number // only used for telemetry
getChangeNumber(name?: string): number
getChangeNumber(name?: string): number | undefined
update(name: string, addedKeys: string[], removedKeys: string[], changeNumber: number): boolean // only for Server-Side
resetSegments(segmentsData: MySegmentsData | IMySegmentsResponse): boolean // only for Sync Client-Side
clear(): void
Expand All @@ -258,7 +258,7 @@ export interface ISegmentsCacheAsync extends ISegmentsCacheBase {
isInSegment(name: string, key: string): Promise<boolean>
registerSegments(names: string[]): Promise<boolean | void>
getRegisteredSegments(): Promise<string[]>
getChangeNumber(name: string): Promise<number>
getChangeNumber(name: string): Promise<number | undefined>
update(name: string, addedKeys: string[], removedKeys: string[], changeNumber: number): Promise<boolean>
clear(): Promise<boolean | void>
}
Expand Down
4 changes: 2 additions & 2 deletions src/sync/polling/updaters/segmentChangesUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ export function segmentChangesUpdaterFactory(

return sincePromise.then(since => {
// if fetchOnlyNew flag, avoid processing already fetched segments
return fetchOnlyNew && since !== -1 ?
return fetchOnlyNew && since !== undefined ?
false :
segmentChangesFetcher(since, segmentName, noCache, till).then((changes) => {
segmentChangesFetcher(since || -1, segmentName, noCache, till).then((changes) => {
return Promise.all(changes.map(x => {
log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processing ${segmentName} with till = ${x.till}. Added: ${x.added.length}. Removed: ${x.removed.length}`);
return segments.update(segmentName, x.added, x.removed, x.till);
Expand Down
2 changes: 1 addition & 1 deletion src/sync/polling/updaters/splitChangesUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
let registeredSegments = Promise.resolve(segments.getRegisteredSegments());
return registeredSegments.then(segmentNames => {
return Promise.all(segmentNames.map(segmentName => segments.getChangeNumber(segmentName)))
.then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== -1));
.then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== undefined));
});
}

Expand Down
Loading