Skip to content

Commit

Permalink
remove caching logic for availability, refactored the universal storage
Browse files Browse the repository at this point in the history
  • Loading branch information
pooyaj committed Dec 7, 2022
1 parent 01849dd commit 1e71aa5
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 75 deletions.
9 changes: 6 additions & 3 deletions packages/browser/src/core/analytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { Plugin } from '../plugin'
import { EventQueue } from '../queue/event-queue'
import {
CookieOptions,
getAvailableStorageOptions,
Group,
ID,
UniversalStorage,
Expand Down Expand Up @@ -133,9 +134,11 @@ export class Analytics
this.queue =
queue ?? createDefaultQueue(options?.retryQueue, disablePersistance)

this._universalStorage = UniversalStorage.getUniversalStorage(
disablePersistance ? ['memory'] : ['cookie', 'localStorage', 'memory'],
cookieOptions
this._universalStorage = new UniversalStorage(
disablePersistance !== false
? ['localStorage', 'cookie', 'memory']
: ['memory'],
getAvailableStorageOptions(cookieOptions)
)

this._user =
Expand Down
59 changes: 36 additions & 23 deletions packages/browser/src/core/user/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Group,
UniversalStorage,
StoreType,
getAvailableStorageOptions,
} from '..'
import jar from 'js-cookie'
import assert from 'assert'
Expand Down Expand Up @@ -956,49 +957,54 @@ describe('universal storage', function () {
it('picks data from cookies first', function () {
jar.set('ajs_test_key', '🍪')
localStorage.setItem('ajs_test_key', '💾')
const us = UniversalStorage.getUniversalStorage(defaultTargets)
const us = new UniversalStorage(
defaultTargets,
getAvailableStorageOptions()
)
expect(us.get('ajs_test_key')).toEqual('🍪')
})

it('picks data from localStorage if there is no cookie target', function () {
jar.set('ajs_test_key', '🍪')
localStorage.setItem('ajs_test_key', '💾')
const us = UniversalStorage.getUniversalStorage([
'localStorage',
'memory',
])
const us = new UniversalStorage(
['localStorage', 'memory'],
getAvailableStorageOptions()
)
expect(us.get('ajs_test_key')).toEqual('💾')
})

it('get data from memory', function () {
jar.set('ajs_test_key', '🍪')
localStorage.setItem('ajs_test_key', '💾')
const us = UniversalStorage.getUniversalStorage(['memory'])
const us = new UniversalStorage(['memory'], getAvailableStorageOptions())
expect(us.get('ajs_test_key')).toBeNull()
})

it('order of default targets does not matter', function () {
it('order of default targets matters!', function () {
jar.set('ajs_test_key', '🍪')
localStorage.setItem('ajs_test_key', '💾')
const us = UniversalStorage.getUniversalStorage([
'localStorage',
'cookie',
'memory',
])
const us = new UniversalStorage(
['cookie', 'localStorage', 'memory'],
getAvailableStorageOptions()
)
expect(us.get('ajs_test_key')).toEqual('🍪')
})

it('returns null if there are no storage targets', function () {
jar.set('ajs_test_key', '🍪')
localStorage.setItem('ajs_test_key', '💾')
const us = UniversalStorage.getUniversalStorage([])
const us = new UniversalStorage([], getAvailableStorageOptions())
expect(us.get('ajs_test_key')).toBeNull()
})

it('can override the default targets', function () {
jar.set('ajs_test_key', '🍪')
localStorage.setItem('ajs_test_key', '💾')
const us = UniversalStorage.getUniversalStorage(defaultTargets)
const us = new UniversalStorage(
defaultTargets,
getAvailableStorageOptions()
)
expect(us.get('ajs_test_key', ['localStorage'])).toEqual('💾')
expect(us.get('ajs_test_key', ['localStorage', 'memory'])).toEqual('💾')
expect(us.get('ajs_test_key', ['cookie', 'memory'])).toEqual('🍪')
Expand All @@ -1010,41 +1016,48 @@ describe('universal storage', function () {

describe('#set', function () {
it('set the data in all storage types', function () {
const us = UniversalStorage.getUniversalStorage<{ ajs_test_key: string }>(
defaultTargets
const us = new UniversalStorage<{ ajs_test_key: string }>(
defaultTargets,
getAvailableStorageOptions()
)
us.set('ajs_test_key', '💰')
expect(jar.get('ajs_test_key')).toEqual('💰')
expect(getFromLS('ajs_test_key')).toEqual('💰')
})

it('skip saving data to localStorage', function () {
const us = UniversalStorage.getUniversalStorage(['cookie', 'memory'])
const us = new UniversalStorage(
['cookie', 'memory'],
getAvailableStorageOptions()
)
us.set('ajs_test_key', '💰')
expect(jar.get('ajs_test_key')).toEqual('💰')
expect(localStorage.getItem('ajs_test_key')).toEqual(null)
})

it('skip saving data to cookie', function () {
const us = UniversalStorage.getUniversalStorage([
'localStorage',
'memory',
])
const us = new UniversalStorage(
['localStorage', 'memory'],
getAvailableStorageOptions()
)
us.set('ajs_test_key', '💰')
expect(jar.get('ajs_test_key')).toEqual(undefined)
expect(getFromLS('ajs_test_key')).toEqual('💰')
})

it('can save and retrieve from memory when there is no other storage', function () {
const us = UniversalStorage.getUniversalStorage(['memory'])
const us = new UniversalStorage(['memory'], getAvailableStorageOptions())
us.set('ajs_test_key', '💰')
expect(jar.get('ajs_test_key')).toEqual(undefined)
expect(localStorage.getItem('ajs_test_key')).toEqual(null)
expect(us.get('ajs_test_key')).toEqual('💰')
})

it('can override the default targets', function () {
const us = UniversalStorage.getUniversalStorage(defaultTargets)
const us = new UniversalStorage(
defaultTargets,
getAvailableStorageOptions()
)
us.set('ajs_test_key', '💰', ['localStorage'])
expect(jar.get('ajs_test_key')).toEqual(undefined)
expect(getFromLS('ajs_test_key')).toEqual('💰')
Expand Down
84 changes: 38 additions & 46 deletions packages/browser/src/core/user/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,7 @@ class Store {
const ONE_YEAR = 365

export class Cookie extends Store {
static _available: boolean | undefined
static available(): boolean {
if (Cookie._available !== undefined) {
return Cookie._available
}

let cookieEnabled = window.navigator.cookieEnabled

if (!cookieEnabled) {
Expand All @@ -76,8 +71,6 @@ export class Cookie extends Store {
jar.remove('ajs:cookies')
}

Cookie._available = cookieEnabled

return cookieEnabled
}

Expand Down Expand Up @@ -153,21 +146,13 @@ const localStorageWarning = (key: string, state: 'full' | 'unavailable') => {
}

export class LocalStorage extends Store {
static _available: boolean | undefined

static available(): boolean {
if (LocalStorage._available !== undefined) {
return LocalStorage._available
}

const test = 'test'
try {
localStorage.setItem(test, test)
localStorage.removeItem(test)
LocalStorage._available = true
return true
} catch (e) {
LocalStorage._available = false
return false
}
}
Expand Down Expand Up @@ -221,16 +206,26 @@ export interface CookieOptions {
}

export class UniversalStorage<Data extends StorageObject = StorageObject> {
private stores: Store[]
private enabledStores: StoreType[]
private storageOptions: StorageOptions

constructor(stores?: Store[]) {
this.stores = stores || []
constructor(stores: StoreType[], storageOptions: StorageOptions) {
this.storageOptions = storageOptions
this.enabledStores = stores
}

private getStores(storeTypes: StoreType[] | undefined): Store[] {
return storeTypes
? this.stores.filter((s) => storeTypes.indexOf(s.type) !== -1)
: this.stores
const stores: Store[] = []
this.enabledStores
.filter((i) => !storeTypes || storeTypes?.includes(i))
.forEach((storeType) => {
const storage = this.storageOptions[storeType]
if (storage !== undefined) {
stores.push(storage)
}
})

return stores
}

/*
Expand Down Expand Up @@ -283,26 +278,21 @@ export class UniversalStorage<Data extends StorageObject = StorageObject> {
store.remove(key)
}
}
}

static getUniversalStorage<T extends Record<string, unknown>>(
defaultTargets: StoreType[] = ['cookie', 'localStorage', 'memory'],
cookieOptions?: CookieOptions
): UniversalStorage<T> {
const stores = []

if (defaultTargets.includes('cookie') && Cookie.available()) {
stores.push(new Cookie(cookieOptions))
}

if (defaultTargets.includes('localStorage') && LocalStorage.available()) {
stores.push(new LocalStorage())
}

if (defaultTargets.includes('memory')) {
stores.push(new Store())
}
type StorageOptions = {
cookie: Cookie | undefined
localStorage: LocalStorage | undefined
memory: Store
}

return new UniversalStorage<T>(stores)
export function getAvailableStorageOptions(
cookieOptions?: CookieOptions
): StorageOptions {
return {
cookie: Cookie.available() ? new Cookie(cookieOptions) : undefined,
localStorage: LocalStorage.available() ? new LocalStorage() : undefined,
memory: new Store(),
}
}

Expand Down Expand Up @@ -346,32 +336,34 @@ export class User {
let defaultStorageTargets: StoreType[] = isDisabled
? []
: shouldPersist
? ['cookie', 'localStorage', 'memory']
? ['localStorage', 'cookie', 'memory']
: ['memory']

const storageOptions = getAvailableStorageOptions(cookieOptions)

if (options.localStorageFallbackDisabled) {
defaultStorageTargets = defaultStorageTargets.filter(
(t) => t !== 'localStorage'
)
}

this.identityStore = UniversalStorage.getUniversalStorage(
this.identityStore = new UniversalStorage(
defaultStorageTargets,
cookieOptions
storageOptions
)

// using only cookies for legacy user store
this.legacyUserStore = UniversalStorage.getUniversalStorage(
this.legacyUserStore = new UniversalStorage(
defaultStorageTargets.filter(
(t) => t !== 'localStorage' && t !== 'memory'
),
cookieOptions
storageOptions
)

// using only localStorage / memory for traits store
this.traitsStore = UniversalStorage.getUniversalStorage(
this.traitsStore = new UniversalStorage(
defaultStorageTargets.filter((t) => t !== 'cookie'),
cookieOptions
storageOptions
)

const legacyUser = this.legacyUserStore.get(defaults.cookie.oldKey)
Expand Down
9 changes: 6 additions & 3 deletions packages/browser/src/plugins/segmentio/normalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { tld } from '../../core/user/tld'
import { SegmentFacade } from '../../lib/to-facade'
import { SegmentioSettings } from './index'
import { version } from '../../generated/version'
import { UniversalStorage } from '../../core/user'
import { getAvailableStorageOptions, UniversalStorage } from '../../core/user'

let cookieOptions: jar.CookieAttributes | undefined
function getCookieOptions(): jar.CookieAttributes {
Expand Down Expand Up @@ -95,9 +95,12 @@ function referrerId(
ctx: SegmentEvent['context'],
disablePersistance: boolean
): void {
const storage = UniversalStorage.getUniversalStorage<{
const storage = new UniversalStorage<{
's:context.referrer': Ad
}>(disablePersistance ? [] : ['cookie'], getCookieOptions())
}>(
disablePersistance ? [] : ['cookie'],
getAvailableStorageOptions(getCookieOptions())
)

const stored = storage.get('s:context.referrer')
let ad: Ad | undefined | null = ads(query)
Expand Down

0 comments on commit 1e71aa5

Please sign in to comment.