react-native-mmkv 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NitroMmkv.podspec +0 -1
- package/android/build.gradle +1 -1
- package/cpp/HybridMMKV.cpp +13 -0
- package/cpp/HybridMMKV.hpp +2 -0
- package/cpp/HybridMMKVFactory.cpp +12 -4
- package/cpp/HybridMMKVFactory.hpp +4 -1
- package/lib/createMMKV/createMMKV.js +4 -14
- package/lib/createMMKV/createMMKV.web.js +43 -51
- package/lib/createMMKV/createMockMMKV.d.ts +2 -1
- package/lib/createMMKV/createMockMMKV.js +18 -5
- package/lib/deleteMMKV/deleteMMKV.d.ts +1 -0
- package/lib/deleteMMKV/deleteMMKV.js +9 -0
- package/lib/deleteMMKV/deleteMMKV.web.d.ts +1 -0
- package/lib/deleteMMKV/deleteMMKV.web.js +14 -0
- package/lib/existsMMKV/existsMMKV.d.ts +1 -0
- package/lib/existsMMKV/existsMMKV.js +9 -0
- package/lib/existsMMKV/existsMMKV.web.d.ts +1 -0
- package/lib/existsMMKV/existsMMKV.web.js +7 -0
- package/lib/getMMKVFactory.d.ts +4 -0
- package/lib/getMMKVFactory.js +20 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -0
- package/lib/specs/MMKV.nitro.d.ts +19 -9
- package/lib/specs/MMKVFactory.nitro.d.ts +13 -3
- package/lib/web/getLocalStorage.d.ts +2 -0
- package/lib/web/getLocalStorage.js +33 -0
- package/nitrogen/generated/android/c++/JHybridMMKVPlatformContextSpec.cpp +6 -0
- package/nitrogen/generated/android/c++/JHybridMMKVPlatformContextSpec.hpp +1 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/mmkv/HybridMMKVPlatformContextSpec.kt +5 -0
- package/nitrogen/generated/ios/NitroMmkv-Swift-Cxx-Bridge.cpp +1 -0
- package/nitrogen/generated/ios/c++/HybridMMKVPlatformContextSpecSwift.hpp +3 -0
- package/nitrogen/generated/ios/swift/HybridMMKVPlatformContextSpec.swift +7 -0
- package/nitrogen/generated/ios/swift/HybridMMKVPlatformContextSpec_cxx.swift +9 -1
- package/nitrogen/generated/shared/c++/HybridMMKVFactorySpec.cpp +3 -1
- package/nitrogen/generated/shared/c++/HybridMMKVFactorySpec.hpp +3 -1
- package/nitrogen/generated/shared/c++/HybridMMKVSpec.cpp +2 -0
- package/nitrogen/generated/shared/c++/HybridMMKVSpec.hpp +6 -0
- package/package.json +3 -4
- package/src/createMMKV/createMMKV.ts +5 -19
- package/src/createMMKV/createMMKV.web.ts +46 -65
- package/src/createMMKV/createMockMMKV.ts +21 -5
- package/src/deleteMMKV/deleteMMKV.ts +11 -0
- package/src/deleteMMKV/deleteMMKV.web.ts +20 -0
- package/src/existsMMKV/existsMMKV.ts +11 -0
- package/src/existsMMKV/existsMMKV.web.ts +11 -0
- package/src/getMMKVFactory.ts +28 -0
- package/src/index.ts +4 -0
- package/src/specs/MMKV.nitro.ts +20 -9
- package/src/specs/MMKVFactory.nitro.ts +15 -3
- package/src/web/getLocalStorage.ts +42 -0
|
@@ -76,7 +76,7 @@ open class HybridMMKVPlatformContextSpec_cxx {
|
|
|
76
76
|
*/
|
|
77
77
|
public func getCxxPart() -> bridge.std__shared_ptr_HybridMMKVPlatformContextSpec_ {
|
|
78
78
|
let cachedCxxPart = self.__cxxPart.lock()
|
|
79
|
-
if cachedCxxPart
|
|
79
|
+
if Bool(fromCxx: cachedCxxPart) {
|
|
80
80
|
return cachedCxxPart
|
|
81
81
|
} else {
|
|
82
82
|
let newCxxPart = bridge.create_std__shared_ptr_HybridMMKVPlatformContextSpec_(self.toUnsafe())
|
|
@@ -105,6 +105,14 @@ open class HybridMMKVPlatformContextSpec_cxx {
|
|
|
105
105
|
self.__implementation.dispose()
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Call toString() on the Swift class.
|
|
110
|
+
*/
|
|
111
|
+
@inline(__always)
|
|
112
|
+
public func toString() -> String {
|
|
113
|
+
return self.__implementation.toString()
|
|
114
|
+
}
|
|
115
|
+
|
|
108
116
|
// Properties
|
|
109
117
|
|
|
110
118
|
|
|
@@ -15,8 +15,10 @@ namespace margelo::nitro::mmkv {
|
|
|
15
15
|
// load custom methods/properties
|
|
16
16
|
registerHybrids(this, [](Prototype& prototype) {
|
|
17
17
|
prototype.registerHybridGetter("defaultMMKVInstanceId", &HybridMMKVFactorySpec::getDefaultMMKVInstanceId);
|
|
18
|
-
prototype.registerHybridMethod("createMMKV", &HybridMMKVFactorySpec::createMMKV);
|
|
19
18
|
prototype.registerHybridMethod("initializeMMKV", &HybridMMKVFactorySpec::initializeMMKV);
|
|
19
|
+
prototype.registerHybridMethod("createMMKV", &HybridMMKVFactorySpec::createMMKV);
|
|
20
|
+
prototype.registerHybridMethod("deleteMMKV", &HybridMMKVFactorySpec::deleteMMKV);
|
|
21
|
+
prototype.registerHybridMethod("existsMMKV", &HybridMMKVFactorySpec::existsMMKV);
|
|
20
22
|
});
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -54,8 +54,10 @@ namespace margelo::nitro::mmkv {
|
|
|
54
54
|
|
|
55
55
|
public:
|
|
56
56
|
// Methods
|
|
57
|
-
virtual std::shared_ptr<HybridMMKVSpec> createMMKV(const Configuration& configuration) = 0;
|
|
58
57
|
virtual void initializeMMKV(const std::string& rootPath) = 0;
|
|
58
|
+
virtual std::shared_ptr<HybridMMKVSpec> createMMKV(const Configuration& configuration) = 0;
|
|
59
|
+
virtual bool deleteMMKV(const std::string& id) = 0;
|
|
60
|
+
virtual bool existsMMKV(const std::string& id) = 0;
|
|
59
61
|
|
|
60
62
|
protected:
|
|
61
63
|
// Hybrid Setup
|
|
@@ -14,6 +14,7 @@ namespace margelo::nitro::mmkv {
|
|
|
14
14
|
HybridObject::loadHybridMethods();
|
|
15
15
|
// load custom methods/properties
|
|
16
16
|
registerHybrids(this, [](Prototype& prototype) {
|
|
17
|
+
prototype.registerHybridGetter("id", &HybridMMKVSpec::getId);
|
|
17
18
|
prototype.registerHybridGetter("size", &HybridMMKVSpec::getSize);
|
|
18
19
|
prototype.registerHybridGetter("isReadOnly", &HybridMMKVSpec::getIsReadOnly);
|
|
19
20
|
prototype.registerHybridMethod("set", &HybridMMKVSpec::set);
|
|
@@ -28,6 +29,7 @@ namespace margelo::nitro::mmkv {
|
|
|
28
29
|
prototype.registerHybridMethod("recrypt", &HybridMMKVSpec::recrypt);
|
|
29
30
|
prototype.registerHybridMethod("trim", &HybridMMKVSpec::trim);
|
|
30
31
|
prototype.registerHybridMethod("addOnValueChangedListener", &HybridMMKVSpec::addOnValueChangedListener);
|
|
32
|
+
prototype.registerHybridMethod("importAllFrom", &HybridMMKVSpec::importAllFrom);
|
|
31
33
|
});
|
|
32
34
|
}
|
|
33
35
|
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
// Forward declaration of `Listener` to properly resolve imports.
|
|
17
17
|
namespace margelo::nitro::mmkv { struct Listener; }
|
|
18
|
+
// Forward declaration of `HybridMMKVSpec` to properly resolve imports.
|
|
19
|
+
namespace margelo::nitro::mmkv { class HybridMMKVSpec; }
|
|
18
20
|
|
|
19
21
|
#include <string>
|
|
20
22
|
#include <NitroModules/ArrayBuffer.hpp>
|
|
@@ -23,6 +25,8 @@ namespace margelo::nitro::mmkv { struct Listener; }
|
|
|
23
25
|
#include <vector>
|
|
24
26
|
#include "Listener.hpp"
|
|
25
27
|
#include <functional>
|
|
28
|
+
#include <memory>
|
|
29
|
+
#include "HybridMMKVSpec.hpp"
|
|
26
30
|
|
|
27
31
|
namespace margelo::nitro::mmkv {
|
|
28
32
|
|
|
@@ -51,6 +55,7 @@ namespace margelo::nitro::mmkv {
|
|
|
51
55
|
|
|
52
56
|
public:
|
|
53
57
|
// Properties
|
|
58
|
+
virtual std::string getId() = 0;
|
|
54
59
|
virtual double getSize() = 0;
|
|
55
60
|
virtual bool getIsReadOnly() = 0;
|
|
56
61
|
|
|
@@ -68,6 +73,7 @@ namespace margelo::nitro::mmkv {
|
|
|
68
73
|
virtual void recrypt(const std::optional<std::string>& key) = 0;
|
|
69
74
|
virtual void trim() = 0;
|
|
70
75
|
virtual Listener addOnValueChangedListener(const std::function<void(const std::string& /* key */)>& onValueChanged) = 0;
|
|
76
|
+
virtual double importAllFrom(const std::shared_ptr<HybridMMKVSpec>& other) = 0;
|
|
71
77
|
|
|
72
78
|
protected:
|
|
73
79
|
// Hybrid Setup
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-mmkv",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "⚡️ The fastest key/value storage for React Native.",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"module": "lib/index",
|
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
"README.md"
|
|
32
32
|
],
|
|
33
33
|
"scripts": {
|
|
34
|
-
"postinstall": "tsc || exit 0;",
|
|
35
34
|
"typecheck": "tsc --noEmit",
|
|
36
35
|
"clean": "rm -rf android/build node_modules/**/android/build lib",
|
|
37
36
|
"lint": "eslint \"**/*.{js,ts,tsx}\" --fix",
|
|
@@ -68,11 +67,11 @@
|
|
|
68
67
|
"eslint": "^8.57.0",
|
|
69
68
|
"eslint-config-prettier": "^9.1.0",
|
|
70
69
|
"eslint-plugin-prettier": "^5.2.1",
|
|
71
|
-
"nitrogen": "0.31.
|
|
70
|
+
"nitrogen": "0.31.7",
|
|
72
71
|
"prettier": "^3.3.3",
|
|
73
72
|
"react": "19.1.1",
|
|
74
73
|
"react-native": "0.82.0",
|
|
75
|
-
"react-native-nitro-modules": "0.31.
|
|
74
|
+
"react-native-nitro-modules": "0.31.7",
|
|
76
75
|
"typescript": "^5.8.3"
|
|
77
76
|
},
|
|
78
77
|
"peerDependencies": {
|
|
@@ -1,33 +1,18 @@
|
|
|
1
|
-
import { NitroModules } from 'react-native-nitro-modules'
|
|
2
1
|
import type { MMKV } from '../specs/MMKV.nitro'
|
|
3
|
-
import type { Configuration
|
|
4
|
-
import type { MMKVPlatformContext } from '../specs/MMKVPlatformContext.nitro'
|
|
2
|
+
import type { Configuration } from '../specs/MMKVFactory.nitro'
|
|
5
3
|
import { Platform } from 'react-native'
|
|
6
4
|
import { addMemoryWarningListener } from '../addMemoryWarningListener/addMemoryWarningListener'
|
|
7
5
|
import { isTest } from '../isTest'
|
|
8
6
|
import { createMockMMKV } from './createMockMMKV'
|
|
9
|
-
|
|
10
|
-
let factory: MMKVFactory | undefined
|
|
11
|
-
let platformContext: MMKVPlatformContext | undefined
|
|
7
|
+
import { getMMKVFactory, getPlatformContext } from '../getMMKVFactory'
|
|
12
8
|
|
|
13
9
|
export function createMMKV(configuration?: Configuration): MMKV {
|
|
14
10
|
if (isTest()) {
|
|
15
11
|
// In a test environment, we mock the MMKV instance.
|
|
16
|
-
return createMockMMKV()
|
|
12
|
+
return createMockMMKV(configuration)
|
|
17
13
|
}
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
// Lazy-init the platform-context HybridObject
|
|
21
|
-
platformContext = NitroModules.createHybridObject<MMKVPlatformContext>(
|
|
22
|
-
'MMKVPlatformContext'
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
if (factory == null) {
|
|
26
|
-
// Lazy-init the factory HybridObject
|
|
27
|
-
factory = NitroModules.createHybridObject<MMKVFactory>('MMKVFactory')
|
|
28
|
-
const baseDirectory = platformContext.getBaseDirectory()
|
|
29
|
-
factory.initializeMMKV(baseDirectory)
|
|
30
|
-
}
|
|
15
|
+
const factory = getMMKVFactory()
|
|
31
16
|
|
|
32
17
|
// Pre-parse the config
|
|
33
18
|
let config = configuration ?? { id: factory.defaultMMKVInstanceId }
|
|
@@ -36,6 +21,7 @@ export function createMMKV(configuration?: Configuration): MMKV {
|
|
|
36
21
|
if (config.path == null) {
|
|
37
22
|
// If the user set an App Group directory in Info.plist, let's use
|
|
38
23
|
// the App Group as a MMKV path:
|
|
24
|
+
const platformContext = getPlatformContext()
|
|
39
25
|
const appGroupDirectory = platformContext.getAppGroupDirectory()
|
|
40
26
|
if (appGroupDirectory != null) {
|
|
41
27
|
config.path = appGroupDirectory
|
|
@@ -1,23 +1,10 @@
|
|
|
1
1
|
import type { MMKV } from '../specs/MMKV.nitro'
|
|
2
2
|
import type { Configuration } from '../specs/MMKVFactory.nitro'
|
|
3
3
|
import { createTextEncoder } from '../web/createTextEncoder'
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const hasAccessToLocalStorage = () => {
|
|
9
|
-
try {
|
|
10
|
-
// throws ACCESS_DENIED error
|
|
11
|
-
window.localStorage
|
|
12
|
-
|
|
13
|
-
return true
|
|
14
|
-
} catch {
|
|
15
|
-
return false
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const KEY_WILDCARD = '\\'
|
|
20
|
-
const inMemoryStorage = new Map<string, string>()
|
|
4
|
+
import {
|
|
5
|
+
getLocalStorage,
|
|
6
|
+
LOCAL_STORAGE_KEY_WILDCARD,
|
|
7
|
+
} from '../web/getLocalStorage'
|
|
21
8
|
|
|
22
9
|
export function createMMKV(
|
|
23
10
|
config: Configuration = { id: 'mmkv.default' }
|
|
@@ -29,48 +16,14 @@ export function createMMKV(
|
|
|
29
16
|
throw new Error("MMKV: 'path' is not supported on Web!")
|
|
30
17
|
}
|
|
31
18
|
|
|
32
|
-
// canUseDOM check prevents spam in Node server environments, such as Next.js server side props.
|
|
33
|
-
if (!hasAccessToLocalStorage() && canUseDOM) {
|
|
34
|
-
console.warn(
|
|
35
|
-
'MMKV: LocalStorage has been disabled. Your experience will be limited to in-memory storage!'
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const storage = () => {
|
|
40
|
-
if (!canUseDOM) {
|
|
41
|
-
throw new Error(
|
|
42
|
-
'Tried to access storage on the server. Did you forget to call this in useEffect?'
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (!hasAccessToLocalStorage()) {
|
|
47
|
-
return {
|
|
48
|
-
getItem: (key: string) => inMemoryStorage.get(key) ?? null,
|
|
49
|
-
setItem: (key: string, value: string) =>
|
|
50
|
-
inMemoryStorage.set(key, value),
|
|
51
|
-
removeItem: (key: string) => inMemoryStorage.delete(key),
|
|
52
|
-
clear: () => inMemoryStorage.clear(),
|
|
53
|
-
length: inMemoryStorage.size,
|
|
54
|
-
key: (index: number) => Object.keys(inMemoryStorage).at(index) ?? null,
|
|
55
|
-
} as Storage
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const domStorage =
|
|
59
|
-
global?.localStorage ?? window?.localStorage ?? localStorage
|
|
60
|
-
if (domStorage == null) {
|
|
61
|
-
throw new Error(`Could not find 'localStorage' instance!`)
|
|
62
|
-
}
|
|
63
|
-
return domStorage
|
|
64
|
-
}
|
|
65
|
-
|
|
66
19
|
const textEncoder = createTextEncoder()
|
|
67
20
|
const listeners = new Set<(key: string) => void>()
|
|
68
21
|
|
|
69
|
-
if (config.id.includes(
|
|
22
|
+
if (config.id.includes(LOCAL_STORAGE_KEY_WILDCARD)) {
|
|
70
23
|
throw new Error('MMKV: `id` cannot contain the backslash character (`\\`)!')
|
|
71
24
|
}
|
|
72
25
|
|
|
73
|
-
const keyPrefix = `${config.id}${
|
|
26
|
+
const keyPrefix = `${config.id}${LOCAL_STORAGE_KEY_WILDCARD}` // mmkv.default\\
|
|
74
27
|
const prefixedKey = (key: string) => {
|
|
75
28
|
if (key.includes('\\')) {
|
|
76
29
|
throw new Error(
|
|
@@ -85,53 +38,68 @@ export function createMMKV(
|
|
|
85
38
|
}
|
|
86
39
|
|
|
87
40
|
return {
|
|
41
|
+
id: config.id,
|
|
42
|
+
size: 0,
|
|
43
|
+
isReadOnly: false,
|
|
88
44
|
clearAll: () => {
|
|
89
|
-
const
|
|
45
|
+
const storage = getLocalStorage()
|
|
46
|
+
const keys = Object.keys(storage)
|
|
90
47
|
for (const key of keys) {
|
|
91
48
|
if (key.startsWith(keyPrefix)) {
|
|
92
|
-
storage
|
|
49
|
+
storage.removeItem(key)
|
|
93
50
|
callListeners(key)
|
|
94
51
|
}
|
|
95
52
|
}
|
|
96
53
|
},
|
|
97
54
|
remove: (key) => {
|
|
98
|
-
const
|
|
55
|
+
const storage = getLocalStorage()
|
|
56
|
+
storage.removeItem(prefixedKey(key))
|
|
57
|
+
const wasRemoved = storage.getItem(prefixedKey(key)) === null
|
|
99
58
|
if (wasRemoved) callListeners(key)
|
|
100
59
|
return wasRemoved
|
|
101
60
|
},
|
|
102
61
|
set: (key, value) => {
|
|
62
|
+
const storage = getLocalStorage()
|
|
103
63
|
if (key === '') throw new Error('Cannot set a value for an empty key!')
|
|
104
|
-
storage
|
|
64
|
+
storage.setItem(prefixedKey(key), value.toString())
|
|
105
65
|
callListeners(key)
|
|
106
66
|
},
|
|
107
|
-
getString: (key) =>
|
|
67
|
+
getString: (key) => {
|
|
68
|
+
const storage = getLocalStorage()
|
|
69
|
+
return storage.getItem(prefixedKey(key)) ?? undefined
|
|
70
|
+
},
|
|
108
71
|
getNumber: (key) => {
|
|
109
|
-
const
|
|
72
|
+
const storage = getLocalStorage()
|
|
73
|
+
const value = storage.getItem(prefixedKey(key))
|
|
110
74
|
if (value == null) return undefined
|
|
111
75
|
return Number(value)
|
|
112
76
|
},
|
|
113
77
|
getBoolean: (key) => {
|
|
114
|
-
const
|
|
78
|
+
const storage = getLocalStorage()
|
|
79
|
+
const value = storage.getItem(prefixedKey(key))
|
|
115
80
|
if (value == null) return undefined
|
|
116
81
|
return value === 'true'
|
|
117
82
|
},
|
|
118
83
|
getBuffer: (key) => {
|
|
119
|
-
const
|
|
84
|
+
const storage = getLocalStorage()
|
|
85
|
+
const value = storage.getItem(prefixedKey(key))
|
|
120
86
|
if (value == null) return undefined
|
|
121
87
|
return textEncoder.encode(value).buffer
|
|
122
88
|
},
|
|
123
89
|
getAllKeys: () => {
|
|
124
|
-
const
|
|
90
|
+
const storage = getLocalStorage()
|
|
91
|
+
const keys = Object.keys(storage)
|
|
125
92
|
return keys
|
|
126
93
|
.filter((key) => key.startsWith(keyPrefix))
|
|
127
94
|
.map((key) => key.slice(keyPrefix.length))
|
|
128
95
|
},
|
|
129
|
-
contains: (key) =>
|
|
96
|
+
contains: (key) => {
|
|
97
|
+
const storage = getLocalStorage()
|
|
98
|
+
return storage.getItem(prefixedKey(key)) != null
|
|
99
|
+
},
|
|
130
100
|
recrypt: () => {
|
|
131
101
|
throw new Error('`recrypt(..)` is not supported on Web!')
|
|
132
102
|
},
|
|
133
|
-
size: 0,
|
|
134
|
-
isReadOnly: false,
|
|
135
103
|
trim: () => {
|
|
136
104
|
// no-op
|
|
137
105
|
},
|
|
@@ -146,5 +114,18 @@ export function createMMKV(
|
|
|
146
114
|
},
|
|
147
115
|
}
|
|
148
116
|
},
|
|
117
|
+
importAllFrom: (other) => {
|
|
118
|
+
const storage = getLocalStorage()
|
|
119
|
+
const keys = other.getAllKeys()
|
|
120
|
+
let imported = 0
|
|
121
|
+
for (const key of keys) {
|
|
122
|
+
const string = other.getString(key)
|
|
123
|
+
if (string != null) {
|
|
124
|
+
storage.set(key, string)
|
|
125
|
+
imported++
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return imported
|
|
129
|
+
},
|
|
149
130
|
}
|
|
150
131
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { MMKV } from '../specs/MMKV.nitro'
|
|
2
|
+
import type { Configuration } from '../specs/MMKVFactory.nitro'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Mock MMKV instance when used in a Jest/Test environment.
|
|
5
6
|
*/
|
|
6
|
-
export function createMockMMKV(
|
|
7
|
+
export function createMockMMKV(
|
|
8
|
+
config: Configuration = { id: 'mmkv.default' }
|
|
9
|
+
): MMKV {
|
|
7
10
|
const storage = new Map<string, string | boolean | number | ArrayBuffer>()
|
|
8
11
|
const listeners = new Set<(key: string) => void>()
|
|
9
12
|
|
|
@@ -14,6 +17,11 @@ export function createMockMMKV(): MMKV {
|
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
return {
|
|
20
|
+
id: config.id,
|
|
21
|
+
get size(): number {
|
|
22
|
+
return storage.size
|
|
23
|
+
},
|
|
24
|
+
isReadOnly: false,
|
|
17
25
|
clearAll: () => {
|
|
18
26
|
const keysBefore = storage.keys()
|
|
19
27
|
storage.clear()
|
|
@@ -55,10 +63,6 @@ export function createMockMMKV(): MMKV {
|
|
|
55
63
|
recrypt: () => {
|
|
56
64
|
console.warn('Encryption is not supported in mocked MMKV instances!')
|
|
57
65
|
},
|
|
58
|
-
get size(): number {
|
|
59
|
-
return storage.size
|
|
60
|
-
},
|
|
61
|
-
isReadOnly: false,
|
|
62
66
|
trim: () => {
|
|
63
67
|
// no-op
|
|
64
68
|
},
|
|
@@ -75,5 +79,17 @@ export function createMockMMKV(): MMKV {
|
|
|
75
79
|
},
|
|
76
80
|
}
|
|
77
81
|
},
|
|
82
|
+
importAllFrom: (other) => {
|
|
83
|
+
const keys = other.getAllKeys()
|
|
84
|
+
let imported = 0
|
|
85
|
+
for (const key of keys) {
|
|
86
|
+
const data = other.getBuffer(key)
|
|
87
|
+
if (data != null) {
|
|
88
|
+
storage.set(key, data)
|
|
89
|
+
imported++
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return imported
|
|
93
|
+
},
|
|
78
94
|
}
|
|
79
95
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getLocalStorage,
|
|
3
|
+
LOCAL_STORAGE_KEY_WILDCARD,
|
|
4
|
+
} from '../web/getLocalStorage'
|
|
5
|
+
|
|
6
|
+
export function deleteMMKV(id: string): boolean {
|
|
7
|
+
const storage = getLocalStorage()
|
|
8
|
+
const prefix = id + LOCAL_STORAGE_KEY_WILDCARD
|
|
9
|
+
let wasRemoved = false
|
|
10
|
+
|
|
11
|
+
const keys = Object.keys(storage)
|
|
12
|
+
for (const key of keys) {
|
|
13
|
+
if (key.startsWith(prefix)) {
|
|
14
|
+
storage.removeItem(key)
|
|
15
|
+
wasRemoved = true
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return wasRemoved
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getLocalStorage,
|
|
3
|
+
LOCAL_STORAGE_KEY_WILDCARD,
|
|
4
|
+
} from '../web/getLocalStorage'
|
|
5
|
+
|
|
6
|
+
export function existsMMKV(id: string): boolean {
|
|
7
|
+
const storage = getLocalStorage()
|
|
8
|
+
const prefix = id + LOCAL_STORAGE_KEY_WILDCARD
|
|
9
|
+
const keys = Object.keys(storage)
|
|
10
|
+
return keys.some((k) => k.startsWith(prefix))
|
|
11
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { NitroModules } from 'react-native-nitro-modules'
|
|
2
|
+
import type { MMKVFactory } from './specs/MMKVFactory.nitro'
|
|
3
|
+
import type { MMKVPlatformContext } from './specs/MMKVPlatformContext.nitro'
|
|
4
|
+
|
|
5
|
+
let factory: MMKVFactory | undefined
|
|
6
|
+
let platformContext: MMKVPlatformContext | undefined
|
|
7
|
+
|
|
8
|
+
export function getPlatformContext(): MMKVPlatformContext {
|
|
9
|
+
if (platformContext == null) {
|
|
10
|
+
// Lazy-init the platform-context HybridObject
|
|
11
|
+
platformContext = NitroModules.createHybridObject<MMKVPlatformContext>(
|
|
12
|
+
'MMKVPlatformContext'
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
return platformContext
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getMMKVFactory(): MMKVFactory {
|
|
19
|
+
if (factory == null) {
|
|
20
|
+
// Lazy-init the factory HybridObject
|
|
21
|
+
factory = NitroModules.createHybridObject<MMKVFactory>('MMKVFactory')
|
|
22
|
+
const context = getPlatformContext()
|
|
23
|
+
const baseDirectory = context.getBaseDirectory()
|
|
24
|
+
factory.initializeMMKV(baseDirectory)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return factory
|
|
28
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,10 @@ export type { Configuration, Mode } from './specs/MMKVFactory.nitro'
|
|
|
5
5
|
// The create function
|
|
6
6
|
export { createMMKV } from './createMMKV/createMMKV'
|
|
7
7
|
|
|
8
|
+
// Exists + Delete
|
|
9
|
+
export { existsMMKV } from './existsMMKV/existsMMKV'
|
|
10
|
+
export { deleteMMKV } from './deleteMMKV/deleteMMKV'
|
|
11
|
+
|
|
8
12
|
// All the hooks
|
|
9
13
|
export { useMMKV } from './hooks/useMMKV'
|
|
10
14
|
export { useMMKVBoolean } from './hooks/useMMKVBoolean'
|
package/src/specs/MMKV.nitro.ts
CHANGED
|
@@ -5,6 +5,19 @@ export interface Listener {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export interface MMKV extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
8
|
+
/**
|
|
9
|
+
* Get the ID of this {@linkcode MMKV} instance.
|
|
10
|
+
*/
|
|
11
|
+
readonly id: string
|
|
12
|
+
/**
|
|
13
|
+
* Get the current total size of the storage, in bytes.
|
|
14
|
+
*/
|
|
15
|
+
readonly size: number
|
|
16
|
+
/**
|
|
17
|
+
* Returns whether this instance is in read-only mode or not.
|
|
18
|
+
* If this is `true`, you can only use "get"-functions.
|
|
19
|
+
*/
|
|
20
|
+
readonly isReadOnly: boolean
|
|
8
21
|
/**
|
|
9
22
|
* Set a {@linkcode value} for the given {@linkcode key}.
|
|
10
23
|
*
|
|
@@ -75,15 +88,6 @@ export interface MMKV extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
|
75
88
|
* In most applications, this is not needed at all.
|
|
76
89
|
*/
|
|
77
90
|
trim(): void
|
|
78
|
-
/**
|
|
79
|
-
* Get the current total size of the storage, in bytes.
|
|
80
|
-
*/
|
|
81
|
-
readonly size: number
|
|
82
|
-
/**
|
|
83
|
-
* Returns whether this instance is in read-only mode or not.
|
|
84
|
-
* If this is `true`, you can only use "get"-functions.
|
|
85
|
-
*/
|
|
86
|
-
readonly isReadOnly: boolean
|
|
87
91
|
/**
|
|
88
92
|
* Adds a value changed listener. The Listener will be called whenever any value
|
|
89
93
|
* in this storage instance changes (set or delete).
|
|
@@ -91,4 +95,11 @@ export interface MMKV extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
|
91
95
|
* To unsubscribe from value changes, call `remove()` on the Listener.
|
|
92
96
|
*/
|
|
93
97
|
addOnValueChangedListener(onValueChanged: (key: string) => void): Listener
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Imports all keys and values from the
|
|
101
|
+
* given other {@linkcode MMKV} instance.
|
|
102
|
+
* @returns the number of imported keys/values.
|
|
103
|
+
*/
|
|
104
|
+
importAllFrom(other: MMKV): number
|
|
94
105
|
}
|
|
@@ -68,16 +68,28 @@ export interface Configuration {
|
|
|
68
68
|
|
|
69
69
|
export interface MMKVFactory
|
|
70
70
|
extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
71
|
+
/**
|
|
72
|
+
* Initialize the MMKV library with the given root path.
|
|
73
|
+
* This has to be called once, before using {@linkcode createMMKV}.
|
|
74
|
+
*/
|
|
75
|
+
initializeMMKV(rootPath: string): void
|
|
76
|
+
|
|
71
77
|
/**
|
|
72
78
|
* Create a new {@linkcode MMKV} instance with the given {@linkcode Configuration}
|
|
73
79
|
*/
|
|
74
80
|
createMMKV(configuration: Configuration): MMKV
|
|
75
81
|
|
|
76
82
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
83
|
+
* Deletes the MMKV instance with the
|
|
84
|
+
* given {@linkcode id}.
|
|
79
85
|
*/
|
|
80
|
-
|
|
86
|
+
deleteMMKV(id: string): boolean
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Returns `true` if an MMKV instance with the
|
|
90
|
+
* given {@linkcode id} exists, `false` otherwise.
|
|
91
|
+
*/
|
|
92
|
+
existsMMKV(id: string): boolean
|
|
81
93
|
|
|
82
94
|
/**
|
|
83
95
|
* Get the default MMKV instance's ID.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const LOCAL_STORAGE_KEY_WILDCARD = '\\'
|
|
2
|
+
|
|
3
|
+
const canUseDOM =
|
|
4
|
+
typeof window !== 'undefined' && window.document?.createElement != null
|
|
5
|
+
|
|
6
|
+
const hasAccessToLocalStorage = () => {
|
|
7
|
+
try {
|
|
8
|
+
// throws ACCESS_DENIED error
|
|
9
|
+
window.localStorage
|
|
10
|
+
|
|
11
|
+
return true
|
|
12
|
+
} catch {
|
|
13
|
+
return false
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const inMemoryStorage = new Map<string, string>()
|
|
17
|
+
|
|
18
|
+
export function getLocalStorage(): Storage {
|
|
19
|
+
if (!canUseDOM) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
'Tried to access storage on the server. Did you forget to call this in useEffect?'
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!hasAccessToLocalStorage()) {
|
|
26
|
+
return {
|
|
27
|
+
getItem: (key: string) => inMemoryStorage.get(key) ?? null,
|
|
28
|
+
setItem: (key: string, value: string) => inMemoryStorage.set(key, value),
|
|
29
|
+
removeItem: (key: string) => inMemoryStorage.delete(key),
|
|
30
|
+
clear: () => inMemoryStorage.clear(),
|
|
31
|
+
length: inMemoryStorage.size,
|
|
32
|
+
key: (index: number) => Object.keys(inMemoryStorage).at(index) ?? null,
|
|
33
|
+
} as Storage
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const domStorage =
|
|
37
|
+
global?.localStorage ?? window?.localStorage ?? localStorage
|
|
38
|
+
if (domStorage == null) {
|
|
39
|
+
throw new Error(`Could not find 'localStorage' instance!`)
|
|
40
|
+
}
|
|
41
|
+
return domStorage
|
|
42
|
+
}
|