Skip to content

Commit

Permalink
Break out Store and config processing
Browse files Browse the repository at this point in the history
  • Loading branch information
alexs-mparticle committed Apr 5, 2024
1 parent b2b9f74 commit a34f3d5
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 63 deletions.
49 changes: 1 addition & 48 deletions src/mp-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -1289,33 +1289,8 @@ function completeSDKInitialization(apiKey, config, mpInstance) {

mpInstance._APIClient = new APIClient(mpInstance, kitBlocker);
mpInstance._Forwarders = new Forwarders(mpInstance, kitBlocker);
if (config.flags) {
if (
config.flags.hasOwnProperty(
Constants.FeatureFlags.EventBatchingIntervalMillis
)
) {
mpInstance._Store.SDKConfig.flags[
Constants.FeatureFlags.EventBatchingIntervalMillis
] =
config.flags[
Constants.FeatureFlags.EventBatchingIntervalMillis
];
}
}
mpInstance._Store.processConfig(config);

// add a new function to apply items to the store that require config to be returned
mpInstance._Store.storageName = mpInstance._Helpers.createMainStorageName(
config.workspaceToken
);
mpInstance._Store.prodStorageName = mpInstance._Helpers.createProductStorageName(
config.workspaceToken
);

// idCache is instantiated here as opposed to when _Identity is instantiated
// because it depends on _Store.storageName, which is not sent until above
// because it is a setting on config which returns asyncronously
// in self hosted mode
mpInstance._Identity.idCache = new LocalStorageVault(
`${mpInstance._Store.storageName}-id-cache`,
{
Expand All @@ -1325,28 +1300,6 @@ function completeSDKInitialization(apiKey, config, mpInstance) {

removeExpiredIdentityCacheDates(mpInstance._Identity.idCache);

if (config.hasOwnProperty('workspaceToken')) {
mpInstance._Store.SDKConfig.workspaceToken = config.workspaceToken;
} else {
mpInstance.Logger.warning(
'You should have a workspaceToken on your config object for security purposes.'
);
}

if (config.hasOwnProperty('requiredWebviewBridgeName')) {
mpInstance._Store.SDKConfig.requiredWebviewBridgeName =
config.requiredWebviewBridgeName;
} else if (config.hasOwnProperty('workspaceToken')) {
mpInstance._Store.SDKConfig.requiredWebviewBridgeName =
config.workspaceToken;
}
mpInstance._Store.webviewBridgeEnabled = mpInstance._NativeSdkHelpers.isWebviewEnabled(
mpInstance._Store.SDKConfig.requiredWebviewBridgeName,
mpInstance._Store.SDKConfig.minWebviewBridgeVersion
);

mpInstance._Store.configurationLoaded = true;

// https://go.mparticle.com/work/SQDSDKS-6044
if (!mpInstance._Store.webviewBridgeEnabled) {
// Load any settings/identities/attributes from cookie or localStorage
Expand Down
2 changes: 2 additions & 0 deletions src/sdkRuntimeModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ export interface SDKIdentityApi {

export interface SDKHelpersApi {
canLog?(): boolean;
createMainStorageName?(workspaceToken: string): string;
createProductStorageName?(workspaceToken: string): string;
createServiceUrl(arg0: string, arg1: string): void;
createXHR?(cb: () => void): XMLHttpRequest;
extend?(...args: any[]);
Expand Down
49 changes: 42 additions & 7 deletions src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ export interface SDKConfig {
v1SecureServiceUrl?: string;
v2SecureServiceUrl?: string;
v3SecureServiceUrl?: string;
webviewBridgeName?: string;
workspaceToken?: string;
requiredWebviewBridgeName?: string;
}

function createSDKConfig(config: SDKInitConfig): SDKConfig {
Expand Down Expand Up @@ -112,7 +115,7 @@ interface WrapperSDKInfo {

// https://go.mparticle.com/work/SQDSDKS-5954
export interface IFeatureFlags {
reportBatching?: string;
reportBatching?: boolean;
eventBatchingIntervalMillis?: number;
offlineStorage?: string;
directURLRouting?: boolean;
Expand Down Expand Up @@ -164,6 +167,7 @@ export interface IStore {
wrapperSDKInfo: WrapperSDKInfo;

nullifySession?: () => void;
processConfig(config: SDKInitConfig): void;
}

// TODO: Merge this with SDKStoreApi in sdkRuntimeModels
Expand All @@ -173,6 +177,11 @@ export default function Store(
mpInstance: MParticleWebSDK,
apiKey?: string
) {
const { createMainStorageName, createProductStorageName } =
mpInstance._Helpers;

const { isWebviewEnabled } = mpInstance._NativeSdkHelpers;

const defaultStore: Partial<IStore> = {
isEnabled: true,
sessionAttributes: {},
Expand Down Expand Up @@ -233,8 +242,7 @@ export default function Store(
this.SDKConfig.flags = {};
}

this.SDKConfig.flags = processFlags(config, this
.SDKConfig as SDKConfig);
this.SDKConfig.flags = processFlags(config);

if (config.deviceId) {
this.deviceId = config.deviceId;
Expand Down Expand Up @@ -427,12 +435,38 @@ export default function Store(
this.sessionAttributes = {};
mpInstance._Persistence.update();
};

this.processConfig = (config: SDKInitConfig) => {
const { workspaceToken, requiredWebviewBridgeName } = config;

// TODO: refactor to use flags directly
this.SDKConfig.flags = processFlags(config);

if (workspaceToken) {
this.SDKConfig.workspaceToken = workspaceToken;
} else {
mpInstance.Logger.warning(
'You should have a workspaceToken on your config object for security purposes.'
);
}
// add a new function to apply items to the store that require config to be returned
this.storageName = createMainStorageName(workspaceToken);
this.prodStorageName = createProductStorageName(workspaceToken);

this.SDKConfig.requiredWebviewBridgeName =
requiredWebviewBridgeName || workspaceToken;

this.webviewBridgeEnabled = isWebviewEnabled(
this.SDKConfig.requiredWebviewBridgeName,
this.SDKConfig.minWebviewBridgeVersion
);

this.configurationLoaded = true;
};
}

export function processFlags(
config: SDKInitConfig,
SDKConfig: SDKConfig
): IFeatureFlags {
// TODO: Refactor to use flags directly
export function processFlags(config: SDKInitConfig): IFeatureFlags {
const flags: IFeatureFlags = {};
const {
ReportBatching,
Expand All @@ -446,6 +480,7 @@ export function processFlags(
return {};
}

// https://go.mparticle.com/work/SQDSDKS-6317
// Passed in config flags take priority over defaults
flags[ReportBatching] = config.flags[ReportBatching] || false;
// The server returns stringified numbers, sowe need to parse
Expand Down
170 changes: 162 additions & 8 deletions test/src/tests-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,19 +341,173 @@ describe('Store', () => {
});
});

describe('#processConfig', () => {
it('should process feature flags', () => {
const config = {
...sampleConfig,
flags: {
reportBatching: false, // This should be a string
eventBatchingIntervalMillis: '42000',
offlineStorage: '42',
directURLRouting: 'False',
cacheIdentity: 'False',
},
};

const store: IStore = new Store(
config,
window.mParticle.getInstance()
);

store.processConfig(config);

const expectedResult = {
reportBatching: false,
eventBatchingIntervalMillis: 42000,
offlineStorage: '42',
directURLRouting: false,
cacheIdentity: false,
};

// TODO: This passes even though we're only doing this in the constructor.
// Should we move the processFlags call into this method?
expect(store.SDKConfig.flags).to.deep.equal(expectedResult);
});

it('should process storage names', () => {
const config = {
...sampleConfig,
workspaceToken: 'foo',
};

const store: IStore = new Store(
config,
window.mParticle.getInstance()
);

store.processConfig(config);

expect(store.storageName, 'storageName').to.equal('mprtcl-v4_foo');
expect(store.prodStorageName, 'prodStorageName').to.equal(
'mprtcl-prodv4_foo'
);
expect(store.SDKConfig.workspaceToken, 'workspace token').to.equal(
'foo'
);
});

it('should warn if workspace token is missing', () => {
const config = {
...sampleConfig,
};

const store: IStore = new Store(
config,
window.mParticle.getInstance()
);

const warnSpy = sinon.spy(
window.mParticle.getInstance().Logger,
'warning'
);

store.processConfig(config);

expect(warnSpy.calledOnce, 'should call Logger.warn').to.be.true;
expect(warnSpy.getCall(0).firstArg).to.equal(
'You should have a workspaceToken on your config object for security purposes.'
);
});

it('should use a Web View Bridge Name if requiredWebviewBridgeName is present', () => {
const config = {
...sampleConfig,
requiredWebviewBridgeName: 'my-webview-bridge-name',
workspaceToken: 'my-workspace-token',
};

const store: IStore = new Store(
config,
window.mParticle.getInstance()
);

debugger;

store.processConfig(config);

expect(
store.SDKConfig.requiredWebviewBridgeName,
'webviewBridgeName'
).to.equal('my-webview-bridge-name');
});

it('should use a workspace token as the Web View Bridge Name if requiredWebviewBridgeName is not present ', () => {
const config = {
...sampleConfig,
workspaceToken: 'my-workspace-token',
};

const store: IStore = new Store(
config,
window.mParticle.getInstance()
);

store.processConfig(config);

expect(
store.SDKConfig.requiredWebviewBridgeName,
'webviewBridgeName'
).to.equal('my-workspace-token');
});

it('should enable WebviewBridge if requiredWebviewBridgeName is present', () => {
const config = {
...sampleConfig,
requiredWebviewBridgeName: 'my-webview-bridge-name',
};

const store: IStore = new Store(
config,
window.mParticle.getInstance()
);

// Webview bridge requires a bridge name set on the global mParticle object
// @ts-ignore
window.mParticle.uiwebviewBridgeName =
'mParticle_my-webview-bridge-name_v2';

store.processConfig(config);

expect(store.webviewBridgeEnabled, 'webviewBridgeEnabled').to.be
.true;
});

it('should set configurationLoaded to true if config is successfully processed', () => {
const config = {
...sampleConfig,
};

const store: IStore = new Store(
config,
window.mParticle.getInstance()
);

store.processConfig(config);

expect(store.configurationLoaded, 'configurationLoaded').to.be.true;
});
});

describe('#processFlags', () => {
it('should return an empty object if no featureFlags are passed', () => {
const flags = processFlags({} as SDKInitConfig, {} as SDKConfig);
const flags = processFlags({} as SDKInitConfig);
expect(Object.keys(flags).length).to.equal(0);
});

it('should return default featureFlags if no featureFlags are passed', () => {
const flags = processFlags(
{ flags: {} } as SDKInitConfig,
{} as SDKConfig
);
const flags = processFlags({ flags: {} } as SDKInitConfig);
const expectedResult = {
reportBatching: false,
reportBatching: false, // This should be a string
eventBatchingIntervalMillis: 0,
offlineStorage: '0',
directURLRouting: false,
Expand All @@ -365,8 +519,8 @@ describe('Store', () => {

it('should return featureFlags if featureFlags are passed in', () => {
const cutomizedFlags = {
reportBatching: true,
eventBatchingIntervalMillis: 5000,
reportBatching: true, // This should be a string
eventBatchingIntervalMillis: '5000',
offlineStorage: '100',
directURLRouting: 'True',
cacheIdentity: 'True',
Expand Down

0 comments on commit a34f3d5

Please sign in to comment.