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

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 (116) 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 +7 -1
  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 +37 -0
  20. package/{android/src/main/cpp → cpp}/MmkvHostObject.cpp +126 -63
  21. package/{android/src/main/cpp → cpp}/MmkvHostObject.h +14 -3
  22. package/cpp/NativeMmkvModule.cpp +40 -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/MMKV.js +34 -4
  29. package/lib/commonjs/MMKV.js.map +1 -1
  30. package/lib/commonjs/NativeMmkv.js +66 -0
  31. package/lib/commonjs/NativeMmkv.js.map +1 -0
  32. package/lib/commonjs/NativeMmkvPlatformContext.js +9 -0
  33. package/lib/commonjs/NativeMmkvPlatformContext.js.map +1 -0
  34. package/lib/commonjs/PlatformChecker.js.map +1 -1
  35. package/lib/commonjs/createMMKV.js +7 -43
  36. package/lib/commonjs/createMMKV.js.map +1 -1
  37. package/lib/commonjs/createMMKV.mock.js +5 -1
  38. package/lib/commonjs/createMMKV.mock.js.map +1 -1
  39. package/lib/commonjs/createMMKV.web.js +8 -4
  40. package/lib/commonjs/createMMKV.web.js.map +1 -1
  41. package/lib/commonjs/createTextEncoder.js.map +1 -1
  42. package/lib/commonjs/hooks.js +11 -10
  43. package/lib/commonjs/hooks.js.map +1 -1
  44. package/lib/commonjs/index.js.map +1 -1
  45. package/lib/module/MMKV.js +23 -4
  46. package/lib/module/MMKV.js.map +1 -1
  47. package/lib/module/NativeMmkv.js +63 -0
  48. package/lib/module/NativeMmkv.js.map +1 -0
  49. package/lib/module/NativeMmkvPlatformContext.js +3 -0
  50. package/lib/module/NativeMmkvPlatformContext.js.map +1 -0
  51. package/lib/module/PlatformChecker.js.map +1 -1
  52. package/lib/module/createMMKV.js +7 -43
  53. package/lib/module/createMMKV.js.map +1 -1
  54. package/lib/module/createMMKV.mock.js +5 -1
  55. package/lib/module/createMMKV.mock.js.map +1 -1
  56. package/lib/module/createMMKV.web.js +6 -4
  57. package/lib/module/createMMKV.web.js.map +1 -1
  58. package/lib/module/createTextEncoder.js.map +1 -1
  59. package/lib/module/hooks.js +7 -2
  60. package/lib/module/hooks.js.map +1 -1
  61. package/lib/module/index.js.map +1 -1
  62. package/lib/typescript/{MMKV.d.ts → src/MMKV.d.ts} +26 -49
  63. package/lib/typescript/src/MMKV.d.ts.map +1 -0
  64. package/lib/typescript/src/NativeMmkv.d.ts +79 -0
  65. package/lib/typescript/src/NativeMmkv.d.ts.map +1 -0
  66. package/lib/typescript/src/NativeMmkvPlatformContext.d.ts +9 -0
  67. package/lib/typescript/src/NativeMmkvPlatformContext.d.ts.map +1 -0
  68. package/lib/typescript/src/PlatformChecker.d.ts.map +1 -0
  69. package/lib/typescript/src/__tests__/hooks.test.d.ts +2 -0
  70. package/lib/typescript/src/__tests__/hooks.test.d.ts.map +1 -0
  71. package/lib/typescript/src/createMMKV.d.ts +3 -0
  72. package/lib/typescript/src/createMMKV.d.ts.map +1 -0
  73. package/lib/typescript/src/createMMKV.mock.d.ts +3 -0
  74. package/lib/typescript/src/createMMKV.mock.d.ts.map +1 -0
  75. package/lib/typescript/src/createMMKV.web.d.ts +3 -0
  76. package/lib/typescript/src/createMMKV.web.d.ts.map +1 -0
  77. package/lib/typescript/src/createTextEncoder.d.ts.map +1 -0
  78. package/lib/typescript/{hooks.d.ts → src/hooks.d.ts} +7 -4
  79. package/lib/typescript/src/hooks.d.ts.map +1 -0
  80. package/lib/typescript/src/index.d.ts.map +1 -0
  81. package/package.json +49 -40
  82. package/react-native-mmkv.podspec +17 -18
  83. package/src/MMKV.ts +40 -62
  84. package/src/NativeMmkv.ts +132 -0
  85. package/src/NativeMmkvPlatformContext.ts +12 -0
  86. package/src/__tests__/hooks.test.tsx +88 -0
  87. package/src/createMMKV.mock.ts +7 -3
  88. package/src/createMMKV.ts +9 -63
  89. package/src/createMMKV.web.ts +6 -2
  90. package/src/hooks.ts +17 -11
  91. package/android/src/main/java/com/reactnativemmkv/MmkvModule.java +0 -49
  92. package/android/src/main/java/com/reactnativemmkv/MmkvPackage.java +0 -26
  93. package/cpp/TypedArray.cpp +0 -322
  94. package/cpp/TypedArray.h +0 -153
  95. package/ios/JSIUtils.h +0 -38
  96. package/ios/JSIUtils.mm +0 -167
  97. package/ios/Mmkv.xcodeproj/project.pbxproj +0 -291
  98. package/ios/MmkvHostObject.h +0 -27
  99. package/ios/MmkvHostObject.mm +0 -295
  100. package/ios/MmkvModule.h +0 -5
  101. package/ios/MmkvModule.mm +0 -101
  102. package/lib/typescript/MMKV.d.ts.map +0 -1
  103. package/lib/typescript/PlatformChecker.d.ts.map +0 -1
  104. package/lib/typescript/createMMKV.d.ts +0 -7
  105. package/lib/typescript/createMMKV.d.ts.map +0 -1
  106. package/lib/typescript/createMMKV.mock.d.ts +0 -3
  107. package/lib/typescript/createMMKV.mock.d.ts.map +0 -1
  108. package/lib/typescript/createMMKV.web.d.ts +0 -3
  109. package/lib/typescript/createMMKV.web.d.ts.map +0 -1
  110. package/lib/typescript/createTextEncoder.d.ts.map +0 -1
  111. package/lib/typescript/hooks.d.ts.map +0 -1
  112. package/lib/typescript/index.d.ts.map +0 -1
  113. /package/lib/typescript/{PlatformChecker.d.ts → src/PlatformChecker.d.ts} +0 -0
  114. /package/lib/typescript/{createTextEncoder.d.ts → src/createTextEncoder.d.ts} +0 -0
  115. /package/lib/typescript/{index.d.ts → src/index.d.ts} +0 -0
  116. /package/src/{index.ts → index.tsx} +0 -0
