Skip to content
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
b32bee3
Upgrade package
Rohit3523 Feb 18, 2026
c27b5a6
changes
Rohit3523 Feb 18, 2026
6383fc4
Switch to multiple process
Rohit3523 Feb 18, 2026
1f814c8
use io.github.zhongwuzw:mmkv:2.2.4 same as rn-mmkv
Rohit3523 Feb 18, 2026
00c9243
pod fix
Rohit3523 Feb 18, 2026
4c85880
Added mmkv core
Rohit3523 Feb 18, 2026
1c6178b
patch update
Rohit3523 Feb 18, 2026
c3e9b3c
mmkv mock update
Rohit3523 Feb 18, 2026
cedff47
chore: format code and fix lint issues
Rohit3523 Feb 18, 2026
d8ec476
rerun
Rohit3523 Feb 18, 2026
e4bf516
revert
Rohit3523 Feb 18, 2026
c9865c0
Merge branch 'develop' into mmkv-v4
Rohit3523 Mar 24, 2026
1415283
chore: format code and fix lint issues
Rohit3523 Mar 24, 2026
2b51682
Merge branch 'develop' into mmkv-v4
Rohit3523 Apr 7, 2026
1fa540b
podfile lock fixed
Rohit3523 Apr 7, 2026
ece27b0
ios part done...
Rohit3523 Apr 14, 2026
6401432
Merge branch 'develop' into mmkv-v4
Rohit3523 Apr 14, 2026
cd6cd9d
coderabbit suggestions
Rohit3523 Apr 14, 2026
b6e9174
chore: format code and fix lint issues
Rohit3523 Apr 14, 2026
9eb3de4
return mmkv count
Rohit3523 Apr 14, 2026
d33c2e2
Merge branch 'mmkv-v4' of https://github.com/RocketChat/Rocket.Chat.R…
Rohit3523 Apr 14, 2026
f658284
Merge branch 'develop' into mmkv-v4
Rohit3523 Apr 15, 2026
1cbedad
changes
Rohit3523 Apr 15, 2026
c0a0c71
making coderabbit happy
Rohit3523 Apr 15, 2026
a9b51d5
making coderabbit happy
Rohit3523 Apr 15, 2026
6f2a7ba
chore: format code and fix lint issues
Rohit3523 Apr 15, 2026
5663b0f
again making coderabbit happy
Rohit3523 Apr 15, 2026
1e9b808
Merge branch 'mmkv-v4' of https://github.com/RocketChat/Rocket.Chat.R…
Rohit3523 Apr 15, 2026
5e9587c
again making coderabbit happy
Rohit3523 Apr 15, 2026
6695cc5
Merge branch 'develop' into mmkv-v4
Rohit3523 May 5, 2026
04c3103
changes
Rohit3523 May 5, 2026
01cfa30
make it simple
Rohit3523 May 5, 2026
c66edce
Merge branch 'develop' into mmkv-v4
OtavioStasiak May 7, 2026
6524f76
Merge branch 'develop' into mmkv-v4
Rohit3523 May 11, 2026
9d2e57a
changes
Rohit3523 May 11, 2026
a3cf229
Merge branch 'mmkv-v4' of https://github.com/RocketChat/Rocket.Chat.R…
Rohit3523 May 11, 2026
3c97e39
changes
Rohit3523 May 11, 2026
3690323
some comment revert
Rohit3523 May 11, 2026
9517b78
remove duplicate mmkv init
Rohit3523 May 11, 2026
b9c0353
ssl fix for mmkv
Rohit3523 May 12, 2026
59b5225
added path
Rohit3523 May 12, 2026
d12256b
podfile fix
Rohit3523 May 12, 2026
6f04424
remove path
Rohit3523 May 12, 2026
c533a84
remove dead code
Rohit3523 May 13, 2026
3b9a9b0
comment
Rohit3523 May 13, 2026
414b288
fix...
Rohit3523 May 14, 2026
ec8e2fb
revert few changes
Rohit3523 May 14, 2026
f9952cf
change
Rohit3523 May 14, 2026
3369288
revert
Rohit3523 May 14, 2026
50dfefa
Some changes
Rohit3523 May 18, 2026
ff2acff
revert log...
Rohit3523 May 18, 2026
396a897
revert change
Rohit3523 May 18, 2026
e222e36
change
Rohit3523 May 18, 2026
3e3a98d
fix new line
Rohit3523 May 18, 2026
80f3af9
Merge branch 'develop' into mmkv-v4
Rohit3523 May 18, 2026
aae99f8
lock file update
Rohit3523 May 18, 2026
4901078
lock file fixed
Rohit3523 May 18, 2026
2dfb0c4
Update ios/Podfile
Rohit3523 May 19, 2026
c758f94
requested changes
Rohit3523 May 19, 2026
529cc6f
Merge branch 'develop' into mmkv-v4
Rohit3523 May 19, 2026
18a0737
podfile fix
Rohit3523 May 19, 2026
2701559
Merge branch 'mmkv-v4' of https://github.com/RocketChat/Rocket.Chat.R…
Rohit3523 May 19, 2026
1bfb186
sync checksum
Rohit3523 May 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
318 changes: 232 additions & 86 deletions __mocks__/react-native-mmkv.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
// Mock for react-native-mmkv
const { useState, useEffect } = require('react');
const { useState, useEffect, useRef, useMemo, useCallback } = require('react');

