react-native-mmkv 2.12.2 → 3.0.0-beta.2

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.
Files changed (131) hide show
  1. package/LICENSE +1 -200
  2. package/MMKV/Core/Core.xcodeproj/project.pbxproj +4 -2
  3. package/MMKV/Core/MMKVPredef.h +1 -1
  4. package/MMKV/Core/MMKV_IO.cpp +5 -1
  5. package/MMKV/Core/MemoryFile.cpp +1 -0
  6. package/MMKV/Core/MemoryFile_OSX.cpp +2 -1
  7. package/MMKV/README.md +8 -8
  8. package/README.md +35 -4
  9. package/android/CMakeLists.txt +20 -28
  10. package/android/build.gradle +59 -89
  11. package/android/gradle.properties +4 -5
  12. package/android/src/main/AndroidManifest.xml +2 -2
  13. package/android/src/{hasNamespace/AndroidManifest.xml → main/AndroidManifestNew.xml} +0 -1
  14. package/android/src/main/cpp/AndroidLogger.cpp +16 -0
  15. package/android/src/main/cpp/cpp-adapter.cpp +4 -80
  16. package/android/src/main/java/com/mrousavy/mmkv/MmkvPackage.java +44 -0
  17. package/android/src/main/java/com/mrousavy/mmkv/MmkvPlatformContextModule.java +17 -0
  18. package/cpp/Logger.h +35 -0
  19. package/cpp/MMKVManagedBuffer.h +32 -0
  20. package/{android/src/main/cpp → cpp}/MmkvHostObject.cpp +126 -63
  21. package/{android/src/main/cpp → cpp}/MmkvHostObject.h +9 -3
  22. package/cpp/NativeMmkvModule.cpp +46 -0
  23. package/cpp/NativeMmkvModule.h +37 -0
  24. package/ios/AppleLogger.mm +16 -0
  25. package/ios/MmkvOnLoad.mm +25 -0
  26. package/ios/MmkvPlatformContext.h +19 -0
  27. package/ios/MmkvPlatformContextModule.mm +37 -0
  28. package/lib/commonjs/LazyTurboModule.js +49 -0
  29. package/lib/commonjs/LazyTurboModule.js.map +1 -0
  30. package/lib/commonjs/MMKV.js +28 -4
  31. package/lib/commonjs/MMKV.js.map +1 -1
  32. package/lib/commonjs/NativeMmkv.js +35 -0
  33. package/lib/commonjs/NativeMmkv.js.map +1 -0
  34. package/lib/commonjs/NativeMmkvPlatformContext.js +13 -0
  35. package/lib/commonjs/NativeMmkvPlatformContext.js.map +1 -0
  36. package/lib/commonjs/PlatformChecker.js.map +1 -1
  37. package/lib/commonjs/Types.js +2 -0
  38. package/lib/commonjs/Types.js.map +1 -0
  39. package/lib/commonjs/createMMKV.js +6 -43
  40. package/lib/commonjs/createMMKV.js.map +1 -1
  41. package/lib/commonjs/createMMKV.mock.js +5 -1
  42. package/lib/commonjs/createMMKV.mock.js.map +1 -1
  43. package/lib/commonjs/createMMKV.web.js +8 -4
  44. package/lib/commonjs/createMMKV.web.js.map +1 -1
  45. package/lib/commonjs/createTextEncoder.js.map +1 -1
  46. package/lib/commonjs/hooks.js +11 -10
  47. package/lib/commonjs/hooks.js.map +1 -1
  48. package/lib/commonjs/index.js.map +1 -1
  49. package/lib/module/LazyTurboModule.js +43 -0
  50. package/lib/module/LazyTurboModule.js.map +1 -0
  51. package/lib/module/MMKV.js +16 -4
  52. package/lib/module/MMKV.js.map +1 -1
  53. package/lib/module/NativeMmkv.js +32 -0
  54. package/lib/module/NativeMmkv.js.map +1 -0
  55. package/lib/module/NativeMmkvPlatformContext.js +7 -0
  56. package/lib/module/NativeMmkvPlatformContext.js.map +1 -0
  57. package/lib/module/PlatformChecker.js.map +1 -1
  58. package/lib/module/Types.js +2 -0
  59. package/lib/module/Types.js.map +1 -0
  60. package/lib/module/createMMKV.js +6 -43
  61. package/lib/module/createMMKV.js.map +1 -1
  62. package/lib/module/createMMKV.mock.js +5 -1
  63. package/lib/module/createMMKV.mock.js.map +1 -1
  64. package/lib/module/createMMKV.web.js +6 -4
  65. package/lib/module/createMMKV.web.js.map +1 -1
  66. package/lib/module/createTextEncoder.js.map +1 -1
  67. package/lib/module/hooks.js +7 -2
  68. package/lib/module/hooks.js.map +1 -1
  69. package/lib/module/index.js.map +1 -1
  70. package/lib/typescript/src/LazyTurboModule.d.ts +6 -0
  71. package/lib/typescript/src/LazyTurboModule.d.ts.map +1 -0
  72. package/lib/typescript/src/MMKV.d.ts +35 -0
  73. package/lib/typescript/src/MMKV.d.ts.map +1 -0
  74. package/lib/typescript/src/NativeMmkv.d.ts +83 -0
  75. package/lib/typescript/src/NativeMmkv.d.ts.map +1 -0
  76. package/lib/typescript/src/NativeMmkvPlatformContext.d.ts +9 -0
  77. package/lib/typescript/src/NativeMmkvPlatformContext.d.ts.map +1 -0
  78. package/lib/typescript/src/PlatformChecker.d.ts.map +1 -0
  79. package/lib/typescript/src/Types.d.ts +86 -0
  80. package/lib/typescript/src/Types.d.ts.map +1 -0
  81. package/lib/typescript/src/__tests__/hooks.test.d.ts +2 -0
  82. package/lib/typescript/src/__tests__/hooks.test.d.ts.map +1 -0
  83. package/lib/typescript/src/createMMKV.d.ts +4 -0
  84. package/lib/typescript/src/createMMKV.d.ts.map +1 -0
  85. package/lib/typescript/src/createMMKV.mock.d.ts +3 -0
  86. package/lib/typescript/src/createMMKV.mock.d.ts.map +1 -0
  87. package/lib/typescript/src/createMMKV.web.d.ts +4 -0
  88. package/lib/typescript/src/createMMKV.web.d.ts.map +1 -0
  89. package/lib/typescript/src/createTextEncoder.d.ts.map +1 -0
  90. package/lib/typescript/{hooks.d.ts → src/hooks.d.ts} +7 -4
  91. package/lib/typescript/src/hooks.d.ts.map +1 -0
  92. package/lib/typescript/src/index.d.ts.map +1 -0
  93. package/package.json +52 -40
  94. package/react-native-mmkv.podspec +17 -18
  95. package/react-native.config.js +20 -0
  96. package/src/LazyTurboModule.ts +62 -0
  97. package/src/MMKV.ts +19 -132
  98. package/src/NativeMmkv.ts +105 -0
  99. package/src/NativeMmkvPlatformContext.ts +14 -0
  100. package/src/Types.ts +89 -0
  101. package/src/__tests__/hooks.test.tsx +89 -0
  102. package/src/createMMKV.mock.ts +7 -3
  103. package/src/createMMKV.ts +10 -65
  104. package/src/createMMKV.web.ts +7 -2
  105. package/src/hooks.ts +17 -11
  106. package/android/src/main/java/com/reactnativemmkv/MmkvModule.java +0 -49
  107. package/android/src/main/java/com/reactnativemmkv/MmkvPackage.java +0 -26
  108. package/cpp/TypedArray.cpp +0 -322
  109. package/cpp/TypedArray.h +0 -153
  110. package/ios/JSIUtils.h +0 -38
  111. package/ios/JSIUtils.mm +0 -167
  112. package/ios/Mmkv.xcodeproj/project.pbxproj +0 -291
  113. package/ios/MmkvHostObject.h +0 -27
  114. package/ios/MmkvHostObject.mm +0 -295
  115. package/ios/MmkvModule.h +0 -5
  116. package/ios/MmkvModule.mm +0 -101
  117. package/lib/typescript/MMKV.d.ts +0 -142
  118. package/lib/typescript/MMKV.d.ts.map +0 -1
  119. package/lib/typescript/PlatformChecker.d.ts.map +0 -1
  120. package/lib/typescript/createMMKV.d.ts +0 -7
  121. package/lib/typescript/createMMKV.d.ts.map +0 -1
  122. package/lib/typescript/createMMKV.mock.d.ts +0 -3
  123. package/lib/typescript/createMMKV.mock.d.ts.map +0 -1
  124. package/lib/typescript/createMMKV.web.d.ts +0 -3
  125. package/lib/typescript/createMMKV.web.d.ts.map +0 -1
  126. package/lib/typescript/createTextEncoder.d.ts.map +0 -1
  127. package/lib/typescript/hooks.d.ts.map +0 -1
  128. package/lib/typescript/index.d.ts.map +0 -1
  129. /package/lib/typescript/{PlatformChecker.d.ts → src/PlatformChecker.d.ts} +0 -0
  130. /package/lib/typescript/{createTextEncoder.d.ts → src/createTextEncoder.d.ts} +0 -0
  131. /package/lib/typescript/{index.d.ts → src/index.d.ts} +0 -0
