From 45398e72be1b259479ffa4b33ab0ebb10ea1bd3f Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 7 Oct 2021 13:06:59 -0300 Subject: [PATCH 1/8] added localhost module validator, used in the slim entry point of JS Browser and RN --- src/logger/constants.ts | 1 + src/logger/messages/error.ts | 1 + .../splitsParser/splitsParserFromFile.ts | 9 +++++---- src/sync/syncManagerFromFile.ts | 13 +++++++++++++ src/sync/syncManagerFromObject.ts | 12 ++++++++++++ src/types.ts | 11 ++++++++++- src/utils/settingsValidation/index.ts | 7 +++++-- .../settingsValidation/localhost/index.ts | 19 +++++++++++++++++++ src/utils/settingsValidation/types.ts | 2 ++ 9 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 src/sync/syncManagerFromFile.ts create mode 100644 src/sync/syncManagerFromObject.ts create mode 100644 src/utils/settingsValidation/localhost/index.ts diff --git a/src/logger/constants.ts b/src/logger/constants.ts index 79f629c2..5ca7317c 100644 --- a/src/logger/constants.ts +++ b/src/logger/constants.ts @@ -118,6 +118,7 @@ export const ERROR_EMPTY = 319; export const ERROR_EMPTY_ARRAY = 320; export const ERROR_INVALID_IMPRESSIONS_MODE = 321; export const ERROR_HTTP = 322; +export const ERROR_LOCALHOST_MODULE_REQUIRED = 323; // Log prefixes (a.k.a. tags or categories) export const LOG_PREFIX_SETTINGS = 'settings'; diff --git a/src/logger/messages/error.ts b/src/logger/messages/error.ts index 9a6de5c3..5d4d13dd 100644 --- a/src/logger/messages/error.ts +++ b/src/logger/messages/error.ts @@ -30,4 +30,5 @@ export const codesError: [number, string][] = [ [c.ERROR_EMPTY_ARRAY, '%s: %s must be a non-empty array.'], // initialization / settings validation [c.ERROR_INVALID_IMPRESSIONS_MODE, c.LOG_PREFIX_SETTINGS + ': you passed an invalid "impressionsMode". It should be one of the following values: %s. Defaulting to "%s" mode.'], + [c.ERROR_LOCALHOST_MODULE_REQUIRED, c.LOG_PREFIX_SETTINGS + ': you didn\'t pass a valid "sync.localhostMode". It should be defined for using the SDK in localhost mode'] ]; diff --git a/src/sync/offline/splitsParser/splitsParserFromFile.ts b/src/sync/offline/splitsParser/splitsParserFromFile.ts index 62de09f4..95ea8d14 100644 --- a/src/sync/offline/splitsParser/splitsParserFromFile.ts +++ b/src/sync/offline/splitsParser/splitsParserFromFile.ts @@ -7,8 +7,9 @@ import yaml from 'js-yaml'; import { isString, endsWith, find, forOwn, uniq, } from '../../../utils/lang'; import parseCondition, { IMockSplitEntry } from './parseCondition'; import { ISplitPartial } from '../../../dtos/types'; -import { SplitIO } from '../../../types'; +import { ISettings, SplitIO } from '../../../types'; import { ILogger } from '../../../logger/types'; +import { ISplitsParser } from './types'; const logPrefix = 'sync:offline:splits-fetcher: '; @@ -68,7 +69,7 @@ function arrangeConditions(mocksData: Record & { }); } -export function splitsParserFromFileFactory() { +export function splitsParserFromFileFactory(): ISplitsParser { let previousMock = 'NO_MOCK_LOADED'; @@ -163,8 +164,8 @@ export function splitsParserFromFileFactory() { } // Load the content of a configuration file into an Object - return function splitsParserFromFile({ features, log }: { features?: SplitIO.MockedFeaturesFilePath, log: ILogger }): false | Record { - const filePath = configFilesPath(features); + return function splitsParserFromFile({ features, log }: ISettings): false | Record { + const filePath = configFilesPath(features as string); let mockData: false | Record; // If we have a filePath, it means the extension is correct, choose the parser. diff --git a/src/sync/syncManagerFromFile.ts b/src/sync/syncManagerFromFile.ts new file mode 100644 index 00000000..f1a27fce --- /dev/null +++ b/src/sync/syncManagerFromFile.ts @@ -0,0 +1,13 @@ +import { splitsParserFromFileFactory } from './offline/splitsParser/splitsParserFromFile'; +import { syncManagerOfflineFactory } from './syncManagerOffline'; +import { SplitIO } from '../types'; +import { LOCALHOST_MODE } from '../utils/constants'; + +// Factory of Localhost SyncManager based on yaml file. +// Requires Node 'fs' and 'path' APIs. +export function LocalhostFromFile(): SplitIO.LocalhostFactory { + const localhost = syncManagerOfflineFactory(splitsParserFromFileFactory); + // @ts-ignore + localhost.type = LOCALHOST_MODE; + return localhost; +} diff --git a/src/sync/syncManagerFromObject.ts b/src/sync/syncManagerFromObject.ts new file mode 100644 index 00000000..24b4f0f3 --- /dev/null +++ b/src/sync/syncManagerFromObject.ts @@ -0,0 +1,12 @@ +import { splitsParserFromSettingsFactory } from './offline/splitsParser/splitsParserFromSettings'; +import { syncManagerOfflineFactory } from './syncManagerOffline'; +import { SplitIO } from '../types'; +import { LOCALHOST_MODE } from '../utils/constants'; + +// Factory of Localhost SyncManager based on JS object. +export function LocalhostFromObject(): SplitIO.LocalhostFactory { + const localhost = syncManagerOfflineFactory(splitsParserFromSettingsFactory); + // @ts-ignore + localhost.type = LOCALHOST_MODE; + return localhost; +} diff --git a/src/types.ts b/src/types.ts index 9d20e84f..3b960424 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,6 +4,7 @@ import { ILogger } from './logger/types'; /* eslint-disable no-use-before-define */ import { IStorageFactoryParams, IStorageSyncCS, IStorageSync, IStorageAsync, IStorageSyncFactory } from './storages/types'; +import { ISyncManagerFactoryParams, ISyncManagerCS } from './sync/types'; /** * EventEmitter interface with the minimal methods used by the SDK @@ -99,7 +100,8 @@ export interface ISettings { readonly sync: { splitFilters: SplitIO.SplitFilter[], impressionsMode: SplitIO.ImpressionsMode, - __splitFiltersValidation: ISplitFiltersValidation + __splitFiltersValidation: ISplitFiltersValidation, + localhostMode: SplitIO.LocalhostFactory }, readonly runtime: { ip: string | false @@ -581,6 +583,13 @@ export namespace SplitIO { * @typedef {Promise} SplitNamesAsync */ export type SplitNamesAsync = Promise; + /** + * Localhost mode factory. + */ + export type LocalhostFactory = { + type?: 'localhost' + (params: ISyncManagerFactoryParams): ISyncManagerCS + } /** * Impression listener interface. This is the interface that needs to be implemented * by the element you provide to the SDK as impression listener. diff --git a/src/utils/settingsValidation/index.ts b/src/utils/settingsValidation/index.ts index 96f22227..2a211f90 100644 --- a/src/utils/settingsValidation/index.ts +++ b/src/utils/settingsValidation/index.ts @@ -74,7 +74,8 @@ const base = { sync: { splitFilters: undefined, // impressions collection mode - impressionsMode: OPTIMIZED + impressionsMode: OPTIMIZED, + localhostMode: undefined }, runtime: { @@ -99,7 +100,7 @@ function fromSecondsToMillis(n: number) { */ export function settingsValidation(config: unknown, validationParams: ISettingsValidationParams) { - const { defaults, runtime, storage, integrations, logger } = validationParams; + const { defaults, runtime, storage, integrations, logger, localhost } = validationParams; // creates a settings object merging base, defaults and config objects. const withDefaults = merge({}, base, defaults, config) as ISettings; @@ -144,6 +145,8 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV // @ts-ignore, modify readonly prop if (integrations) withDefaults.integrations = integrations(withDefaults); + if (localhost) withDefaults.sync.localhostMode = localhost(withDefaults); + // validate push options if (withDefaults.streamingEnabled !== false) { // @ts-ignore, modify readonly prop withDefaults.streamingEnabled = true; diff --git a/src/utils/settingsValidation/localhost/index.ts b/src/utils/settingsValidation/localhost/index.ts new file mode 100644 index 00000000..0f6aad9d --- /dev/null +++ b/src/utils/settingsValidation/localhost/index.ts @@ -0,0 +1,19 @@ +import { ERROR_LOCALHOST_MODULE_REQUIRED } from '../../../logger/constants'; +import { ISettings, } from '../../../types'; +import { LOCALHOST_MODE } from '../../constants'; + +/** + * This function validates `settings.storage` object + * + * @param {any} settings config object provided by the user to initialize the sdk + * + * @returns {Object} valid storage factory. It might be the default `InMemoryStorageCSFactory` if the provided storage is invalid. + */ +export function validateLocalhost(settings: ISettings) { + const localhostMode = settings.sync.localhostMode; + + if (settings.mode === LOCALHOST_MODE && (typeof localhostMode !== 'function' || localhostMode.type !== LOCALHOST_MODE)) { + settings.log.error(ERROR_LOCALHOST_MODULE_REQUIRED); + } + return localhostMode; +} diff --git a/src/utils/settingsValidation/types.ts b/src/utils/settingsValidation/types.ts index a3ab3761..a9438a30 100644 --- a/src/utils/settingsValidation/types.ts +++ b/src/utils/settingsValidation/types.ts @@ -18,4 +18,6 @@ export interface ISettingsValidationParams { integrations?: (settings: ISettings) => ISettings['integrations'], /** Logger validator */ logger: (settings: ISettings) => ISettings['log'], + /** Localhost mode validator */ + localhost?: (settings: ISettings) => ISettings['sync']['localhostMode'], } From 35163205c0210b0336a53beebb0ee7c491ecd07a Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 7 Oct 2021 14:45:11 -0300 Subject: [PATCH 2/8] updated test mocks --- .../settingsValidation/__tests__/settings.mocks.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/utils/settingsValidation/__tests__/settings.mocks.ts b/src/utils/settingsValidation/__tests__/settings.mocks.ts index 4b8a10e4..a08da99d 100644 --- a/src/utils/settingsValidation/__tests__/settings.mocks.ts +++ b/src/utils/settingsValidation/__tests__/settings.mocks.ts @@ -1,6 +1,7 @@ import { InMemoryStorageCSFactory } from '../../../storages/inMemory/InMemoryStorageCS'; import { ISettings } from '../../../types'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { LocalhostFromObject } from '../../../sync/syncManagerFromObject'; export const settingsWithKey = { core: { @@ -61,13 +62,19 @@ export const fullSettings: ISettings = { }, features: 'path/to/file', storage: InMemoryStorageCSFactory, - integrations: [()=>{}], // A no-op integration + integrations: [() => { }], // A no-op integration mode: 'standalone', debug: false, streamingEnabled: false, sync: { splitFilters: [], - impressionsMode: 'OPTIMIZED' + impressionsMode: 'OPTIMIZED', + localhostMode: LocalhostFromObject(), + __splitFiltersValidation: { + validFilters: [], + queryString: null, + groupedFilters: { byName: [], byPrefix: [] } + } }, version: 'jest', runtime: { From 069c5908031fcaf3df706e3992d37dd3557bc151 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 13 Oct 2021 12:28:03 -0300 Subject: [PATCH 3/8] review --- src/logger/index.ts | 14 +++++++------- src/logger/messages/error.ts | 2 +- .../LocalhostFromFile.ts} | 10 ++++------ .../LocalhostFromObject.ts} | 10 ++++------ src/sync/{ => offline}/syncManagerOffline.ts | 10 +++++----- src/types.ts | 2 +- src/utils/settingsValidation/localhost/index.ts | 3 ++- 7 files changed, 24 insertions(+), 27 deletions(-) rename src/sync/{syncManagerFromFile.ts => offline/LocalhostFromFile.ts} (56%) rename src/sync/{syncManagerFromObject.ts => offline/LocalhostFromObject.ts} (51%) rename src/sync/{ => offline}/syncManagerOffline.ts (85%) diff --git a/src/logger/index.ts b/src/logger/index.ts index 4738e191..ed2e5032 100644 --- a/src/logger/index.ts +++ b/src/logger/index.ts @@ -12,7 +12,7 @@ export const LogLevels: { [level: string]: LogLevel } = { NONE: 'NONE' }; -const LogLevelRanks = { +const LogLevelIndexes = { DEBUG: 1, INFO: 2, WARN: 3, @@ -47,28 +47,28 @@ export class Logger implements ILogger { constructor(options?: ILoggerOptions, codes?: IMap) { this.options = objectAssign({}, defaultOptions, options); this.codes = codes || new _Map(); - this.logLevel = LogLevelRanks[this.options.logLevel]; + this.logLevel = LogLevelIndexes[this.options.logLevel]; } setLogLevel(logLevel: LogLevel) { this.options.logLevel = logLevel; - this.logLevel = LogLevelRanks[logLevel]; + this.logLevel = LogLevelIndexes[logLevel]; } debug(msg: string | number, args?: any[]) { - if (this._shouldLog(LogLevelRanks.DEBUG)) this._log(LogLevels.DEBUG, msg, args); + if (this._shouldLog(LogLevelIndexes.DEBUG)) this._log(LogLevels.DEBUG, msg, args); } info(msg: string | number, args?: any[]) { - if (this._shouldLog(LogLevelRanks.INFO)) this._log(LogLevels.INFO, msg, args); + if (this._shouldLog(LogLevelIndexes.INFO)) this._log(LogLevels.INFO, msg, args); } warn(msg: string | number, args?: any[]) { - if (this._shouldLog(LogLevelRanks.WARN)) this._log(LogLevels.WARN, msg, args); + if (this._shouldLog(LogLevelIndexes.WARN)) this._log(LogLevels.WARN, msg, args); } error(msg: string | number, args?: any[]) { - if (this._shouldLog(LogLevelRanks.ERROR)) this._log(LogLevels.ERROR, msg, args); + if (this._shouldLog(LogLevelIndexes.ERROR)) this._log(LogLevels.ERROR, msg, args); } private _log(level: LogLevel, msg: string | number, args?: any[]) { diff --git a/src/logger/messages/error.ts b/src/logger/messages/error.ts index 5d4d13dd..75269bc9 100644 --- a/src/logger/messages/error.ts +++ b/src/logger/messages/error.ts @@ -30,5 +30,5 @@ export const codesError: [number, string][] = [ [c.ERROR_EMPTY_ARRAY, '%s: %s must be a non-empty array.'], // initialization / settings validation [c.ERROR_INVALID_IMPRESSIONS_MODE, c.LOG_PREFIX_SETTINGS + ': you passed an invalid "impressionsMode". It should be one of the following values: %s. Defaulting to "%s" mode.'], - [c.ERROR_LOCALHOST_MODULE_REQUIRED, c.LOG_PREFIX_SETTINGS + ': you didn\'t pass a valid "sync.localhostMode". It should be defined for using the SDK in localhost mode'] + [c.ERROR_LOCALHOST_MODULE_REQUIRED, c.LOG_PREFIX_SETTINGS + ': an invalid value was received for "sync.localhostMode" config. A valid entity should be provided for localhost mode.'] ]; diff --git a/src/sync/syncManagerFromFile.ts b/src/sync/offline/LocalhostFromFile.ts similarity index 56% rename from src/sync/syncManagerFromFile.ts rename to src/sync/offline/LocalhostFromFile.ts index f1a27fce..3a9b176f 100644 --- a/src/sync/syncManagerFromFile.ts +++ b/src/sync/offline/LocalhostFromFile.ts @@ -1,13 +1,11 @@ -import { splitsParserFromFileFactory } from './offline/splitsParser/splitsParserFromFile'; +import { splitsParserFromFileFactory } from './splitsParser/splitsParserFromFile'; import { syncManagerOfflineFactory } from './syncManagerOffline'; -import { SplitIO } from '../types'; -import { LOCALHOST_MODE } from '../utils/constants'; +import { SplitIO } from '../../types'; // Factory of Localhost SyncManager based on yaml file. // Requires Node 'fs' and 'path' APIs. export function LocalhostFromFile(): SplitIO.LocalhostFactory { - const localhost = syncManagerOfflineFactory(splitsParserFromFileFactory); - // @ts-ignore - localhost.type = LOCALHOST_MODE; + const localhost = syncManagerOfflineFactory(splitsParserFromFileFactory) as SplitIO.LocalhostFactory; + localhost.type = 'fromFile'; return localhost; } diff --git a/src/sync/syncManagerFromObject.ts b/src/sync/offline/LocalhostFromObject.ts similarity index 51% rename from src/sync/syncManagerFromObject.ts rename to src/sync/offline/LocalhostFromObject.ts index 24b4f0f3..57d8ca0f 100644 --- a/src/sync/syncManagerFromObject.ts +++ b/src/sync/offline/LocalhostFromObject.ts @@ -1,12 +1,10 @@ -import { splitsParserFromSettingsFactory } from './offline/splitsParser/splitsParserFromSettings'; +import { splitsParserFromSettingsFactory } from './splitsParser/splitsParserFromSettings'; import { syncManagerOfflineFactory } from './syncManagerOffline'; -import { SplitIO } from '../types'; -import { LOCALHOST_MODE } from '../utils/constants'; +import { SplitIO } from '../../types'; // Factory of Localhost SyncManager based on JS object. export function LocalhostFromObject(): SplitIO.LocalhostFactory { - const localhost = syncManagerOfflineFactory(splitsParserFromSettingsFactory); - // @ts-ignore - localhost.type = LOCALHOST_MODE; + const localhost = syncManagerOfflineFactory(splitsParserFromSettingsFactory) as SplitIO.LocalhostFactory; + localhost.type = 'fromObject'; return localhost; } diff --git a/src/sync/syncManagerOffline.ts b/src/sync/offline/syncManagerOffline.ts similarity index 85% rename from src/sync/syncManagerOffline.ts rename to src/sync/offline/syncManagerOffline.ts index 2ef909ee..58a75b6f 100644 --- a/src/sync/syncManagerOffline.ts +++ b/src/sync/offline/syncManagerOffline.ts @@ -1,9 +1,9 @@ -import { ISyncManager, ISyncManagerCS, ISyncManagerFactoryParams } from './types'; -import fromObjectSyncTaskFactory from './offline/syncTasks/fromObjectSyncTask'; +import { ISyncManager, ISyncManagerCS, ISyncManagerFactoryParams } from '../types'; +import fromObjectSyncTaskFactory from './syncTasks/fromObjectSyncTask'; import objectAssign from 'object-assign'; -import { ISplitsParser } from './offline/splitsParser/types'; -import { IReadinessManager } from '../readiness/types'; -import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants'; +import { ISplitsParser } from './splitsParser/types'; +import { IReadinessManager } from '../../readiness/types'; +import { SDK_SEGMENTS_ARRIVED } from '../../readiness/constants'; function flush() { return Promise.resolve(); diff --git a/src/types.ts b/src/types.ts index 3b960424..92efbe6d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -587,7 +587,7 @@ export namespace SplitIO { * Localhost mode factory. */ export type LocalhostFactory = { - type?: 'localhost' + type: 'fromObject' | 'fromFile' (params: ISyncManagerFactoryParams): ISyncManagerCS } /** diff --git a/src/utils/settingsValidation/localhost/index.ts b/src/utils/settingsValidation/localhost/index.ts index 0f6aad9d..2fb40e05 100644 --- a/src/utils/settingsValidation/localhost/index.ts +++ b/src/utils/settingsValidation/localhost/index.ts @@ -12,7 +12,8 @@ import { LOCALHOST_MODE } from '../../constants'; export function validateLocalhost(settings: ISettings) { const localhostMode = settings.sync.localhostMode; - if (settings.mode === LOCALHOST_MODE && (typeof localhostMode !== 'function' || localhostMode.type !== LOCALHOST_MODE)) { + // localhostMode.type is used for internal validation. Not considered part of the public API, and might be updated eventually. + if (settings.mode === LOCALHOST_MODE && (typeof localhostMode !== 'function' || localhostMode.type !== 'fromObject')) { settings.log.error(ERROR_LOCALHOST_MODULE_REQUIRED); } return localhostMode; From 8230e89924520bf013e9494fa0bb3c3626c81898 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 13 Oct 2021 21:55:39 -0300 Subject: [PATCH 4/8] polishing on some export default --- src/integrations/__tests__/browser.spec.ts | 4 ++-- src/integrations/browser.ts | 8 ++++---- src/integrations/ga/GaToSplit.ts | 2 +- .../ga/{GaToSplitPlugin.ts => GoogleAnalyticsToSplit.ts} | 4 ++-- src/integrations/ga/SplitToGa.ts | 2 +- .../ga/{SplitToGaPlugin.ts => SplitToGoogleAnalytics.ts} | 4 ++-- src/integrations/ga/__tests__/GaToSplit.spec.ts | 2 +- src/integrations/ga/__tests__/SplitToGa.spec.ts | 2 +- src/utils/settingsValidation/__tests__/settings.mocks.ts | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) rename src/integrations/ga/{GaToSplitPlugin.ts => GoogleAnalyticsToSplit.ts} (66%) rename src/integrations/ga/{SplitToGaPlugin.ts => SplitToGoogleAnalytics.ts} (67%) diff --git a/src/integrations/__tests__/browser.spec.ts b/src/integrations/__tests__/browser.spec.ts index 9bab3e99..1b79d8bb 100644 --- a/src/integrations/__tests__/browser.spec.ts +++ b/src/integrations/__tests__/browser.spec.ts @@ -6,9 +6,9 @@ import { loggerMock } from '../../logger/__tests__/sdkLogger.mock'; // Mock integration modules (GaToSplit and SplitToGa). jest.mock('../ga/GaToSplit'); -import GaToSplitMock from '../ga/GaToSplit'; +import { GaToSplit as GaToSplitMock } from '../ga/GaToSplit'; jest.mock('../ga/SplitToGa'); -import SplitToGaMock from '../ga/SplitToGa'; +import { SplitToGa as SplitToGaMock } from '../ga/SplitToGa'; const SplitToGaQueueMethod = jest.fn(); (SplitToGaMock as unknown as jest.Mock).mockImplementation(() => { diff --git a/src/integrations/browser.ts b/src/integrations/browser.ts index f9cb8927..f3a17713 100644 --- a/src/integrations/browser.ts +++ b/src/integrations/browser.ts @@ -2,8 +2,8 @@ import { GOOGLE_ANALYTICS_TO_SPLIT, SPLIT_TO_GOOGLE_ANALYTICS } from '../utils/c import { IIntegration, IIntegrationManager, IIntegrationFactoryParams } from './types'; import { BrowserIntegration } from './ga/types'; import pluggableIntegrationsManagerFactory from './pluggable'; -import GaToSplitPlugin from './ga/GaToSplitPlugin'; -import SplitToGaPlugin from './ga/SplitToGaPlugin'; +import { GoogleAnalyticsToSplit } from './ga/GoogleAnalyticsToSplit'; +import { SplitToGoogleAnalytics } from './ga/SplitToGoogleAnalytics'; /** * IntegrationsManager factory for the browser variant of the isomorphic JS SDK. @@ -23,8 +23,8 @@ export default function integrationsManagerFactory( const integrationFactories: Array<(params: IIntegrationFactoryParams) => IIntegration | void> = integrations .map(integrationOptions => { switch (integrationOptions.type) { - case GOOGLE_ANALYTICS_TO_SPLIT: return GaToSplitPlugin(integrationOptions); - case SPLIT_TO_GOOGLE_ANALYTICS: return SplitToGaPlugin(integrationOptions); + case GOOGLE_ANALYTICS_TO_SPLIT: return GoogleAnalyticsToSplit(integrationOptions); + case SPLIT_TO_GOOGLE_ANALYTICS: return SplitToGoogleAnalytics(integrationOptions); } }) .filter(integrationFactory => { diff --git a/src/integrations/ga/GaToSplit.ts b/src/integrations/ga/GaToSplit.ts index befa31f1..360c93a1 100644 --- a/src/integrations/ga/GaToSplit.ts +++ b/src/integrations/ga/GaToSplit.ts @@ -182,7 +182,7 @@ export function fixEventTypeId(log: ILogger, eventTypeId: any) { * @param {object} coreSettings core settings used to define an identity if no one provided as SDK or plugin options * @param {object} log factory logger */ -export default function GaToSplit(sdkOptions: GoogleAnalyticsToSplitOptions, params: IIntegrationFactoryParams) { +export function GaToSplit(sdkOptions: GoogleAnalyticsToSplitOptions, params: IIntegrationFactoryParams) { const { storage, settings: { core: coreSettings, log } } = params; diff --git a/src/integrations/ga/GaToSplitPlugin.ts b/src/integrations/ga/GoogleAnalyticsToSplit.ts similarity index 66% rename from src/integrations/ga/GaToSplitPlugin.ts rename to src/integrations/ga/GoogleAnalyticsToSplit.ts index 04a16905..940447aa 100644 --- a/src/integrations/ga/GaToSplitPlugin.ts +++ b/src/integrations/ga/GoogleAnalyticsToSplit.ts @@ -1,8 +1,8 @@ import { IIntegrationFactoryParams } from '../types'; -import GaToSplit from './GaToSplit'; +import { GaToSplit } from './GaToSplit'; import { GoogleAnalyticsToSplitOptions } from './types'; -export default function GaToSplitPlugin(options: GoogleAnalyticsToSplitOptions) { +export function GoogleAnalyticsToSplit(options: GoogleAnalyticsToSplitOptions) { // GaToSplit integration factory return (params: IIntegrationFactoryParams) => { diff --git a/src/integrations/ga/SplitToGa.ts b/src/integrations/ga/SplitToGa.ts index df933c21..dd469676 100644 --- a/src/integrations/ga/SplitToGa.ts +++ b/src/integrations/ga/SplitToGa.ts @@ -10,7 +10,7 @@ const logPrefix = 'split-to-ga: '; const noGaWarning = '`ga` command queue not found.'; const noHit = 'No hit was sent.'; -export default class SplitToGa implements IIntegration { +export class SplitToGa implements IIntegration { // A falsy object represents the default tracker static defaultTrackerNames = ['']; diff --git a/src/integrations/ga/SplitToGaPlugin.ts b/src/integrations/ga/SplitToGoogleAnalytics.ts similarity index 67% rename from src/integrations/ga/SplitToGaPlugin.ts rename to src/integrations/ga/SplitToGoogleAnalytics.ts index 9001c180..4ec71177 100644 --- a/src/integrations/ga/SplitToGaPlugin.ts +++ b/src/integrations/ga/SplitToGoogleAnalytics.ts @@ -1,8 +1,8 @@ import { IIntegrationFactoryParams } from '../types'; -import SplitToGa from './SplitToGa'; +import { SplitToGa } from './SplitToGa'; import { SplitToGoogleAnalyticsOptions } from './types'; -export default function SplitToGaPlugin(options: SplitToGoogleAnalyticsOptions = {}) { +export function SplitToGoogleAnalytics(options: SplitToGoogleAnalyticsOptions = {}) { // SplitToGa integration factory return (params: IIntegrationFactoryParams) => { diff --git a/src/integrations/ga/__tests__/GaToSplit.spec.ts b/src/integrations/ga/__tests__/GaToSplit.spec.ts index 0a7ef567..3296fe86 100644 --- a/src/integrations/ga/__tests__/GaToSplit.spec.ts +++ b/src/integrations/ga/__tests__/GaToSplit.spec.ts @@ -1,7 +1,7 @@ /* eslint-disable no-undef */ import { IEventsCacheSync } from '../../../storages/types'; import { SplitIO, ISettings } from '../../../types'; -import GaToSplit, { validateIdentities, defaultPrefix, defaultMapper, validateEventData, fixEventTypeId } from '../GaToSplit'; +import { GaToSplit, validateIdentities, defaultPrefix, defaultMapper, validateEventData, fixEventTypeId } from '../GaToSplit'; import { gaMock, gaRemove, modelMock } from './gaMock'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; diff --git a/src/integrations/ga/__tests__/SplitToGa.spec.ts b/src/integrations/ga/__tests__/SplitToGa.spec.ts index 849350ca..d05e4bab 100644 --- a/src/integrations/ga/__tests__/SplitToGa.spec.ts +++ b/src/integrations/ga/__tests__/SplitToGa.spec.ts @@ -6,7 +6,7 @@ import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; import { gaMock, gaRemove } from './gaMock'; // Test target -import SplitToGa from '../SplitToGa'; +import { SplitToGa } from '../SplitToGa'; const fakeImpressionPayload: SplitIO.ImpressionData = { impression: { diff --git a/src/utils/settingsValidation/__tests__/settings.mocks.ts b/src/utils/settingsValidation/__tests__/settings.mocks.ts index a08da99d..80aacabf 100644 --- a/src/utils/settingsValidation/__tests__/settings.mocks.ts +++ b/src/utils/settingsValidation/__tests__/settings.mocks.ts @@ -1,7 +1,7 @@ import { InMemoryStorageCSFactory } from '../../../storages/inMemory/InMemoryStorageCS'; import { ISettings } from '../../../types'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; -import { LocalhostFromObject } from '../../../sync/syncManagerFromObject'; +import { LocalhostFromObject } from '../../../sync/offline/LocalhostFromObject'; export const settingsWithKey = { core: { From 427f56c2874009fe924a97b96d3cdb69304b67d6 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 13 Oct 2021 23:45:45 -0300 Subject: [PATCH 5/8] validator update --- package-lock.json | 2 +- package.json | 2 +- src/listeners/__tests__/node.spec.ts | 4 ++-- src/sync/offline/LocalhostFromFile.ts | 2 +- src/sync/offline/LocalhostFromObject.ts | 2 +- src/types.ts | 4 ++-- src/utils/settingsValidation/localhost/index.ts | 7 ++++--- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 17c71d80..a8317261 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "0.1.1-rc.18", + "version": "0.1.1-rc.19", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c8daf370..353d90fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "0.1.1-rc.18", + "version": "0.1.1-rc.19", "description": "Split Javascript SDK common components", "main": "cjs/index.js", "module": "esm/index.js", diff --git a/src/listeners/__tests__/node.spec.ts b/src/listeners/__tests__/node.spec.ts index 4e226a6b..1755fa7d 100644 --- a/src/listeners/__tests__/node.spec.ts +++ b/src/listeners/__tests__/node.spec.ts @@ -144,7 +144,7 @@ test('Node JS listener / Signal Listener SIGTERM callback with async handler tha // Call function // @ts-expect-error - const handlerPromise = listener._sigtermHandler(); + const handlerPromise: Promise = listener._sigtermHandler(); // Handler was properly called. expect(syncManagerMock.flush).toBeCalledTimes(1); @@ -154,7 +154,7 @@ test('Node JS listener / Signal Listener SIGTERM callback with async handler tha expect(processKillSpy).not.toBeCalled(); // Calling .then since the wrapUp handler does not throw. - await (handlerPromise as Promise).then(() => { + await handlerPromise.then(() => { // Clean up is called. expect(listener.stop).toBeCalledTimes(1); // It called for kill again, so the shutdown keeps going. diff --git a/src/sync/offline/LocalhostFromFile.ts b/src/sync/offline/LocalhostFromFile.ts index 3a9b176f..2caff329 100644 --- a/src/sync/offline/LocalhostFromFile.ts +++ b/src/sync/offline/LocalhostFromFile.ts @@ -6,6 +6,6 @@ import { SplitIO } from '../../types'; // Requires Node 'fs' and 'path' APIs. export function LocalhostFromFile(): SplitIO.LocalhostFactory { const localhost = syncManagerOfflineFactory(splitsParserFromFileFactory) as SplitIO.LocalhostFactory; - localhost.type = 'fromFile'; + localhost.type = 'LocalhostFromFile'; return localhost; } diff --git a/src/sync/offline/LocalhostFromObject.ts b/src/sync/offline/LocalhostFromObject.ts index 57d8ca0f..d1510996 100644 --- a/src/sync/offline/LocalhostFromObject.ts +++ b/src/sync/offline/LocalhostFromObject.ts @@ -5,6 +5,6 @@ import { SplitIO } from '../../types'; // Factory of Localhost SyncManager based on JS object. export function LocalhostFromObject(): SplitIO.LocalhostFactory { const localhost = syncManagerOfflineFactory(splitsParserFromSettingsFactory) as SplitIO.LocalhostFactory; - localhost.type = 'fromObject'; + localhost.type = 'LocalhostFromObject'; return localhost; } diff --git a/src/types.ts b/src/types.ts index 92efbe6d..691c5beb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -101,7 +101,7 @@ export interface ISettings { splitFilters: SplitIO.SplitFilter[], impressionsMode: SplitIO.ImpressionsMode, __splitFiltersValidation: ISplitFiltersValidation, - localhostMode: SplitIO.LocalhostFactory + localhostMode?: SplitIO.LocalhostFactory }, readonly runtime: { ip: string | false @@ -587,7 +587,7 @@ export namespace SplitIO { * Localhost mode factory. */ export type LocalhostFactory = { - type: 'fromObject' | 'fromFile' + type: 'LocalhostFromObject' | 'LocalhostFromFile' (params: ISyncManagerFactoryParams): ISyncManagerCS } /** diff --git a/src/utils/settingsValidation/localhost/index.ts b/src/utils/settingsValidation/localhost/index.ts index 2fb40e05..19a196b8 100644 --- a/src/utils/settingsValidation/localhost/index.ts +++ b/src/utils/settingsValidation/localhost/index.ts @@ -3,18 +3,19 @@ import { ISettings, } from '../../../types'; import { LOCALHOST_MODE } from '../../constants'; /** - * This function validates `settings.storage` object + * This function validates `settings.sync.localhostMode` object * * @param {any} settings config object provided by the user to initialize the sdk * - * @returns {Object} valid storage factory. It might be the default `InMemoryStorageCSFactory` if the provided storage is invalid. + * @returns {Object | undefined} valid localhost mode module, or undefined if the provided one is not provided or invalid. */ export function validateLocalhost(settings: ISettings) { const localhostMode = settings.sync.localhostMode; // localhostMode.type is used for internal validation. Not considered part of the public API, and might be updated eventually. - if (settings.mode === LOCALHOST_MODE && (typeof localhostMode !== 'function' || localhostMode.type !== 'fromObject')) { + if (settings.mode === LOCALHOST_MODE && (typeof localhostMode !== 'function' || localhostMode.type !== 'LocalhostFromObject')) { settings.log.error(ERROR_LOCALHOST_MODULE_REQUIRED); + return undefined; } return localhostMode; } From 60741a3e6462678315b85e248ed299b5e4088402 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 14 Oct 2021 12:46:27 -0300 Subject: [PATCH 6/8] polish comment --- src/utils/settingsValidation/localhost/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/settingsValidation/localhost/index.ts b/src/utils/settingsValidation/localhost/index.ts index 19a196b8..b97b320b 100644 --- a/src/utils/settingsValidation/localhost/index.ts +++ b/src/utils/settingsValidation/localhost/index.ts @@ -7,7 +7,7 @@ import { LOCALHOST_MODE } from '../../constants'; * * @param {any} settings config object provided by the user to initialize the sdk * - * @returns {Object | undefined} valid localhost mode module, or undefined if the provided one is not provided or invalid. + * @returns {Object | undefined} provided localhost mode module at `settings.sync.localhostMode`, or undefined if no module is provided or is invalid. */ export function validateLocalhost(settings: ISettings) { const localhostMode = settings.sync.localhostMode; From 9addabc236baed80e4f46e18f7d9d62ca9537c99 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 14 Oct 2021 14:33:57 -0300 Subject: [PATCH 7/8] polishing --- src/utils/settingsValidation/index.ts | 21 ++++++++++--------- .../settingsValidation/localhost/index.ts | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/utils/settingsValidation/index.ts b/src/utils/settingsValidation/index.ts index 2a211f90..1840fdb5 100644 --- a/src/utils/settingsValidation/index.ts +++ b/src/utils/settingsValidation/index.ts @@ -111,17 +111,18 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV withDefaults.log = log; // Scheduler periods - withDefaults.scheduler.featuresRefreshRate = fromSecondsToMillis(withDefaults.scheduler.featuresRefreshRate); - withDefaults.scheduler.segmentsRefreshRate = fromSecondsToMillis(withDefaults.scheduler.segmentsRefreshRate); - withDefaults.scheduler.metricsRefreshRate = fromSecondsToMillis(withDefaults.scheduler.metricsRefreshRate); - withDefaults.scheduler.impressionsRefreshRate = fromSecondsToMillis(withDefaults.scheduler.impressionsRefreshRate); - withDefaults.scheduler.offlineRefreshRate = fromSecondsToMillis(withDefaults.scheduler.offlineRefreshRate); - withDefaults.scheduler.eventsPushRate = fromSecondsToMillis(withDefaults.scheduler.eventsPushRate); + const { scheduler, startup } = withDefaults; + scheduler.featuresRefreshRate = fromSecondsToMillis(scheduler.featuresRefreshRate); + scheduler.segmentsRefreshRate = fromSecondsToMillis(scheduler.segmentsRefreshRate); + scheduler.metricsRefreshRate = fromSecondsToMillis(scheduler.metricsRefreshRate); + scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate); + scheduler.offlineRefreshRate = fromSecondsToMillis(scheduler.offlineRefreshRate); + scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate); // Startup periods - withDefaults.startup.requestTimeoutBeforeReady = fromSecondsToMillis(withDefaults.startup.requestTimeoutBeforeReady); - withDefaults.startup.readyTimeout = fromSecondsToMillis(withDefaults.startup.readyTimeout); - withDefaults.startup.eventsFirstPushWindow = fromSecondsToMillis(withDefaults.startup.eventsFirstPushWindow); + startup.requestTimeoutBeforeReady = fromSecondsToMillis(startup.requestTimeoutBeforeReady); + startup.readyTimeout = fromSecondsToMillis(startup.readyTimeout); + startup.eventsFirstPushWindow = fromSecondsToMillis(withDefaults.startup.eventsFirstPushWindow); // ensure a valid SDK mode // @ts-ignore, modify readonly prop @@ -152,7 +153,7 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV withDefaults.streamingEnabled = true; // Backoff bases. // We are not checking if bases are positive numbers. Thus, we might be reauthenticating immediately (`setTimeout` with NaN or negative number) - withDefaults.scheduler.pushRetryBackoffBase = fromSecondsToMillis(withDefaults.scheduler.pushRetryBackoffBase); + scheduler.pushRetryBackoffBase = fromSecondsToMillis(scheduler.pushRetryBackoffBase); } // validate the `splitFilters` settings and parse splits query diff --git a/src/utils/settingsValidation/localhost/index.ts b/src/utils/settingsValidation/localhost/index.ts index b97b320b..7d5f9272 100644 --- a/src/utils/settingsValidation/localhost/index.ts +++ b/src/utils/settingsValidation/localhost/index.ts @@ -7,7 +7,7 @@ import { LOCALHOST_MODE } from '../../constants'; * * @param {any} settings config object provided by the user to initialize the sdk * - * @returns {Object | undefined} provided localhost mode module at `settings.sync.localhostMode`, or undefined if no module is provided or is invalid. + * @returns {Object | undefined} provided localhost mode module at `settings.sync.localhostMode`, or undefined if it is not provided or invalid. */ export function validateLocalhost(settings: ISettings) { const localhostMode = settings.sync.localhostMode; From 8a1d5ecd1cf734dc2456134b5264c2cca86217d1 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 14 Oct 2021 17:16:32 -0300 Subject: [PATCH 8/8] more polishing --- package-lock.json | 2 +- package.json | 2 +- src/sdkFactory/types.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a8317261..a5324ded 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "0.1.1-rc.19", + "version": "0.1.1-rc.20", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 353d90fc..d85878ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "0.1.1-rc.19", + "version": "0.1.1-rc.20", "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 ce5981ce..b0d87343 100644 --- a/src/sdkFactory/types.ts +++ b/src/sdkFactory/types.ts @@ -40,7 +40,7 @@ export interface ISdkFactoryParams { splitApiFactory?: (settings: ISettings, platform: IPlatform) => ISplitApi, // SyncManager factory. - // It is not required when providing an asynchronous storage. + // Not required when providing an asynchronous storage (consumer mode), but required in standalone mode to avoid SDK timeout. // It can create an offline or online sync manager, with or without streaming support. syncManagerFactory?: (params: ISyncManagerFactoryParams) => ISyncManager,