// Shared storage between instances with the same id
const storageInstances = new Map();
let defaultInstance = null;

export const Mode = {
SINGLE_PROCESS: 1,
MULTI_PROCESS: 2
SINGLE_PROCESS: 'single-process',
MULTI_PROCESS: 'multi-process'
};

export class MMKV {
// MMKV Instance class
class MMKVInstance {
constructor(config = {}) {
const { id = 'default', mode, path } = config;
const { id = 'mmkv.default', path, encryptionKey, mode, readOnly } = config;
this.id = id;
this.mode = mode;
this.path = path;
this.encryptionKey = encryptionKey;
this.mode = mode;
this.isReadOnly = readOnly || false;
this._size = 0;

Comment thread
coderabbitai[bot] marked this conversation as resolved.
// Share storage between instances with the same id
if (!storageInstances.has(this.id)) {
Expand All @@ -29,8 +34,16 @@ export class MMKV {
this.listeners = instance.listeners;
}

get size() {
return this._size;
}

set(key, value) {
if (this.isReadOnly) {
throw new Error('Cannot set value in read-only instance');
}
this.storage.set(key, value);
this._size = this.storage.size;
this.notifyListeners(key);
}

Expand All @@ -49,13 +62,22 @@ export class MMKV {
return typeof value === 'boolean' ? value : undefined;
}

getBuffer(key) {
const value = this.storage.get(key);
return value instanceof ArrayBuffer ? value : undefined;
}

contains(key) {
return this.storage.has(key);
}

delete(key) {
remove(key) {
if (this.isReadOnly) {
throw new Error('Cannot remove value in read-only instance');
}
const deleted = this.storage.delete(key);
if (deleted) {
this._size = this.storage.size;
this.notifyListeners(key);
}
return deleted;
Expand All @@ -66,11 +88,39 @@ export class MMKV {
}

clearAll() {
if (this.isReadOnly) {
throw new Error('Cannot clear read-only instance');
}
this.storage.clear();
this._size = 0;
// Notify about clear (pass undefined to indicate clear all)
this.notifyListeners(undefined);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

recrypt(key) {
this.encryptionKey = key;
}

trim() {
// No-op for mock
}

importAllFrom(other) {
if (this.isReadOnly) {
throw new Error('Cannot import values into read-only instance');
}
let count = 0;
for (const [key, value] of other.storage.entries()) {
this.storage.set(key, value);
count++;
}
this._size = this.storage.size;
if (count > 0) {
this.notifyListeners(undefined);
}
return count;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

addOnValueChangedListener(callback) {
this.listeners.push(callback);
return {
Expand All @@ -94,106 +144,202 @@ export class MMKV {
}
}

// Export Configuration type for TypeScript
export const Configuration = {};
// Factory function to create MMKV instances
export function createMMKV(configuration) {
return new MMKVInstance(configuration);
}

// React hooks for MMKV
export function useMMKVString(key, mmkvInstance) {
const [value, setValue] = useState(() => mmkvInstance.getString(key));
// Get default instance
function getDefaultMMKVInstance() {
if (defaultInstance == null) {
defaultInstance = createMMKV();
}
return defaultInstance;
}

useEffect(() => {
const listener = mmkvInstance.addOnValueChangedListener(changedKey => {
if (changedKey === key || changedKey === undefined) {
setValue(mmkvInstance.getString(key));
}
});
return () => listener.remove();
}, [key, mmkvInstance]);
// Top-level functions
export function existsMMKV(id) {
return storageInstances.has(id);
}

const setStoredValue = newValue => {
if (newValue === undefined) {
mmkvInstance.delete(key);
} else {
mmkvInstance.set(key, newValue);
}
setValue(newValue);
};
export function deleteMMKV(id) {
const instance = storageInstances.get(id);
instance?.storage.clear();
instance?.listeners.splice(0);

return [value, setStoredValue];
const deleted = storageInstances.delete(id);
if (defaultInstance?.id === id) {
defaultInstance = null;
}
return deleted;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

export function useMMKVNumber(key, mmkvInstance) {
const [value, setValue] = useState(() => mmkvInstance.getNumber(key));
// Helper function for configuration comparison
function isConfigurationEqual(left, right) {
if (left == null || right == null) {
return left == null && right == null;
}

useEffect(() => {
const listener = mmkvInstance.addOnValueChangedListener(changedKey => {
if (changedKey === key || changedKey === undefined) {
setValue(mmkvInstance.getNumber(key));
}
});
return () => listener.remove();
}, [key, mmkvInstance]);
return (
left.encryptionKey === right.encryptionKey &&
left.id === right.id &&
left.path === right.path &&
left.mode === right.mode &&
left.readOnly === right.readOnly
);
}

const setStoredValue = newValue => {
if (newValue === undefined) {
mmkvInstance.delete(key);
} else {
mmkvInstance.set(key, newValue);
}
setValue(newValue);
};
/**
* Use the default, shared MMKV instance or a custom instance with configuration
*/
export function useMMKV(configuration) {
const configurationRef = useRef();
const instanceRef = useRef();

return [value, setStoredValue];
if (configuration == null) {
return getDefaultMMKVInstance();
}

if (!instanceRef.current || !isConfigurationEqual(configurationRef.current, configuration)) {
configurationRef.current = configuration;
instanceRef.current = createMMKV(configuration);
}

return instanceRef.current;
}

export function useMMKVBoolean(key, mmkvInstance) {
const [value, setValue] = useState(() => mmkvInstance.getBoolean(key));
/**
* Listen for changes in the given MMKV storage instance
*/
export function useMMKVListener(valueChangedListener, instance) {
const ref = useRef(valueChangedListener);
const mmkv = instance ?? getDefaultMMKVInstance();

useEffect(() => {
const listener = mmkvInstance.addOnValueChangedListener(changedKey => {
if (changedKey === key || changedKey === undefined) {
setValue(mmkvInstance.getBoolean(key));
}
ref.current = valueChangedListener;
}, [valueChangedListener]);

useEffect(() => {
const listener = mmkv.addOnValueChangedListener(changedKey => {
ref.current(changedKey);
});
return () => listener.remove();
}, [key, mmkvInstance]);
}, [mmkv]);
}

/**
* Get a list of all keys that exist in the given MMKV instance
*/
export function useMMKVKeys(instance) {
const mmkv = instance ?? getDefaultMMKVInstance();
const [allKeys, setKeys] = useState(() => mmkv.getAllKeys());

const setStoredValue = newValue => {
if (newValue === undefined) {
mmkvInstance.delete(key);
} else {
mmkvInstance.set(key, newValue);
useEffect(() => {
setKeys(mmkv.getAllKeys());
}, [mmkv]);

useMMKVListener(key => {
if (key === undefined) {
setKeys(() => mmkv.getAllKeys());
return;
}
setValue(newValue);
};

return [value, setStoredValue];
const currentlyHasKey = allKeys.includes(key);
const hasKey = mmkv.contains(key);
if (hasKey !== currentlyHasKey) {
setKeys(() => mmkv.getAllKeys());
}
}, mmkv);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return allKeys;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

export function useMMKVObject(key, mmkvInstance) {
const [value, setValue] = useState(() => {
const stored = mmkvInstance.getString(key);
return stored ? JSON.parse(stored) : undefined;
});
/**
* Create a custom MMKV hook for a specific type
*/
function createMMKVHook(getter, onSet) {
return (key, instance) => {
const mmkv = instance ?? getDefaultMMKVInstance();

const [bump, setBump] = useState(0);
const value = useMemo(() => getter(mmkv, key), [mmkv, key, bump]);

const set = useCallback(
v => {
const newValue = typeof v === 'function' ? v(getter(mmkv, key)) : v;
if (onSet) {
onSet(mmkv, key, newValue);
return;
}
switch (typeof newValue) {
case 'number':
case 'string':
case 'boolean':
mmkv.set(key, newValue);
break;
case 'undefined':
mmkv.remove(key);
break;
case 'object':
if (newValue instanceof ArrayBuffer) {
mmkv.set(key, newValue);
break;
} else {
throw new Error(`MMKV: Type object (${newValue}) is not supported!`);
}
default:
throw new Error(`MMKV: Type ${typeof newValue} is not supported!`);
}
},
[key, mmkv, onSet]
);

useEffect(() => {
const listener = mmkv.addOnValueChangedListener(changedKey => {
if (changedKey === undefined || changedKey === key) {
setBump(b => b + 1);
}
});
return () => listener.remove();
}, [key, mmkv]);

useEffect(() => {
const listener = mmkvInstance.addOnValueChangedListener(changedKey => {
if (changedKey === key || changedKey === undefined) {
const stored = mmkvInstance.getString(key);
setValue(stored ? JSON.parse(stored) : undefined);
}
});
return () => listener.remove();
}, [key, mmkvInstance]);
return [value, set];
};
}

const setStoredValue = newValue => {
if (newValue === undefined) {
mmkvInstance.delete(key);
} else {
mmkvInstance.set(key, JSON.stringify(newValue));
/**
* Use the string value of the given key from the given MMKV storage instance
*/
export const useMMKVString = createMMKVHook((instance, key) => instance.getString(key));

/**
* Use the number value of the given key from the given MMKV storage instance
*/
export const useMMKVNumber = createMMKVHook((instance, key) => instance.getNumber(key));

/**
* Use the boolean value of the given key from the given MMKV storage instance
*/
export const useMMKVBoolean = createMMKVHook((instance, key) => instance.getBoolean(key));

/**
* Use the object value (JSON stringified) of the given key from the given MMKV storage instance
*/
export const useMMKVObject = createMMKVHook(
(instance, key) => {
const stored = instance.getString(key);
return stored ? JSON.parse(stored) : undefined;
},
(mmkv, key, value) => {
if (value === undefined) {
mmkv.remove(key);
return;
}
setValue(newValue);
};
mmkv.set(key, JSON.stringify(value));
}
);

return [value, setStoredValue];
}
/**
* Use the buffer value of the given key from the given MMKV storage instance
*/
export const useMMKVBuffer = createMMKVHook((instance, key) => instance.getBuffer(key));
Loading
Loading