@@ -7,31 +7,39 @@
7
7
  //
8
8
 
9
9
  #include "MmkvHostObject.h"
10
- #include "TypedArray.h"
10
+ #include "Logger.h"
11
+ #include "MMKVManagedBuffer.h"
11
12
  #include <MMKV.h>
12
- #include <android/log.h>
13
13
  #include <string>
14
14
  #include <vector>
15
15
 
16
- MmkvHostObject::MmkvHostObject(const std::string& instanceId, std::string path,
17
- std::string cryptKey) {
18
- bool hasEncryptionKey = cryptKey.size() > 0;
19
- __android_log_print(ANDROID_LOG_INFO, "RNMMKV",
20
- "Creating MMKV instance \"%s\"... (Path: %s, Encrypted: %b)",
21
- instanceId.c_str(), path.c_str(), hasEncryptionKey);
16
+ using namespace mmkv;
17
+
18
+ MmkvHostObject::MmkvHostObject(const facebook::react::MMKVConfig& config) {
19
+ std::string path = config.path.has_value() ? config.path.value() : "";
20
+ std::string encryptionKey = config.encryptionKey.has_value() ? config.encryptionKey.value() : "";
21
+ bool hasEncryptionKey = encryptionKey.size() > 0;
22
+ Logger::log("RNMMKV", "Creating MMKV instance \"%s\"... (Path: %s, Encrypted: %s)",
23
+ config.id.c_str(), path.c_str(), hasEncryptionKey ? "true" : "false");
24
+
22
25
  std::string* pathPtr = path.size() > 0 ? &path : nullptr;
23
- std::string* cryptKeyPtr = cryptKey.size() > 0 ? &cryptKey : nullptr;
24
- instance = MMKV::mmkvWithID(instanceId, mmkv::DEFAULT_MMAP_SIZE, MMKV_SINGLE_PROCESS, cryptKeyPtr,
25
- pathPtr);
26
+ std::string* encryptionKeyPtr = encryptionKey.size() > 0 ? &encryptionKey : nullptr;
27
+ MMKVMode mode = getMMKVMode(config);
28
+
29
+ #ifdef __APPLE__
30
+ instance = MMKV::mmkvWithID(config.id, mode, encryptionKeyPtr, pathPtr);
31
+ #else
32
+ instance = MMKV::mmkvWithID(config.id, DEFAULT_MMAP_SIZE, mode, encryptionKeyPtr, pathPtr);
33
+ #endif
26
34
 
27
35
  if (instance == nullptr) {
28
36
  // Check if instanceId is invalid
29
- if (instanceId.empty()) {
37
+ if (config.id.empty()) {
30
38
  throw std::runtime_error("Failed to create MMKV instance! `id` cannot be empty!");
31
39
  }
32
40
 
33
41
  // Check if encryptionKey is invalid
34
- if (cryptKey.size() > 16) {
42
+ if (encryptionKey.size() > 16) {
35
43
  throw std::runtime_error(
36
44
  "Failed to create MMKV instance! `encryptionKey` cannot be longer than 16 bytes!");
37
45
  }
@@ -40,8 +48,18 @@ MmkvHostObject::MmkvHostObject(const std::string& instanceId, std::string path,
40
48
  }
41
49
  }
42
50
 
51
+ MmkvHostObject::~MmkvHostObject() {
52
+ if (instance != nullptr) {
53
+ std::string instanceId = instance->mmapID();
54
+ Logger::log("RNMMKV", "Destroying MMKV instance \"%s\"...", instanceId.c_str());
55
+ instance->clearMemoryCache();
56
+ }
57
+ instance = nullptr;
58
+ }
59
+
43
60
  std::vector<jsi::PropNameID> MmkvHostObject::getPropertyNames(jsi::Runtime& rt) {
44
61
  std::vector<jsi::PropNameID> result;
62
+ result.reserve(12);
45
63
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("set")));
46
64
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getBoolean")));
47
65
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getBuffer")));
@@ -52,26 +70,44 @@ std::vector<jsi::PropNameID> MmkvHostObject::getPropertyNames(jsi::Runtime& rt)
52
70
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getAllKeys")));
53
71
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("deleteAll")));
54
72
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("recrypt")));
73
+ result.push_back(jsi::PropNameID::forUtf8(rt, std::string("trim")));
74
+ result.push_back(jsi::PropNameID::forUtf8(rt, std::string("size")));
55
75
  return result;
