react-native-mmkv
Version:
⚡️ The fastest key/value storage for React Native.
145 lines (144 loc) • 5.11 kB
JavaScript
import { createTextDecoder } from '../web/createTextDecoder';
import { createTextEncoder } from '../web/createTextEncoder';
import { getLocalStorage, LOCAL_STORAGE_KEY_WILDCARD, } from '../web/getLocalStorage';
export function createMMKV(config = { id: 'mmkv.default' }) {
if (config.encryptionKey != null) {
throw new Error("MMKV: 'encryptionKey' is not supported on Web!");
}
if (config.path != null) {
throw new Error("MMKV: 'path' is not supported on Web!");
}
const textDecoder = createTextDecoder();
const textEncoder = createTextEncoder();
const listeners = new Set();
if (config.id.includes(LOCAL_STORAGE_KEY_WILDCARD)) {
throw new Error('MMKV: `id` cannot contain the backslash character (`\\`)!');
}
const keyPrefix = `${config.id}${LOCAL_STORAGE_KEY_WILDCARD}`; // mmkv.default\\
const prefixedKey = (key) => {
if (key.includes('\\')) {
throw new Error('MMKV: `key` cannot contain the backslash character (`\\`)!');
}
return `${keyPrefix}${key}`;
};
const callListeners = (key) => {
listeners.forEach((l) => l(key));
};
return {
id: config.id,
get length() {
return getLocalStorage().length;
},
get size() {
return this.byteSize;
},
get byteSize() {
// estimate - assumes UTF8
return JSON.stringify(getLocalStorage()).length;
},
isReadOnly: false,
isEncrypted: false,
clearAll: () => {
const storage = getLocalStorage();
const keys = Object.keys(storage);
for (const key of keys) {
if (key.startsWith(keyPrefix)) {
storage.removeItem(key);
callListeners(key);
}
}
},
remove: (key) => {
const storage = getLocalStorage();
storage.removeItem(prefixedKey(key));
const wasRemoved = storage.getItem(prefixedKey(key)) === null;
if (wasRemoved)
callListeners(key);
return wasRemoved;
},
set: (key, value) => {
const storage = getLocalStorage();
if (key === '')
throw new Error('Cannot set a value for an empty key!');
if (value instanceof ArrayBuffer) {
storage.setItem(prefixedKey(key), textDecoder.decode(value));
}
else {
storage.setItem(prefixedKey(key), String(value));
}
callListeners(key);
},
getString: (key) => {
const storage = getLocalStorage();
return storage.getItem(prefixedKey(key)) ?? undefined;
},
getNumber: (key) => {
const storage = getLocalStorage();
const value = storage.getItem(prefixedKey(key));
if (value == null)
return undefined;
return Number(value);
},
getBoolean: (key) => {
const storage = getLocalStorage();
const value = storage.getItem(prefixedKey(key));
if (value == null)
return undefined;
return value === 'true';
},
getBuffer: (key) => {
const storage = getLocalStorage();
const value = storage.getItem(prefixedKey(key));
if (value == null)
return undefined;
return textEncoder.encode(value).buffer;
},
getAllKeys: () => {
const storage = getLocalStorage();
const keys = Object.keys(storage);
return keys
.filter((key) => key.startsWith(keyPrefix))
.map((key) => key.slice(keyPrefix.length));
},
contains: (key) => {
const storage = getLocalStorage();
return storage.getItem(prefixedKey(key)) != null;
},
recrypt: () => {
throw new Error('`recrypt(..)` is not supported on Web!');
},
encrypt: () => {
throw new Error('`encrypt(..)` is not supported on Web!');
},
decrypt: () => {
throw new Error('`decrypt(..)` is not supported on Web!');
},
trim: () => {
// no-op
},
dispose: () => { },
equals: () => false,
name: 'MMKV',
addOnValueChangedListener: (listener) => {
listeners.add(listener);
return {
remove: () => {
listeners.delete(listener);
},
};
},
importAllFrom: (other) => {
const storage = getLocalStorage();
const keys = other.getAllKeys();
let imported = 0;
for (const key of keys) {
const string = other.getString(key);
if (string != null) {
storage.set(key, string);
imported++;
}
}
return imported;
},
};
}