@applicaster/zapp-react-native-utils
Version:
Applicaster Zapp React Native utilities package
109 lines (82 loc) • 3.18 kB
text/typescript
import { bridgeLogger } from "../../zapp-react-native-bridge/logger";
import { BehaviorSubject } from "rxjs";
import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
import { getNamespaceAndKey } from "../appUtils/contextKeysManager/utils";
import { createLogger } from "../logger";
export const { log_verbose, log_debug, log_warning, log_info, log_error } =
createLogger({
category: "StorageSingleValueProvider",
subsystem: "zapp-react-native-bridge",
parent: bridgeLogger,
});
export interface SingleValueProvider {
getObservable(): BehaviorSubject<string | null>;
setValue(value: string): Promise<void>;
getValue(): string | null;
getValueAsync(): Promise<string | null>;
clearValue(): Promise<void>;
}
interface StorageListenerArgs {
value: string | null;
}
export class StorageSingleValueProvider implements SingleValueProvider {
// Static cache of providers by namespace
private static singleValueProviders: Record<
string,
StorageSingleValueProvider
> = {};
public static getProvider(keyNamespace: string): SingleValueProvider {
if (!this.singleValueProviders[keyNamespace]) {
this.singleValueProviders[keyNamespace] = new StorageSingleValueProvider(
keyNamespace
);
}
return this.singleValueProviders[keyNamespace];
}
private valueSubject: BehaviorSubject<string | null>;
private readonly key: string;
private readonly namespace: string;
private constructor(keyNamespace: string) {
const { namespace, key } = getNamespaceAndKey(keyNamespace);
if (!key) {
throw new Error("StorageSingleValueProvider: Key is required");
}
this.key = key;
this.namespace = namespace;
localStorage.addListener?.({ key, namespace }, this.reloadValue);
this.valueSubject = new BehaviorSubject<string | null>(null);
void this.getValueAsync();
log_debug("StorageSingleValueProvider: Initializing");
}
private reloadValue = async ({ value }: StorageListenerArgs) => {
log_debug(`reloadValue: request to reload value: ${value}`);
this.valueSubject.next(value);
};
public getObservable = (): BehaviorSubject<string | null> =>
this.valueSubject;
private async updateValueAndNotifyObservers(value: string | null) {
if (value === null) {
await localStorage.removeItem(this.key, this.namespace);
} else {
await localStorage.setItem(this.key, value, this.namespace);
}
this.valueSubject.next(value);
}
public setValue = async (value: string): Promise<void> => {
log_debug(`setValue: Setting new value: ${value}`);
await this.updateValueAndNotifyObservers(value);
};
public clearValue = async (): Promise<void> => {
await localStorage.removeItem(this.key, this.namespace);
log_debug("clearValue: Removing value");
this.valueSubject.next(null);
};
public getValueAsync = async (): Promise<string | null> => {
const value = await localStorage.getItem(this.key, this.namespace);
this.valueSubject.next(value);
return value;
};
public getValue = (): string | null => {
return this.valueSubject.getValue();
};
}