56
76
  }
57
77
 
78
+ MMKVMode MmkvHostObject::getMMKVMode(const facebook::react::MMKVConfig& config) {
79
+ if (!config.mode.has_value()) {
80
+ return MMKVMode::MMKV_SINGLE_PROCESS;
81
+ }
82
+ auto mode = config.mode.value();
83
+ switch (mode) {
84
+ case facebook::react::MmkvCxxMode::SINGLE_PROCESS:
85
+ return MMKVMode::MMKV_SINGLE_PROCESS;
86
+ case facebook::react::MmkvCxxMode::MULTI_PROCESS:
87
+ return MMKVMode::MMKV_MULTI_PROCESS;
88
+ default:
89
+ throw std::runtime_error("Invalid MMKV Mode value!");
90
+ }
91
+ }
92
+
58
93
  jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propNameId) {
59
94
  auto propName = propNameId.utf8(runtime);
60
95
  auto funcName = "MMKV." + propName;
61
96
 
62
97
  if (propName == "set") {
63
- // MMKV.set(key: string, value: string | number | bool | Uint8Array)
98
+ // MMKV.set(key: string, value: string | number | bool | ArrayBuffer)
64
99
  return jsi::Function::createFromHostFunction(
65
100
  runtime, jsi::PropNameID::forAscii(runtime, funcName),
66
101
  2, // key, value
67
102
  [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
68
103
  size_t count) -> jsi::Value {
69
- if (!arguments[0].isString()) {
104
+ if (count != 2 || !arguments[0].isString()) {
105
+ [[unlikely]];
70
106
  throw jsi::JSError(runtime,
71
107
  "MMKV::set: First argument ('key') has to be of type string!");
72
108
  }
73
109
 
74
- auto keyName = arguments[0].getString(runtime).utf8(runtime);
110
+ auto keyName = arguments[0].asString(runtime).utf8(runtime);
75
111
 
76
112
  if (arguments[1].isBool()) {
77
113
  // bool
@@ -81,22 +117,21 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
81
117
  instance->set(arguments[1].getNumber(), keyName);
82
118
  } else if (arguments[1].isString()) {
83
119
  // string
84
- auto stringValue = arguments[1].getString(runtime).utf8(runtime);
120
+ auto stringValue = arguments[1].asString(runtime).utf8(runtime);
85
121
  instance->set(stringValue, keyName);
86
122
  } else if (arguments[1].isObject()) {
87
123
  // object
88
124
  auto object = arguments[1].asObject(runtime);
89
- if (isTypedArray(runtime, object)) {
90
- // Uint8Array
91
- auto typedArray = getTypedArray(runtime, object);
92
- auto bufferValue = typedArray.getBuffer(runtime);
93
- mmkv::MMBuffer buffer(bufferValue.data(runtime), bufferValue.size(runtime),
94
- mmkv::MMBufferCopyFlag::MMBufferNoCopy);
95
- instance->set(buffer, keyName);
125
+ if (object.isArrayBuffer(runtime)) {
126
+ // ArrayBuffer
127
+ auto arrayBuffer = object.getArrayBuffer(runtime);
128
+ MMBuffer data(arrayBuffer.data(runtime), arrayBuffer.size(runtime), MMBufferNoCopy);
129
+ instance->set(data, keyName);
96
130
  } else {
97
131
  // unknown object
98
132
  throw jsi::JSError(
99
- runtime, "MMKV::set: 'value' argument is an object, but not of type Uint8Array!");
133
+ runtime,
134
+ "MMKV::set: 'value' argument is an object, but not of type ArrayBuffer!");
100
135
  }
101
136
  } else {
102
137
  // unknown type
@@ -116,62 +151,65 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
116
151
  1, // key
117
152
  [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
118
153
  size_t count) -> jsi::Value {
119
- if (!arguments[0].isString()) {
154
+ if (count != 1 || !arguments[0].isString()) {
155
+ [[unlikely]];
120
156
  throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
121
157
  }
122
158
 
123
- auto keyName = arguments[0].getString(runtime).utf8(runtime);
159
+ auto keyName = arguments[0].asString(runtime).utf8(runtime);
124
160
  bool hasValue;
125
161
  auto value = instance->getBool(keyName, false, &hasValue);
126
- if (hasValue) {
127
- return jsi::Value(value);
128
- } else {
162
+ if (!hasValue) {
163
+ [[unlikely]];
129
164
  return jsi::Value::undefined();
130
165
  }
166
+ return jsi::Value(value);
131
167
  });
132
168
  }
133
169
 
134
- if (propName == "getString") {
135
- // MMKV.getString(key: string)
170
+ if (propName == "getNumber") {
171
+ // MMKV.getNumber(key: string)
136
172
  return jsi::Function::createFromHostFunction(
137
173
  runtime, jsi::PropNameID::forAscii(runtime, funcName),
138
174
  1, // key
139
175
  [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
140
176
  size_t count) -> jsi::Value {
141
- if (!arguments[0].isString()) {
177
+ if (count != 1 || !arguments[0].isString()) {
178
+ [[unlikely]];
142
179
  throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
143
180
  }
144
181
 
145
- auto keyName = arguments[0].getString(runtime).utf8(runtime);
146
- std::string result;
147
- bool hasValue = instance->getString(keyName, result);
148
- if (hasValue) {
149
- return jsi::Value(runtime, jsi::String::createFromUtf8(runtime, result));
150
- } else {
182
+ auto keyName = arguments[0].asString(runtime).utf8(runtime);
183
+ bool hasValue;
184
+ auto value = instance->getDouble(keyName, 0.0, &hasValue);
185
+ if (!hasValue) {
186
+ [[unlikely]];
151
187
  return jsi::Value::undefined();
152
188
  }
189
+ return jsi::Value(value);
153
190
  });
154
191
  }
155
192
 
156
- if (propName == "getNumber") {
157
- // MMKV.getNumber(key: string)
193
+ if (propName == "getString") {
194
+ // MMKV.getString(key: string)
158
195
  return jsi::Function::createFromHostFunction(
159
196
  runtime, jsi::PropNameID::forAscii(runtime, funcName),
160
197
  1, // key
161
198
  [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
162
199
  size_t count) -> jsi::Value {
163
- if (!arguments[0].isString()) {
200
+ if (count != 1 || !arguments[0].isString()) {
201
+ [[unlikely]];
164
202
  throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
165
203
  }
166
204
 
167
- auto keyName = arguments[0].getString(runtime).utf8(runtime);
168
- bool hasValue;
169
- auto value = instance->getDouble(keyName, 0.0, &hasValue);
170
- if (hasValue) {
171
- return jsi::Value(value);
172
- } else {
205
+ auto keyName = arguments[0].asString(runtime).utf8(runtime);
206
+ std::string result;
207
+ bool hasValue = instance->getString(keyName, result);
208
+ if (!hasValue) {
209
+ [[unlikely]];
173
210
  return jsi::Value::undefined();
174
211
  }
212
+ return jsi::Value(runtime, jsi::String::createFromUtf8(runtime, result));
175
213
  });
176
214
  }
177
215
 
@@ -182,24 +220,20 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
182
220
  1, // key
183
221
  [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
184
222
  size_t count) -> jsi::Value {
185
- if (!arguments[0].isString()) {
223
+ if (count != 1 || !arguments[0].isString()) {
224
+ [[unlikely]];
186
225
  throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
187
226
  }
188
227
 
189
- auto keyName = arguments[0].getString(runtime).utf8(runtime);
228
+ auto keyName = arguments[0].asString(runtime).utf8(runtime);
190
229
  mmkv::MMBuffer buffer;
191
230
  bool hasValue = instance->getBytes(keyName, buffer);
192
- if (hasValue) {
193
- auto length = buffer.length();
194
- TypedArray<TypedArrayKind::Uint8Array> array(runtime, length);
195
- auto data = static_cast<const unsigned char*>(buffer.getPtr());
196
- std::vector<unsigned char> vector(length);
197
- vector.assign(data, data + length);
198
- array.update(runtime, vector);
199
- return array;
200
- } else {
231
+ if (!hasValue) {
232
+ [[unlikely]];
201
233
  return jsi::Value::undefined();
202
234
  }
235
+ auto mutableData = std::make_shared<MMKVManagedBuffer>(std::move(buffer));
236
+ return jsi::ArrayBuffer(runtime, mutableData);
203
237
  });
204
238
  }
205
239
 
@@ -210,11 +244,12 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
210
244
  1, // key
211
245
  [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
212
246
  size_t count) -> jsi::Value {
213
- if (!arguments[0].isString()) {
247
+ if (count != 1 || !arguments[0].isString()) {
248
+ [[unlikely]];
214
249
  throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
215
250
  }
216
251
 
217
- auto keyName = arguments[0].getString(runtime).utf8(runtime);
252
+ auto keyName = arguments[0].asString(runtime).utf8(runtime);
218
253
  bool containsKey = instance->containsKey(keyName);
219
254
  return jsi::Value(containsKey);
220
255
  });
@@ -227,11 +262,12 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
227
262
  1, // key
228
263
  [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
229
264
  size_t count) -> jsi::Value {
230
- if (!arguments[0].isString()) {
265
+ if (count != 1 || !arguments[0].isString()) {
266
+ [[unlikely]];
231
267
  throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
232
268
  }
233
269
 
234
- auto keyName = arguments[0].getString(runtime).utf8(runtime);
270
+ auto keyName = arguments[0].asString(runtime).utf8(runtime);
235
271
  instance->removeValueForKey(keyName);
236
272
  return jsi::Value::undefined();
237
273
  });
@@ -270,6 +306,12 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
270
306
  1, // encryptionKey
271
307
  [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
272
308
  size_t count) -> jsi::Value {
309
+ if (count != 1) {
310
+ [[unlikely]];
311
+ throw jsi::JSError(runtime, "Expected 1 argument (encryptionKey), but received " +
312
+ std::to_string(count) + "!");
313
+ }
314
+
273
315
  if (arguments[0].isUndefined()) {
274
316
  // reset encryption key to "no encryption"
275
317
  instance->reKey(std::string());
@@ -278,13 +320,34 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
278
320
  auto encryptionKey = arguments[0].getString(runtime).utf8(runtime);
279
321
  instance->reKey(encryptionKey);
280
322
  } else {
323
+ // Invalid argument (maybe object?)
281
324
  throw jsi::JSError(
282
325
  runtime,
283
326
  "First argument ('encryptionKey') has to be of type string (or undefined)!");
284
327
  }
328
+
285
329
  return jsi::Value::undefined();
286
330
  });
287
331
  }
288
332
 
333
+ if (propName == "trim") {
334
+ // MMKV.trim()
335
+ return jsi::Function::createFromHostFunction(
336
+ runtime, jsi::PropNameID::forAscii(runtime, funcName), 0,
337
+ [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
338
+ size_t count) -> jsi::Value {
339
+ instance->clearMemoryCache();
340
+ instance->trim();
341
+
342
+ return jsi::Value::undefined();
343
+ });
344
+ }
345
+
346
+ if (propName == "size") {
347
+ // MMKV.size
348
+ size_t size = instance->actualSize();
349
+ return jsi::Value(static_cast<int>(size));
350
+ }
351
+
289
352
  return jsi::Value::undefined();
290
353
  }
@@ -8,19 +8,25 @@
8
8
 
9
9
  #pragma once
10
10
 
11
- #include <MMKV.h>
11
+ #include "MMKV.h"
12
+ #include "NativeMmkvModule.h"
12
13
  #include <jsi/jsi.h>
13
14
 
14
15
  using namespace facebook;
16
+ using namespace mmkv;
15
17
 
16
- class JSI_EXPORT MmkvHostObject : public jsi::HostObject {
18
+ class MmkvHostObject : public jsi::HostObject {
17
19
  public:
18
- MmkvHostObject(const std::string& instanceId, std::string path, std::string cryptKey);
20
+ MmkvHostObject(const facebook::react::MMKVConfig& config);
21
+ ~MmkvHostObject();
19
22
 
20
23
  public:
21
24
  jsi::Value get(jsi::Runtime&, const jsi::PropNameID& name) override;
22
25
  std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& rt) override;
23
26
 
27
+ private:
28
+ static MMKVMode getMMKVMode(const facebook::react::MMKVConfig& config);
29
+
24
30
  private:
25
31
  MMKV* instance;
26
32
  };
@@ -0,0 +1,46 @@
1
+ //
2
+ // NativeMmkvModule.cpp
3
+ // react-native-mmkv
4
+ //
5
+ // Created by Marc Rousavy on 25.03.2024.
6
+ //
7
+
8
+ #include "NativeMmkvModule.h"
9
+ #include "Logger.h"
10
+ #include "MMKV.h"
11
+ #include "MmkvHostObject.h"
12
+
13
+ namespace facebook::react {
14
+
15
+ NativeMmkvModule::NativeMmkvModule(std::shared_ptr<CallInvoker> jsInvoker)
16
+ : NativeMmkvCxxSpec(jsInvoker) {}
17
+
18
+ bool NativeMmkvModule::initialize(jsi::Runtime& runtime, std::string basePath) {
19
+ if (basePath.size() < 1) {
20
+ throw jsi::JSError(runtime, "Path cannot be empty!");
21
+ }
22
+
23
+ Logger::log("RNMMKV", "Initializing MMKV at %s...", basePath.c_str());
24
+
25
+ #ifdef DEBUG
26
+ MMKVLogLevel logLevel = MMKVLogDebug;
27
+ #else
28
+ MMKVLogLevel logLevel = MMKVLogWarning;
29
+ #endif
30
+
31
+ MMKV::initializeMMKV(basePath, logLevel);
32
+
33
+ return true;
34
+ }
35
+
36
+ NativeMmkvModule::~NativeMmkvModule() {
37
+ Logger::log("RNMMKV", "Closing all MMKV instances...");
38
+ MMKV::onExit();
39
+ }
40
+
41
+ jsi::Object NativeMmkvModule::createMMKV(jsi::Runtime& runtime, MMKVConfig config) {
42
+ auto instance = std::make_shared<MmkvHostObject>(config);
43
+ return jsi::Object::createFromHostObject(runtime, instance);
44
+ }
45
+
46
+ } // namespace facebook::react
@@ -0,0 +1,37 @@
1
+ //
2
+ // NativeMmkvModule.h
3
+ // react-native-mmkv
4
+ //
5
+ // Created by Marc Rousavy on 25.03.2024.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #if __has_include(<React-Codegen/RNMmkvSpecJSI.h>)
11
+ // CocoaPods include (iOS)
12
+ #include <React-Codegen/RNMmkvSpecJSI.h>
13
+ #elif __has_include(<RNMmkvSpecJSI.h>)
14
+ // CMake include on Android
15
+ #include <RNMmkvSpecJSI.h>
16
+ #else
17
+ #error Cannot find react-native-mmkv spec! Try cleaning your cache and re-running CodeGen!
18
+ #endif
19
+
20
+ namespace facebook::react {
21
+
22
+ // The MMKVConfiguration type from JS
23
+ using MMKVConfig = MmkvCxxConfiguration<std::string, std::optional<std::string>,
24
+ std::optional<std::string>, std::optional<MmkvCxxMode>>;
25
+ template <> struct Bridging<MMKVConfig> : MmkvCxxConfigurationBridging<MMKVConfig> {};
26
+
27
+ // The TurboModule itself
28
+ class NativeMmkvModule : public NativeMmkvCxxSpec<NativeMmkvModule> {
29
+ public:
30
+ NativeMmkvModule(std::shared_ptr<CallInvoker> jsInvoker);
31
+ ~NativeMmkvModule();
32
+
33
+ bool initialize(jsi::Runtime& runtime, std::string basePath);
34
+ jsi::Object createMMKV(jsi::Runtime& runtime, MMKVConfig config);
35
+ };
36
+
37
+ } // namespace facebook::react
@@ -0,0 +1,16 @@
1
+ //
2
+ // AppleLogger.m
3
+ // react-native-mmkv
4
+ //
5
+ // Created by Marc Rousavy on 25.03.24.
6
+ //
7
+
8
+ #import "Logger.h"
9
+ #import <Foundation/Foundation.h>
10
+
11
+ void Logger::log(const std::string& tag, const std::string& message) {
12
+ #pragma clang diagnostic push
13
+ #pragma clang diagnostic ignored "-Wformat-security"
14
+ NSLog(@"[%s]: %s", tag.c_str(), message.c_str());
15
+ #pragma clang diagnostic pop
16
+ }
@@ -0,0 +1,25 @@
1
+ //
2
+ // MmkvOnLoad.mm
3
+ // react-native-mmkv
4
+ //
5
+ // Created by Marc Rousavy on 27.03.24.
6
+ //
7
+
8
+ #import "NativeMmkvModule.h"
9
+ #import <Foundation/Foundation.h>
10
+ #import <ReactCommon/CxxTurboModuleUtils.h>
11
+
12
+ @interface MMKVOnLoad : NSObject
13
+ @end
14
+
15
+ @implementation MMKVOnLoad
16
+
17
+ + (void)load {
18
+ facebook::react::registerCxxModuleToGlobalModuleMap(
19
+ std::string(facebook::react::NativeMmkvModule::kModuleName),
20
+ [&](std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
21
+ return std::make_shared<facebook::react::NativeMmkvModule>(jsInvoker);
22
+ });
23
+ }
24
+
25
+ @end
@@ -0,0 +1,19 @@
1
+ //
2
+ // RTNMmkvPlatformContext.h
3
+ // Pods
4
+ //
5
+ // Created by Marc Rousavy on 27.03.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #import <Foundation/Foundation.h>
11
+ #import <RNMmkvSpec/RNMmkvSpec.h>
12
+
13
+ NS_ASSUME_NONNULL_BEGIN
14
+
15
+ @interface MmkvPlatformContext : NSObject <NativeMmkvPlatformContextSpec>
16
+
17
+ @end
18
+
19
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,37 @@
1
+ //
2
+ // AppleMmkvPlatformContext.m
3
+ // react-native-mmkv
4
+ //
5
+ // Created by Marc Rousavy on 25.03.24.
6
+ //
7
+
8
+ #import "MmkvPlatformContext.h"
9
+ #import <Foundation/Foundation.h>
10
+
11
+ @implementation MmkvPlatformContext
12
+
13
+ RCT_EXPORT_MODULE()
14
+
15
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
16
+ (const facebook::react::ObjCTurboModule::InitParams&)params {
17
+ return std::make_shared<facebook::react::NativeMmkvPlatformContextSpecJSI>(params);
18
+ }
19
+
20
+ - (NSString*)getBaseDirectory {
21
+ #if TARGET_OS_TV
22
+ NSArray* paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
23
+ #else
24
+ NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
25
+ #endif
26
+ NSString* documentPath = (NSString*)[paths firstObject];
27
+ if ([documentPath length] > 0) {
28
+ NSString* basePath = [documentPath stringByAppendingPathComponent:@"mmkv"];
29
+ return basePath;
30
+ } else {
31
+ @throw [NSException exceptionWithName:@"BasePathNotFound"
32
+ reason:@"Cannot find base-path to store MMKV files!"
33
+ userInfo:nil];
34
+ }
35
+ }
36
+
37
+ @end
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getLazyTurboModule = getLazyTurboModule;
7
+ var _reactNative = require("react-native");
8
+ /**
9
+ * Lazily get a TurboModule by wrapping it in a Proxy.
10
+ */
11
+ function getLazyTurboModule(initializeTurboModule) {
12
+ const proxy = new Proxy({
13
+ module: null
14
+ }, {
15
+ get: (target, property) => {
16
+ if (target.module == null) {
17
+ // Target is null, let's initialize it!
18
+ target.module = initializeTurboModule();
19
+ if (target.module == null) {
20
+ // TurboModule not found, something went wrong!
21
+ let message = 'Failed to create a new MMKV instance: The native MMKV Module could not be found.';
22
+ message += '\n* Make sure react-native-mmkv is correctly autolinked (run `npx react-native config` to verify)';
23
+ if (_reactNative.Platform.OS === 'ios' || _reactNative.Platform.OS === 'macos') {
24
+ message += '\n* Make sure you ran `pod install` in the ios/ directory.';
25
+ }
26
+ if (_reactNative.Platform.OS === 'android') {
27
+ message += '\n* Make sure gradle is synced.';
28
+ }
29
+ // check if Expo
30
+ const ExpoConstants = _reactNative.NativeModules.NativeUnimoduleProxy?.modulesConstants?.ExponentConstants;
31
+ if (ExpoConstants != null) {
32
+ if (ExpoConstants.appOwnership === 'expo') {
33
+ // We're running Expo Go
34
+ throw new Error('react-native-mmkv is not supported in Expo Go! Use EAS (`expo prebuild`) or eject to a bare workflow instead.');
35
+ } else {
36
+ // We're running Expo bare / standalone
37
+ message += '\n* Make sure you ran `expo prebuild`.';
38
+ }
39
+ }
40
+ message += '\n* Make sure you rebuilt the app.';
41
+ throw new Error(message);
42
+ }
43
+ }
44
+ return target.module[property];
45
+ }
46
+ });
47
+ return proxy;
48
+ }
49
+ //# sourceMappingURL=LazyTurboModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","getLazyTurboModule","initializeTurboModule","proxy","Proxy","module","get","target","property","message","Platform","OS","ExpoConstants","NativeModules","NativeUnimoduleProxy","modulesConstants","ExponentConstants","appOwnership","Error"],"sourceRoot":"../../src","sources":["LazyTurboModule.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAMA;AACA;AACA;AACO,SAASC,kBAAkBA,CAChCC,qBAAqC,EAClC;EACH,MAAMC,KAAK,GAAG,IAAIC,KAAK,CACrB;IACEC,MAAM,EAAE;EACV,CAAC,EACD;IACEC,GAAG,EAAEA,CAACC,MAAM,EAAEC,QAAQ,KAAK;MACzB,IAAID,MAAM,CAACF,MAAM,IAAI,IAAI,EAAE;QACzB;QACAE,MAAM,CAACF,MAAM,GAAGH,qBAAqB,CAAC,CAAC;QAEvC,IAAIK,MAAM,CAACF,MAAM,IAAI,IAAI,EAAE;UACzB;UACA,IAAII,OAAO,GACT,kFAAkF;UACpFA,OAAO,IACL,mGAAmG;UACrG,IAAIC,qBAAQ,CAACC,EAAE,KAAK,KAAK,IAAID,qBAAQ,CAACC,EAAE,KAAK,OAAO,EAAE;YACpDF,OAAO,IACL,4DAA4D;UAChE;UACA,IAAIC,qBAAQ,CAACC,EAAE,KAAK,SAAS,EAAE;YAC7BF,OAAO,IAAI,iCAAiC;UAC9C;UACA;UACA,MAAMG,aAAa,GACjBC,0BAAa,CAACC,oBAAoB,EAAEC,gBAAgB,EAChDC,iBAAiB;UACvB,IAAIJ,aAAa,IAAI,IAAI,EAAE;YACzB,IAAIA,aAAa,CAACK,YAAY,KAAK,MAAM,EAAE;cACzC;cACA,MAAM,IAAIC,KAAK,CACb,+GACF,CAAC;YACH,CAAC,MAAM;cACL;cACAT,OAAO,IAAI,wCAAwC;YACrD;UACF;UAEAA,OAAO,IAAI,oCAAoC;UAC/C,MAAM,IAAIS,KAAK,CAACT,OAAO,CAAC;QAC1B;MACF;MAEA,OAAOF,MAAM,CAACF,MAAM,CAACG,QAAQ,CAAY;IAC3C;EACF,CACF,CAAC;EACD,OAAOL,KAAK;AACd","ignoreList":[]}