@segment/analytics-next
Version:
Analytics Next (aka Analytics 2.0) is the latest version of Segment’s JavaScript SDK - enabling you to send your data to any tool without having to learn, test, or use a new API every time.
79 lines (67 loc) • 2.16 kB
text/typescript
import { Store, StorageObject } from './types'
// not adding to private method because those method names do not get minified atm, and does not use 'this'
const _logStoreKeyError = (
store: Store,
action: 'set' | 'get' | 'remove',
key: string,
err: unknown
) => {
console.warn(
`${store.constructor.name}: Can't ${action} key "${key}" | Err: ${err}`
)
}
/**
* Uses multiple storages in a priority list to get/set values in the order they are specified.
*/
export class UniversalStorage<Data extends StorageObject = StorageObject> {
private stores: Store[]
constructor(stores: Store[]) {
this.stores = stores
}
get<K extends keyof Data>(key: K): Data[K] | null {
let val: Data[K] | null = null
for (const store of this.stores) {
try {
val = store.get(key) as Data[K] | null
if (val !== undefined && val !== null) {
return val
}
} catch (e) {
_logStoreKeyError(store, 'get', key, e)
}
}
return null
}
set<K extends keyof Data>(key: K, value: Data[K] | null): void {
this.stores.forEach((store) => {
try {
store.set(key, value)
} catch (e) {
_logStoreKeyError(store, 'set', key, e)
}
})
}
clear<K extends keyof Data>(key: K): void {
this.stores.forEach((store) => {
try {
store.remove(key)
} catch (e) {
_logStoreKeyError(store, 'remove', key, e)
}
})
}
/*
This is to support few scenarios where:
- value exist in one of the stores ( as a result of other stores being cleared from browser ) and we want to resync them
- read values in AJS 1.0 format ( for customers after 1.0 --> 2.0 migration ) and then re-write them in AJS 2.0 format
*/
getAndSync<K extends keyof Data>(key: K): Data[K] | null {
const val = this.get(key)
// legacy behavior, getAndSync can change the type of a value from number to string (AJS 1.0 stores numerical values as a number)
const coercedValue = (typeof val === 'number' ? val.toString() : val) as
| Data[K]
| null
this.set(key, coercedValue)
return coercedValue
}
}