From 1b81254d8c57d9b676603f316b2d4eb3d120a595 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 22 Nov 2021 17:51:17 -0300 Subject: [PATCH 1/5] renamed CustomStorage to PluggableStorage --- package-lock.json | 2 +- package.json | 2 +- src/sdkFactory/index.ts | 2 +- src/storages/pluggable/EventsCachePluggable.ts | 6 +++--- src/storages/pluggable/ImpressionsCachePluggable.ts | 6 +++--- src/storages/pluggable/SegmentsCachePluggable.ts | 6 +++--- src/storages/pluggable/SplitsCachePluggable.ts | 8 ++++---- src/storages/pluggable/__tests__/index.spec.ts | 2 +- src/storages/pluggable/__tests__/wrapper.mock.ts | 2 +- src/storages/pluggable/inMemoryWrapper.ts | 6 +++--- src/storages/pluggable/index.ts | 12 ++++++------ src/storages/pluggable/wrapperAdapter.ts | 8 ++++---- src/storages/types.ts | 8 ++++---- src/sync/polling/updaters/mySegmentsUpdater.ts | 2 +- .../streaming/UpdateWorkers/SplitsUpdateWorker.ts | 1 - src/utils/constants/index.ts | 2 +- .../storage/__tests__/storageCS.spec.ts | 12 ++++++------ src/utils/settingsValidation/storage/storageCS.ts | 8 ++++---- 18 files changed, 47 insertions(+), 48 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7f35f186..da27bd8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "1.0.1-rc.1", + "version": "1.0.1-rc.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 75501e66..921c8745 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "1.0.1-rc.1", + "version": "1.0.1-rc.2", "description": "Split Javascript SDK common components", "main": "cjs/index.js", "module": "esm/index.js", diff --git a/src/sdkFactory/index.ts b/src/sdkFactory/index.ts index 136cc064..2d2b89cd 100644 --- a/src/sdkFactory/index.ts +++ b/src/sdkFactory/index.ts @@ -40,7 +40,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO. matchingKey: getMatching(settings.core.key), splitFiltersValidation: settings.sync.__splitFiltersValidation, - // ATM, only used by CustomStorage + // ATM, only used by PluggableStorage mode: settings.mode, // Callback used to emit SDK_READY in consumer mode, where `syncManagerFactory` is undefined diff --git a/src/storages/pluggable/EventsCachePluggable.ts b/src/storages/pluggable/EventsCachePluggable.ts index ff0b19dc..d30d43b7 100644 --- a/src/storages/pluggable/EventsCachePluggable.ts +++ b/src/storages/pluggable/EventsCachePluggable.ts @@ -1,4 +1,4 @@ -import { ICustomStorageWrapper, IEventsCacheAsync } from '../types'; +import { IPluggableStorageWrapper, IEventsCacheAsync } from '../types'; import { IMetadata } from '../../dtos/types'; import { SplitIO } from '../../types'; import { ILogger } from '../../logger/types'; @@ -8,11 +8,11 @@ import { StoredEventWithMetadata } from '../../sync/submitters/types'; export class EventsCachePluggable implements IEventsCacheAsync { private readonly log: ILogger; - private readonly wrapper: ICustomStorageWrapper; + private readonly wrapper: IPluggableStorageWrapper; private readonly key: string; private readonly metadata: IMetadata; - constructor(log: ILogger, key: string, wrapper: ICustomStorageWrapper, metadata: IMetadata) { + constructor(log: ILogger, key: string, wrapper: IPluggableStorageWrapper, metadata: IMetadata) { this.log = log; this.key = key; this.wrapper = wrapper; diff --git a/src/storages/pluggable/ImpressionsCachePluggable.ts b/src/storages/pluggable/ImpressionsCachePluggable.ts index debe30ed..4de3e33e 100644 --- a/src/storages/pluggable/ImpressionsCachePluggable.ts +++ b/src/storages/pluggable/ImpressionsCachePluggable.ts @@ -1,4 +1,4 @@ -import { ICustomStorageWrapper, IImpressionsCacheAsync } from '../types'; +import { IPluggableStorageWrapper, IImpressionsCacheAsync } from '../types'; import { IMetadata } from '../../dtos/types'; import { ImpressionDTO } from '../../types'; import { ILogger } from '../../logger/types'; @@ -8,10 +8,10 @@ export class ImpressionsCachePluggable implements IImpressionsCacheAsync { private readonly log: ILogger; private readonly key: string; - private readonly wrapper: ICustomStorageWrapper; + private readonly wrapper: IPluggableStorageWrapper; private readonly metadata: IMetadata; - constructor(log: ILogger, key: string, wrapper: ICustomStorageWrapper, metadata: IMetadata) { + constructor(log: ILogger, key: string, wrapper: IPluggableStorageWrapper, metadata: IMetadata) { this.log = log; this.key = key; this.wrapper = wrapper; diff --git a/src/storages/pluggable/SegmentsCachePluggable.ts b/src/storages/pluggable/SegmentsCachePluggable.ts index ec4c3fc3..7b19633a 100644 --- a/src/storages/pluggable/SegmentsCachePluggable.ts +++ b/src/storages/pluggable/SegmentsCachePluggable.ts @@ -2,7 +2,7 @@ /* eslint-disable no-unused-vars */ import { isNaNNumber } from '../../utils/lang'; import KeyBuilderSS from '../KeyBuilderSS'; -import { ICustomStorageWrapper, ISegmentsCacheAsync } from '../types'; +import { IPluggableStorageWrapper, ISegmentsCacheAsync } from '../types'; import { ILogger } from '../../logger/types'; import { LOG_PREFIX } from './constants'; import { _Set } from '../../utils/lang/sets'; @@ -14,9 +14,9 @@ export class SegmentsCachePluggable implements ISegmentsCacheAsync { private readonly log: ILogger; private readonly keys: KeyBuilderSS; - private readonly wrapper: ICustomStorageWrapper; + private readonly wrapper: IPluggableStorageWrapper; - constructor(log: ILogger, keys: KeyBuilderSS, wrapper: ICustomStorageWrapper) { + constructor(log: ILogger, keys: KeyBuilderSS, wrapper: IPluggableStorageWrapper) { this.log = log; this.keys = keys; this.wrapper = wrapper; diff --git a/src/storages/pluggable/SplitsCachePluggable.ts b/src/storages/pluggable/SplitsCachePluggable.ts index e4e29ce4..95bbcc0e 100644 --- a/src/storages/pluggable/SplitsCachePluggable.ts +++ b/src/storages/pluggable/SplitsCachePluggable.ts @@ -1,6 +1,6 @@ import { isFiniteNumber, isNaNNumber } from '../../utils/lang'; import KeyBuilder from '../KeyBuilder'; -import { ICustomStorageWrapper } from '../types'; +import { IPluggableStorageWrapper } from '../types'; import { ILogger } from '../../logger/types'; import { ISplit } from '../../dtos/types'; import { LOG_PREFIX } from './constants'; @@ -13,15 +13,15 @@ export class SplitsCachePluggable extends AbstractSplitsCacheAsync { private readonly log: ILogger; private readonly keys: KeyBuilder; - private readonly wrapper: ICustomStorageWrapper; + private readonly wrapper: IPluggableStorageWrapper; /** - * Create a SplitsCache that uses a custom storage wrapper. + * Create a SplitsCache that uses a storage wrapper. * @param log Logger instance. * @param keys Key builder. * @param wrapper Adapted wrapper storage. */ - constructor(log: ILogger, keys: KeyBuilder, wrapper: ICustomStorageWrapper) { + constructor(log: ILogger, keys: KeyBuilder, wrapper: IPluggableStorageWrapper) { super(); this.log = log; this.keys = keys; diff --git a/src/storages/pluggable/__tests__/index.spec.ts b/src/storages/pluggable/__tests__/index.spec.ts index 34a95fca..6f37f4f1 100644 --- a/src/storages/pluggable/__tests__/index.spec.ts +++ b/src/storages/pluggable/__tests__/index.spec.ts @@ -57,7 +57,7 @@ describe('PLUGGABLE STORAGE', () => { expect(() => PluggableStorage({ wrapper: wrapperMock })).not.toThrow(); // not prefix but valid wrapper is OK // Throws exception if no object is passed as wrapper - const errorNoValidWrapper = 'Expecting custom storage `wrapper` in options, but no valid wrapper instance was provided.'; + const errorNoValidWrapper = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.'; expect(() => PluggableStorage()).toThrow(errorNoValidWrapper); expect(() => PluggableStorage({ wrapper: undefined })).toThrow(errorNoValidWrapper); expect(() => PluggableStorage({ wrapper: 'invalid wrapper' })).toThrow(errorNoValidWrapper); diff --git a/src/storages/pluggable/__tests__/wrapper.mock.ts b/src/storages/pluggable/__tests__/wrapper.mock.ts index 3301ef5c..594ecbcf 100644 --- a/src/storages/pluggable/__tests__/wrapper.mock.ts +++ b/src/storages/pluggable/__tests__/wrapper.mock.ts @@ -1,6 +1,6 @@ import { startsWith, toNumber } from '../../../utils/lang'; -// Creates an in memory ICustomStorageWrapper implementation with Jest mocks +// Creates an in memory IPluggableStorageWrapper implementation with Jest mocks export function wrapperMockFactory() { /** Holds items and list of items */ diff --git a/src/storages/pluggable/inMemoryWrapper.ts b/src/storages/pluggable/inMemoryWrapper.ts index 3f050a16..cb3a77e8 100644 --- a/src/storages/pluggable/inMemoryWrapper.ts +++ b/src/storages/pluggable/inMemoryWrapper.ts @@ -1,15 +1,15 @@ -import { ICustomStorageWrapper } from '../types'; +import { IPluggableStorageWrapper } from '../types'; import { startsWith, toNumber } from '../../utils/lang'; import { ISet, setToArray, _Set } from '../../utils/lang/sets'; /** - * Creates a ICustomStorageWrapper implementation that stores items in memory. + * Creates a IPluggableStorageWrapper implementation that stores items in memory. * The `_cache` property is the object were items are stored. * Intended for testing purposes. * * @param connDelay delay in millis for `connect` resolve. If not provided, `connect` resolves inmediatelly. */ -export function inMemoryWrapperFactory(connDelay?: number): ICustomStorageWrapper & { _cache: Record>, _setConnDelay(connDelay: number): void } { +export function inMemoryWrapperFactory(connDelay?: number): IPluggableStorageWrapper & { _cache: Record>, _setConnDelay(connDelay: number): void } { let _cache: Record> = {}; let _connDelay = connDelay; diff --git a/src/storages/pluggable/index.ts b/src/storages/pluggable/index.ts index f0d202f1..9dd9f592 100644 --- a/src/storages/pluggable/index.ts +++ b/src/storages/pluggable/index.ts @@ -1,4 +1,4 @@ -import { ICustomStorageWrapper, IStorageAsync, IStorageAsyncFactory, IStorageFactoryParams } from '../types'; +import { IPluggableStorageWrapper, IStorageAsync, IStorageAsyncFactory, IStorageFactoryParams } from '../types'; import KeyBuilderSS from '../KeyBuilderSS'; import { SplitsCachePluggable } from './SplitsCachePluggable'; @@ -8,17 +8,17 @@ import { EventsCachePluggable } from './EventsCachePluggable'; import { wrapperAdapter, METHODS_TO_PROMISE_WRAP } from './wrapperAdapter'; import { isObject } from '../../utils/lang'; import { validatePrefix } from '../KeyBuilder'; -import { CONSUMER_PARTIAL_MODE, STORAGE_CUSTOM } from '../../utils/constants'; +import { CONSUMER_PARTIAL_MODE, STORAGE_PLUGGABLE } from '../../utils/constants'; import ImpressionsCacheInMemory from '../inMemory/ImpressionsCacheInMemory'; import EventsCacheInMemory from '../inMemory/EventsCacheInMemory'; import ImpressionCountsCacheInMemory from '../inMemory/ImpressionCountsCacheInMemory'; -const NO_VALID_WRAPPER = 'Expecting custom storage `wrapper` in options, but no valid wrapper instance was provided.'; +const NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.'; const NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.'; export interface PluggableStorageOptions { prefix?: string - wrapper: ICustomStorageWrapper + wrapper: IPluggableStorageWrapper } /** @@ -36,7 +36,7 @@ function validatePluggableStorageOptions(options: any) { } // subscription to wrapper connect event in order to emit SDK_READY event -function wrapperConnect(wrapper: ICustomStorageWrapper, onReadyCb: (error?: any) => void) { +function wrapperConnect(wrapper: IPluggableStorageWrapper, onReadyCb: (error?: any) => void) { wrapper.connect().then(() => { onReadyCb(); }).catch((e) => { @@ -96,6 +96,6 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn }; } - PluggableStorageFactory.type = STORAGE_CUSTOM; + PluggableStorageFactory.type = STORAGE_PLUGGABLE; return PluggableStorageFactory; } diff --git a/src/storages/pluggable/wrapperAdapter.ts b/src/storages/pluggable/wrapperAdapter.ts index 3b530d21..c47a5d8b 100644 --- a/src/storages/pluggable/wrapperAdapter.ts +++ b/src/storages/pluggable/wrapperAdapter.ts @@ -1,5 +1,5 @@ import { ILogger } from '../../logger/types'; -import { ICustomStorageWrapper } from '../types'; +import { IPluggableStorageWrapper } from '../types'; import { LOG_PREFIX } from './constants'; export const METHODS_TO_PROMISE_WRAP: string[] = [ @@ -23,14 +23,14 @@ export const METHODS_TO_PROMISE_WRAP: string[] = [ ]; /** - * Adapter of the Custom Storage Wrapper. + * Adapter of the Pluggable Storage Wrapper. * Used to handle exceptions as rejected promises, in order to simplify the error handling on storages. * * @param log logger instance - * @param wrapper custom storage wrapper to adapt + * @param wrapper storage wrapper to adapt * @returns an adapted version of the given storage wrapper */ -export function wrapperAdapter(log: ILogger, wrapper: ICustomStorageWrapper): ICustomStorageWrapper { +export function wrapperAdapter(log: ILogger, wrapper: IPluggableStorageWrapper): IPluggableStorageWrapper { const wrapperAdapter: Record = {}; diff --git a/src/storages/types.ts b/src/storages/types.ts index bbd1c2c7..5ce0d1e9 100644 --- a/src/storages/types.ts +++ b/src/storages/types.ts @@ -4,9 +4,9 @@ import { StoredEventWithMetadata, StoredImpressionWithMetadata } from '../sync/s import { SplitIO, ImpressionDTO, SDKMode } from '../types'; /** - * Interface of a custom storage wrapper. + * Interface of a pluggable storage wrapper. */ -export interface ICustomStorageWrapper { +export interface IPluggableStorageWrapper { /** Key-Value operations */ @@ -430,7 +430,7 @@ export interface IStorageFactoryParams { matchingKey?: string, /* undefined on server-side SDKs */ splitFiltersValidation?: ISplitFiltersValidation, - // ATM, only used by CustomStorage + // ATM, only used by PluggableStorage mode?: SDKMode, // This callback is invoked when the storage is ready to be used. Error-first callback style: if an error is passed, @@ -440,7 +440,7 @@ export interface IStorageFactoryParams { metadata: IMetadata, } -export type StorageType = 'MEMORY' | 'LOCALSTORAGE' | 'REDIS' | 'CUSTOM'; +export type StorageType = 'MEMORY' | 'LOCALSTORAGE' | 'REDIS' | 'PLUGGABLE'; export type IStorageSyncFactory = { type: StorageType, diff --git a/src/sync/polling/updaters/mySegmentsUpdater.ts b/src/sync/polling/updaters/mySegmentsUpdater.ts index 4ceb4ab3..17a5b762 100644 --- a/src/sync/polling/updaters/mySegmentsUpdater.ts +++ b/src/sync/polling/updaters/mySegmentsUpdater.ts @@ -38,7 +38,7 @@ export function mySegmentsUpdaterFactory( // mySegmentsPromise = tracker.start(tracker.TaskNames.MY_SEGMENTS_FETCH, startingUp ? metricCollectors : false, mySegmentsPromise); } - // @TODO if allowing custom storages, handle async execution + // @TODO if allowing pluggable storages, handle async execution function updateSegments(segmentsData: SegmentsData) { let shouldNotifyUpdate; diff --git a/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts b/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts index 944d5776..8542d0a9 100644 --- a/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +++ b/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts @@ -83,7 +83,6 @@ export default class SplitsUpdateWorker implements IUpdateWorker { * @param {string} defaultTreatment default treatment value */ killSplit({ changeNumber, splitName, defaultTreatment }: ISplitKillData) { - // @TODO handle retry due to errors in storage, once we allow the definition of custom async storages if (this.splitsCache.killLocally(splitName, defaultTreatment, changeNumber)) { // trigger an SDK_UPDATE if Split was killed locally this.splitsEventEmitter.emit(SDK_SPLITS_ARRIVED, true); diff --git a/src/utils/constants/index.ts b/src/utils/constants/index.ts index e632938f..4a4d8303 100644 --- a/src/utils/constants/index.ts +++ b/src/utils/constants/index.ts @@ -31,4 +31,4 @@ export const CONSUMER_PARTIAL_MODE: SDKMode = 'consumer_partial'; export const STORAGE_MEMORY: StorageType = 'MEMORY'; export const STORAGE_LOCALSTORAGE: StorageType = 'LOCALSTORAGE'; export const STORAGE_REDIS: StorageType = 'REDIS'; -export const STORAGE_CUSTOM: StorageType = 'CUSTOM'; +export const STORAGE_PLUGGABLE: StorageType = 'PLUGGABLE'; diff --git a/src/utils/settingsValidation/storage/__tests__/storageCS.spec.ts b/src/utils/settingsValidation/storage/__tests__/storageCS.spec.ts index 6d270946..5bd7c389 100644 --- a/src/utils/settingsValidation/storage/__tests__/storageCS.spec.ts +++ b/src/utils/settingsValidation/storage/__tests__/storageCS.spec.ts @@ -5,8 +5,8 @@ import { loggerMock as log } from '../../../../logger/__tests__/sdkLogger.mock'; const mockInLocalStorageFactory = () => { }; mockInLocalStorageFactory.type = 'LOCALSTORAGE'; -const mockCustomStorageFactory = () => { }; -mockCustomStorageFactory.type = 'CUSTOM'; +const mockPluggableStorageFactory = () => { }; +mockPluggableStorageFactory.type = 'PLUGGABLE'; describe('storage validator for pluggable storage (client-side)', () => { @@ -38,13 +38,13 @@ describe('storage validator for pluggable storage (client-side)', () => { }); test('throws error if the provided storage factory is not compatible with the mode', () => { - expect(() => { validateStorageCS({ log, mode: 'consumer', storage: mockInLocalStorageFactory }); }).toThrow('A CustomStorage instance is required on consumer mode'); - expect(() => { validateStorageCS({ log, mode: 'consumer_partial', storage: mockInLocalStorageFactory }); }).toThrow('A CustomStorage instance is required on consumer mode'); + expect(() => { validateStorageCS({ log, mode: 'consumer', storage: mockInLocalStorageFactory }); }).toThrow('A PluggableStorage instance is required on consumer mode'); + expect(() => { validateStorageCS({ log, mode: 'consumer_partial', storage: mockInLocalStorageFactory }); }).toThrow('A PluggableStorage instance is required on consumer mode'); expect(log.error).not.toBeCalled(); - expect(validateStorageCS({ log, mode: 'standalone', storage: mockCustomStorageFactory })).toBe(InMemoryStorageCSFactory); - expect(validateStorageCS({ log, mode: 'localhost', storage: mockCustomStorageFactory })).toBe(InMemoryStorageCSFactory); + expect(validateStorageCS({ log, mode: 'standalone', storage: mockPluggableStorageFactory })).toBe(InMemoryStorageCSFactory); + expect(validateStorageCS({ log, mode: 'localhost', storage: mockPluggableStorageFactory })).toBe(InMemoryStorageCSFactory); expect(log.error).toBeCalledTimes(2); }); diff --git a/src/utils/settingsValidation/storage/storageCS.ts b/src/utils/settingsValidation/storage/storageCS.ts index 3dadb31a..097ce95d 100644 --- a/src/utils/settingsValidation/storage/storageCS.ts +++ b/src/utils/settingsValidation/storage/storageCS.ts @@ -2,7 +2,7 @@ import { InMemoryStorageCSFactory } from '../../../storages/inMemory/InMemorySto import { ISettings, SDKMode } from '../../../types'; import { ILogger } from '../../../logger/types'; import { ERROR_STORAGE_INVALID } from '../../../logger/constants'; -import { LOCALHOST_MODE, STANDALONE_MODE, STORAGE_CUSTOM, STORAGE_LOCALSTORAGE, STORAGE_MEMORY } from '../../../utils/constants'; +import { LOCALHOST_MODE, STANDALONE_MODE, STORAGE_PLUGGABLE, STORAGE_LOCALSTORAGE, STORAGE_MEMORY } from '../../../utils/constants'; import { IStorageFactoryParams, IStorageSync } from '../../../storages/types'; export function __InLocalStorageMockFactory(params: IStorageFactoryParams): IStorageSync { @@ -25,7 +25,7 @@ export function validateStorageCS(settings: { log: ILogger, storage?: any, mode: let { storage = InMemoryStorageCSFactory, log, mode } = settings; // If an invalid storage is provided, fallback into MEMORY - if (typeof storage !== 'function' || [STORAGE_MEMORY, STORAGE_LOCALSTORAGE, STORAGE_CUSTOM].indexOf(storage.type) === -1) { + if (typeof storage !== 'function' || [STORAGE_MEMORY, STORAGE_LOCALSTORAGE, STORAGE_PLUGGABLE].indexOf(storage.type) === -1) { storage = InMemoryStorageCSFactory; log.error(ERROR_STORAGE_INVALID); } @@ -37,10 +37,10 @@ export function validateStorageCS(settings: { log: ILogger, storage?: any, mode: if ([LOCALHOST_MODE, STANDALONE_MODE].indexOf(mode) === -1) { // Consumer modes require an async storage - if (storage.type !== STORAGE_CUSTOM) throw new Error('A CustomStorage instance is required on consumer mode'); + if (storage.type !== STORAGE_PLUGGABLE) throw new Error('A PluggableStorage instance is required on consumer mode'); } else { // Standalone and localhost modes require a sync storage - if (storage.type === STORAGE_CUSTOM) { + if (storage.type === STORAGE_PLUGGABLE) { storage = InMemoryStorageCSFactory; log.error(ERROR_STORAGE_INVALID, [' It requires consumer mode.']); } From f68fe6b49c576940207db6733919e5ec85b10ab8 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 1 Dec 2021 15:27:48 -0300 Subject: [PATCH 2/5] upgraded ioredis for vulnerability fix --- package-lock.json | 25 ++++++++++++++++--------- package.json | 4 ++-- src/utils/env/isNode.ts | 5 ++++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index da27bd8c..c0eb61f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1053,9 +1053,9 @@ } }, "@types/ioredis": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.17.4.tgz", - "integrity": "sha512-kb5+thmQJ7HHyOAnCOeqRJlF2fyvadHghnLLLKZzCNyShStJeIQtNGGDjA30gWqj6UFSDAWBfGEMKrFDrGfvzQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.1.tgz", + "integrity": "sha512-raYHPqRWrfnEoym94BY28mG1+tcZqh3dsp2q7x5IyMAAEvIdu+H0X8diASMpncIm+oHyH9dalOeOnGOL/YnuOA==", "dev": true, "requires": { "@types/node": "*" @@ -1967,9 +1967,9 @@ "dev": true }, "denque": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", - "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", "dev": true }, "detect-newline": { @@ -2894,9 +2894,9 @@ "dev": true }, "ioredis": { - "version": "4.27.2", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.27.2.tgz", - "integrity": "sha512-7OpYymIthonkC2Jne5uGWXswdhlua1S1rWGAERaotn0hGJWTSURvxdHA9G6wNbT/qKCloCja/FHsfKXW8lpTmg==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.2.tgz", + "integrity": "sha512-kQ+Iv7+c6HsDdPP2XUHaMv8DhnSeAeKEwMbaoqsXYbO+03dItXt7+5jGQDRyjdRUV2rFJbzg7P4Qt1iX2tqkOg==", "dev": true, "requires": { "cluster-key-slot": "^1.1.0", @@ -2904,6 +2904,7 @@ "denque": "^1.1.0", "lodash.defaults": "^4.2.0", "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", "p-map": "^2.1.0", "redis-commands": "1.7.0", "redis-errors": "^1.2.0", @@ -4480,6 +4481,12 @@ "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", "dev": true }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", diff --git a/package.json b/package.json index 921c8745..4fcd3c70 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ }, "devDependencies": { "@types/google.analytics": "0.0.40", - "@types/ioredis": "^4.14.1", + "@types/ioredis": "^4.28.0", "@types/jest": "^27.0.0", "@types/lodash": "^4.14.162", "@types/node": "^14.14.7", @@ -61,7 +61,7 @@ "eslint": "^7.32.0", "eslint-plugin-compat": "3.7.0", "fetch-mock": "^9.10.7", - "ioredis": "^4.26.0", + "ioredis": "^4.28.0", "jest": "^27.2.3", "jest-localstorage-mock": "^2.4.3", "js-yaml": "^3.14.0", diff --git a/src/utils/env/isNode.ts b/src/utils/env/isNode.ts index f189c5b6..64c6200a 100644 --- a/src/utils/env/isNode.ts +++ b/src/utils/env/isNode.ts @@ -1,3 +1,6 @@ -// We check for version truthiness since most shims will have that as empty string. // eslint-disable-next-line no-undef +/** + * 'true' if running in Node.js, or 'false' otherwise. + * We check for version truthiness since most shims will have that as empty string. + */ export const isNode: boolean = typeof process !== 'undefined' && typeof process.version !== 'undefined' && !!process.version ? true : false; From 4ada05afb3eb39858ed419dbdcdb8f767a6f014a Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 2 Dec 2021 16:55:47 -0300 Subject: [PATCH 3/5] removed NodeJS types --- .eslintrc | 1 - package.json | 1 - src/storages/pluggable/constants.ts | 2 +- src/types.ts | 17 +++++++++-------- src/utils/MinEventEmitter.ts | 20 ++++++++++---------- src/utils/env/isNode.ts | 2 +- 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/.eslintrc b/.eslintrc index 94782cad..fb21ecc8 100644 --- a/.eslintrc +++ b/.eslintrc @@ -18,7 +18,6 @@ "EventSource": "readonly", // @TODO remove. Configure as a type declaration "MessageEvent": "readonly", // @TODO remove. Configure as a type declaration "Event": "readonly", // @TODO remove. Configure as a type declaration - "NodeJS": "readonly", "UniversalAnalytics": "readonly" // @TODO remove when moving GA integrations to Browser-SDK }, diff --git a/package.json b/package.json index 4fcd3c70..b6fa3516 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,6 @@ "@types/ioredis": "^4.28.0", "@types/jest": "^27.0.0", "@types/lodash": "^4.14.162", - "@types/node": "^14.14.7", "@types/object-assign": "^4.0.30", "@typescript-eslint/eslint-plugin": "^4.2.0", "@typescript-eslint/parser": "^4.2.0", diff --git a/src/storages/pluggable/constants.ts b/src/storages/pluggable/constants.ts index 1f845f45..f28d60b8 100644 --- a/src/storages/pluggable/constants.ts +++ b/src/storages/pluggable/constants.ts @@ -1 +1 @@ -export const LOG_PREFIX = 'storage:pluggable:'; +export const LOG_PREFIX = 'storage:pluggable: '; diff --git a/src/types.ts b/src/types.ts index c7fbc62b..d4351696 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,15 +7,16 @@ import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory import { ISyncManagerFactoryParams, ISyncManagerCS } from './sync/types'; /** - * EventEmitter interface with the minimal methods used by the SDK + * Reduced version of NodeJS.EventEmitter interface with the minimal methods used by the SDK + * @see {@link https://nodejs.org/api/events.html} */ -export interface IEventEmitter extends Pick { - addListener(event: string, listener: (...args: any[]) => void): any; - on(event: string, listener: (...args: any[]) => void): any - once(event: string, listener: (...args: any[]) => void): any - removeListener(event: string, listener: (...args: any[]) => void): any; - off(event: string, listener: (...args: any[]) => void): any; - removeAllListeners(event?: string): any +export interface IEventEmitter { + addListener(event: string, listener: (...args: any[]) => void): this; + on(event: string, listener: (...args: any[]) => void): this + once(event: string, listener: (...args: any[]) => void): this + removeListener(event: string, listener: (...args: any[]) => void): this; + off(event: string, listener: (...args: any[]) => void): this; + removeAllListeners(event?: string): this emit(event: string, ...args: any[]): boolean } diff --git a/src/utils/MinEventEmitter.ts b/src/utils/MinEventEmitter.ts index 2bddb0d6..1ff39d4e 100644 --- a/src/utils/MinEventEmitter.ts +++ b/src/utils/MinEventEmitter.ts @@ -18,7 +18,7 @@ export default class EventEmitter implements IEventEmitter { boolean // whether it is a one-time listener or not ]>> = {}; - private registerListener(type: string, listener: (...args: any[]) => void, oneTime: boolean): EventEmitter { + private registerListener(type: string, listener: (...args: any[]) => void, oneTime: boolean) { checkListener(listener); // To avoid recursion in the case that type === "newListener" before @@ -33,27 +33,27 @@ export default class EventEmitter implements IEventEmitter { return this; } - addListener(type: string, listener: (...args: any[]) => void): EventEmitter { + addListener(type: string, listener: (...args: any[]) => void) { return this.registerListener(type, listener, false); } // alias of addListener - on(type: string, listener: (...args: any[]) => void): EventEmitter { + on(type: string, listener: (...args: any[]) => void) { return this.addListener(type, listener); } - once(type: string, listener: (...args: any[]) => void): EventEmitter { + once(type: string, listener: (...args: any[]) => void) { return this.registerListener(type, listener, true); } - // eslint-disable-next-line - removeListener(type: string, listener: (...args: any[]) => void): EventEmitter { + // @ts-ignore + removeListener(/* type: string, listener: (...args: any[]) => void */) { throw new Error('Method not implemented.'); } - // alias of removeListener - off(type: string, listener: (...args: any[]) => void): EventEmitter { - return this.removeListener(type, listener); + // @ts-ignore alias of removeListener + off(/* type: string, listener: (...args: any[]) => void */) { + return this.removeListener(/* type, listener */); } emit(type: string, ...args: any[]): boolean { @@ -68,7 +68,7 @@ export default class EventEmitter implements IEventEmitter { return true; } - removeAllListeners(type?: string): EventEmitter { + removeAllListeners(type?: string) { if (!this.listeners[REMOVE_LISTENER_EVENT]) { // if not listening for `removeListener`, no need to emit if (type) { diff --git a/src/utils/env/isNode.ts b/src/utils/env/isNode.ts index 64c6200a..8c28623c 100644 --- a/src/utils/env/isNode.ts +++ b/src/utils/env/isNode.ts @@ -1,6 +1,6 @@ -// eslint-disable-next-line no-undef /** * 'true' if running in Node.js, or 'false' otherwise. * We check for version truthiness since most shims will have that as empty string. */ +// eslint-disable-next-line no-undef export const isNode: boolean = typeof process !== 'undefined' && typeof process.version !== 'undefined' && !!process.version ? true : false; From 4de6898e7dd83ecf79a3c523c455b14adcd71ccd Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 2 Dec 2021 16:57:51 -0300 Subject: [PATCH 4/5] removed EventSource DOM type --- .eslintrc | 1 - package-lock.json | 2 +- package.json | 2 +- src/sdkFactory/types.ts | 4 ++-- src/services/types.ts | 18 ++++++++++++++++-- src/sync/streaming/SSEClient/index.ts | 10 +++++----- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/.eslintrc b/.eslintrc index fb21ecc8..affa34c4 100644 --- a/.eslintrc +++ b/.eslintrc @@ -15,7 +15,6 @@ "globals": { // global TS types - "EventSource": "readonly", // @TODO remove. Configure as a type declaration "MessageEvent": "readonly", // @TODO remove. Configure as a type declaration "Event": "readonly", // @TODO remove. Configure as a type declaration "UniversalAnalytics": "readonly" // @TODO remove when moving GA integrations to Browser-SDK diff --git a/package-lock.json b/package-lock.json index c0eb61f5..b2c91c99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "1.0.1-rc.2", + "version": "1.0.1-rc.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b6fa3516..cf0cc5ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "1.0.1-rc.2", + "version": "1.0.1-rc.3", "description": "Split Javascript SDK common components", "main": "cjs/index.js", "module": "esm/index.js", diff --git a/src/sdkFactory/types.ts b/src/sdkFactory/types.ts index b0d87343..d907d2d0 100644 --- a/src/sdkFactory/types.ts +++ b/src/sdkFactory/types.ts @@ -3,7 +3,7 @@ import { ISignalListener } from '../listeners/types'; import { ILogger } from '../logger/types'; import { ISdkReadinessManager } from '../readiness/types'; import { ISdkClientFactoryParams } from '../sdkClient/types'; -import { IFetch, ISplitApi } from '../services/types'; +import { IFetch, ISplitApi, IEventSourceConstructor } from '../services/types'; import { IStorageAsync, IStorageSync, ISplitsCacheSync, ISplitsCacheAsync, IStorageFactoryParams } from '../storages/types'; import { ISyncManager, ISyncManagerFactoryParams } from '../sync/types'; import { IImpressionObserver } from '../trackers/impressionObserver/types'; @@ -16,7 +16,7 @@ import { SplitIO, ISettings, IEventEmitter } from '../types'; export interface IPlatform { getOptions?: () => object getFetch?: () => (IFetch | undefined) - getEventSource?: () => (typeof EventSource | undefined) + getEventSource?: () => (IEventSourceConstructor | undefined) EventEmitter: new () => IEventEmitter } diff --git a/src/services/types.ts b/src/services/types.ts index b1bdf954..d7af2d59 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -50,8 +50,8 @@ export type IPostMetricsCounters = (body: string) => Promise export type IPostMetricsTimes = (body: string) => Promise export interface ISplitApi { - getSdkAPIHealthCheck: IHealthCheckAPI - getEventsAPIHealthCheck: IHealthCheckAPI + getSdkAPIHealthCheck: IHealthCheckAPI + getEventsAPIHealthCheck: IHealthCheckAPI fetchAuth: IFetchAuth fetchSplitChanges: IFetchSplitChanges fetchSegmentChanges: IFetchSegmentChanges @@ -62,3 +62,17 @@ export interface ISplitApi { postMetricsCounters: IPostMetricsCounters postMetricsTimes: IPostMetricsTimes } + +// Minimal version of EventSource API used by the SDK +interface EventSourceEventMap { + 'error': Event + 'message': MessageEvent + 'open': Event +} + +interface IEventSource { + addEventListener(type: K, listener: (this: IEventSource, ev: EventSourceEventMap[K]) => any): void + close(): void +} + +export type IEventSourceConstructor = new (url: string, eventSourceInitDict?: { headers?: object }) => IEventSource diff --git a/src/sync/streaming/SSEClient/index.ts b/src/sync/streaming/SSEClient/index.ts index 7e3cc4bb..fbd09261 100644 --- a/src/sync/streaming/SSEClient/index.ts +++ b/src/sync/streaming/SSEClient/index.ts @@ -1,3 +1,4 @@ +import { IEventSourceConstructor } from '../../../services/types'; import { ISettings } from '../../../types'; import { IAuthTokenPushEnabled } from '../AuthClient/types'; import { ISSEClient, ISseEventHandler } from './types'; @@ -31,9 +32,9 @@ function buildSSEHeaders(settings: ISettings) { */ export default class SSEClient implements ISSEClient { // Instance properties: - eventSource: typeof EventSource; + eventSource?: IEventSourceConstructor; streamingUrl: string; - connection?: InstanceType; + connection?: InstanceType; handler?: ISseEventHandler; useHeaders?: boolean; headers: Record; @@ -46,8 +47,7 @@ export default class SSEClient implements ISSEClient { * @param getEventSource Function to get the EventSource constructor. * @throws 'EventSource API is not available. ' if EventSource is not available. */ - constructor(settings: ISettings, useHeaders?: boolean, getEventSource?: () => (typeof EventSource | undefined)) { - // @ts-expect-error + constructor(settings: ISettings, useHeaders?: boolean, getEventSource?: () => (IEventSourceConstructor | undefined)) { this.eventSource = getEventSource && getEventSource(); // if eventSource is not available, throw an exception if (!this.eventSource) throw new Error('EventSource API is not available. '); @@ -79,7 +79,7 @@ export default class SSEClient implements ISSEClient { ).join(','); const url = `${this.streamingUrl}?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${VERSION}&heartbeats=true`; // same results using `&heartbeats=false` - this.connection = new this.eventSource( + this.connection = new this.eventSource!( // For client-side SDKs, SplitSDKClientKey and SplitSDKClientKey metadata is passed as query params, // because native EventSource implementations for browser doesn't support headers. this.useHeaders ? url : url + `&SplitSDKVersion=${this.headers.SplitSDKVersion}&SplitSDKClientKey=${this.headers.SplitSDKClientKey}`, From c1ebd257b518cbbddeae709a4b0d23d66b471d81 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 9 Dec 2021 20:14:12 -0300 Subject: [PATCH 5/5] fixed type --- package-lock.json | 2 +- package.json | 2 +- src/services/types.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b2c91c99..cdecc850 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "1.0.1-rc.3", + "version": "1.0.1-rc.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index cf0cc5ac..68610a2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "1.0.1-rc.3", + "version": "1.0.1-rc.4", "description": "Split Javascript SDK common components", "main": "cjs/index.js", "module": "esm/index.js", diff --git a/src/services/types.ts b/src/services/types.ts index d7af2d59..22650c5b 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -75,4 +75,4 @@ interface IEventSource { close(): void } -export type IEventSourceConstructor = new (url: string, eventSourceInitDict?: { headers?: object }) => IEventSource +export type IEventSourceConstructor = new (url: string, eventSourceInitDict?: any) => IEventSource