@@ -1,3 +1,3 @@
1
- <manifest package="com.reactnativemmkv" xmlns:android="http://schemas.android.com/apk/res/android">
2
-
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.mrousavy.mmkv">
3
3
  </manifest>
@@ -1,3 +1,2 @@
1
1
  <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
-
3
2
  </manifest>
@@ -0,0 +1,16 @@
1
+ //
2
+ // AndroidLogger.cpp
3
+ // react-native-mmkv
4
+ //
5
+ // Created by Marc Rousavy on 05.03.24.
6
+ //
7
+
8
+ #include "Logger.h"
9
+ #include <android/log.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
+ __android_log_print(ANDROID_LOG_INFO, tag.c_str(), message.c_str());
15
+ #pragma clang diagnostic pop
16
+ }
@@ -1,83 +1,7 @@
1
- #include "MmkvHostObject.h"
2
- #include "TypedArray.h"
3
- #include <MMKV.h>
4
1
  #include <jni.h>
5
- #include <jsi/jsi.h>
6
2
 
7
- using namespace facebook;
8
-
9
- std::string getPropertyAsStringOrEmptyFromObject(jsi::Object& object,
10
- const std::string& propertyName,
11
- jsi::Runtime& runtime) {
12
- jsi::Value value = object.getProperty(runtime, propertyName.c_str());
13
- return value.isString() ? value.asString(runtime).utf8(runtime) : "";
14
- }
15
-
16
- void install(jsi::Runtime& jsiRuntime) {
17
- // MMKV.createNewInstance()
18
- auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction(
19
- jsiRuntime, jsi::PropNameID::forAscii(jsiRuntime, "mmkvCreateNewInstance"), 1,
20
- [](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
21
- size_t count) -> jsi::Value {
22
- if (count != 1) {
23
- throw jsi::JSError(runtime, "MMKV.createNewInstance(..) expects one argument (object)!");
24
- }
25
- jsi::Object config = arguments[0].asObject(runtime);
26
-
27
- std::string instanceId = getPropertyAsStringOrEmptyFromObject(config, "id", runtime);
28
- std::string path = getPropertyAsStringOrEmptyFromObject(config, "path", runtime);
29
- std::string encryptionKey =
30
- getPropertyAsStringOrEmptyFromObject(config, "encryptionKey", runtime);
31
-
32
- auto instance = std::make_shared<MmkvHostObject>(instanceId, path, encryptionKey);
33
- return jsi::Object::createFromHostObject(runtime, instance);
34
- });
35
- jsiRuntime.global().setProperty(jsiRuntime, "mmkvCreateNewInstance",
36
- std::move(mmkvCreateNewInstance));
37
-
38
- // Adds the PropNameIDCache object to the Runtime. If the Runtime gets destroyed, the Object gets
39
- // destroyed and the cache gets invalidated.
40
- auto propNameIdCache = std::make_shared<InvalidateCacheOnDestroy>(jsiRuntime);
41
- jsiRuntime.global().setProperty(jsiRuntime, "mmkvArrayBufferPropNameIdCache",
42
- jsi::Object::createFromHostObject(jsiRuntime, propNameIdCache));
43
- }
44
-
45
- std::string jstringToStdString(JNIEnv* env, jstring jStr) {
46
- if (!jStr)
47
- return "";
48
-
49
- const auto stringClass = env->GetObjectClass(jStr);
50
- const auto getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
51
- const auto stringJbytes =
52
- (jbyteArray)env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8"));
53
-
54
- auto length = (size_t)env->GetArrayLength(stringJbytes);
55
- auto pBytes = env->GetByteArrayElements(stringJbytes, nullptr);
56
-
57
- std::string ret = std::string((char*)pBytes, length);
58
- env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
59
-
60
- env->DeleteLocalRef(stringJbytes);
61
- env->DeleteLocalRef(stringClass);
62
- return ret;
63
- }
64
-
65
- extern "C" JNIEXPORT void JNICALL Java_com_reactnativemmkv_MmkvModule_nativeInstall(JNIEnv* env,
66
- jobject clazz,
67
- jlong jsiPtr,
68
- jstring path) {
69
- #if DEBUG
70
- MMKVLogLevel logLevel = MMKVLogDebug;
71
- #else
72
- MMKVLogLevel logLevel = MMKVLogError;
73
- #endif
74
- std::string storageDirectory = jstringToStdString(env, path);
75
- MMKV::initializeMMKV(storageDirectory, logLevel);
76
-
77
- auto runtime = reinterpret_cast<jsi::Runtime*>(jsiPtr);
78
- if (runtime) {
79
- install(*runtime);
80
- }
81
- // if runtime was nullptr, MMKV will not be installed. This should only happen while Remote
82
- // Debugging (Chrome), but will be weird either way.
3
+ extern "C" JNIEXPORT jdouble JNICALL Java_com_mmkv_MmkvModule_nativeMultiply(JNIEnv* env,
4
+ jclass type, jdouble a,
5
+ jdouble b) {
6
+ return 5.0;
83
7
  }
@@ -0,0 +1,44 @@
1
+ package com.mrousavy.mmkv;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+
6
+ import com.facebook.react.bridge.NativeModule;
7
+ import com.facebook.react.bridge.ReactApplicationContext;
8
+ import com.facebook.react.module.model.ReactModuleInfo;
9
+ import com.facebook.react.module.model.ReactModuleInfoProvider;
10
+ import com.facebook.react.TurboReactPackage;
11
+
12
+ import java.util.HashMap;
13
+ import java.util.Map;
14
+
15
+ public class MmkvPackage extends TurboReactPackage {
16
+ @Nullable
17
+ @Override
18
+ public NativeModule getModule(String name, @NonNull ReactApplicationContext reactContext) {
19
+ if (name.equals(MmkvPlatformContextModule.NAME)) {
20
+ return new MmkvPlatformContextModule(reactContext);
21
+ } else {
22
+ return null;
23
+ }
24
+ }
25
+
26
+ @Override
27
+ public ReactModuleInfoProvider getReactModuleInfoProvider() {
28
+ return () -> {
29
+ final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
30
+ moduleInfos.put(
31
+ MmkvPlatformContextModule.NAME,
32
+ new ReactModuleInfo(
33
+ MmkvPlatformContextModule.NAME,
34
+ MmkvPlatformContextModule.NAME,
35
+ false, // canOverrideExistingModule
36
+ false, // needsEagerInit
37
+ true, // hasConstants
38
+ false, // isCxxModule
39
+ true // isTurboModule
40
+ ));
41
+ return moduleInfos;
42
+ };
43
+ }
44
+ }
@@ -0,0 +1,17 @@
1
+ package com.mrousavy.mmkv;
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext;
4
+
5
+ public class MmkvPlatformContextModule extends NativeMmkvPlatformContextSpec {
6
+ private final ReactApplicationContext context;
7
+
8
+ public MmkvPlatformContextModule(ReactApplicationContext reactContext) {
9
+ super(reactContext);
10
+ context = reactContext;
11
+ }
12
+
13
+ @Override
14
+ public String getBaseDirectory() {
15
+ return context.getFilesDir().getAbsolutePath() + "/mmkv";
16
+ }
17
+ }
package/cpp/Logger.h ADDED
@@ -0,0 +1,35 @@
1
+ //
2
+ // Logger.h
3
+ // react-native-mmkv
4
+ //
5
+ // Created by Marc Rousavy on 25.03.24.
6
+ //
7
+
8
+ #include <string>
9
+
10
+ class Logger {
11
+ private:
12
+ Logger() = delete;
13
+
14
+ private:
15
+ template <typename... Args>
16
+ static std::string string_format(const std::string& format, Args... args) {
17
+ int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
18
+ if (size_s <= 0) {
19
+ throw std::runtime_error("Failed to format string!");
20
+ }
21
+ auto size = static_cast<size_t>(size_s);
22
+ std::unique_ptr<char[]> buf(new char[size]);
23
+ std::snprintf(buf.get(), size, format.c_str(), args...);
24
+ return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
25
+ }
26
+
27
+ public:
28
+ static void log(const std::string& tag, const std::string& message);
29
+
30
+ template <typename... Args>
31
+ inline static void log(const std::string& tag, const std::string& formatString, Args&&... args) {
32
+ std::string formattedString = string_format(formatString, std::forward<Args>(args)...);
33
+ log(tag, formattedString);
34
+ }
35
+ };
@@ -0,0 +1,37 @@
1
+ //
2
+ // ManagedBuffer.h
3
+ // react-native-mmkv
4
+ //
5
+ // Created by Marc Rousavy on 25.03.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include <jsi/jsi.h>
11
+
12
+ #if __has_include("MMKVManagedBuffer.h")
13
+ #include "MMKVManagedBuffer.h"
14
+ #else
15
+ #include <MMKVCore/MMKVManagedBuffer.h>
16
+ #endif
17
+
18
+ using namespace facebook;
19
+
20
+ /**
21
+ A jsi::MutableBuffer that manages mmkv::MMBuffer memory (by ownership).
22
+ */
23
+ class MMKVManagedBuffer : public jsi::MutableBuffer {
24
+ public:
25
+ explicit MMKVManagedBuffer(mmkv::MMBuffer&& buffer) : _buffer(std::move(buffer)) {}
26
+
27
+ uint8_t* data() override {
28
+ return static_cast<uint8_t*>(_buffer.getPtr());
29
+ }
30
+
31
+ size_t size() const override {
32
+ return _buffer.length();
33
+ }
34
+
35
+ private:
36
+ mmkv::MMBuffer _buffer;
37
+ };
@@ -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,30 @@
8
8
 
9
9
  #pragma once
10
10
 
11
- #include <MMKV.h>
11
+ #include "NativeMmkvModule.h"
12
12
  #include <jsi/jsi.h>
13
13
 
14
+ #if __has_include("MMKV.h")
15
+ #include "MMKV.h"
16
+ #else
17
+ #include <MMKVCore/MMKV.h>
18
+ #endif
19
+
14
20
  using namespace facebook;
21
+ using namespace mmkv;
15
22
 
16
- class JSI_EXPORT MmkvHostObject : public jsi::HostObject {
23
+ class MmkvHostObject : public jsi::HostObject {
17
24
  public:
18
- MmkvHostObject(const std::string& instanceId, std::string path, std::string cryptKey);
25
+ MmkvHostObject(const facebook::react::MMKVConfig& config);
26
+ ~MmkvHostObject();
19
27
 
20
28
  public:
21
29
  jsi::Value get(jsi::Runtime&, const jsi::PropNameID& name) override;
22
30
  std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& rt) override;
23
31
 
32
+ private:
33
+ static MMKVMode getMMKVMode(const facebook::react::MMKVConfig& config);
34
+
24
35
  private:
25
36
  MMKV* instance;
26
37
  };