react-native-nitro-storage 0.1.0 → 0.1.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 (61) hide show
  1. package/README.md +111 -24
  2. package/android/CMakeLists.txt +30 -24
  3. package/android/src/main/cpp/AndroidStorageAdapterCpp.cpp +10 -0
  4. package/android/src/main/cpp/AndroidStorageAdapterCpp.hpp +13 -0
  5. package/android/src/main/cpp/cpp-adapter.cpp +3 -2
  6. package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +10 -0
  7. package/cpp/bindings/HybridStorage.cpp +59 -17
  8. package/cpp/bindings/HybridStorage.hpp +4 -0
  9. package/cpp/core/NativeStorageAdapter.hpp +3 -0
  10. package/ios/IOSStorageAdapterCpp.hpp +3 -0
  11. package/ios/IOSStorageAdapterCpp.mm +41 -77
  12. package/lib/commonjs/Storage.nitro.js +0 -7
  13. package/lib/commonjs/Storage.nitro.js.map +1 -1
  14. package/lib/commonjs/Storage.types.js +13 -0
  15. package/lib/commonjs/Storage.types.js.map +1 -0
  16. package/lib/commonjs/index.js +127 -14
  17. package/lib/commonjs/index.js.map +1 -1
  18. package/lib/commonjs/index.web.js +268 -0
  19. package/lib/commonjs/index.web.js.map +1 -0
  20. package/lib/commonjs/migration.js +39 -0
  21. package/lib/commonjs/migration.js.map +1 -0
  22. package/lib/commonjs/package.json +1 -0
  23. package/lib/module/Storage.nitro.js +1 -6
  24. package/lib/module/Storage.nitro.js.map +1 -1
  25. package/lib/module/Storage.types.js +9 -0
  26. package/lib/module/Storage.types.js.map +1 -0
  27. package/lib/module/index.js +122 -13
  28. package/lib/module/index.js.map +1 -1
  29. package/lib/module/index.web.js +257 -0
  30. package/lib/module/index.web.js.map +1 -0
  31. package/lib/module/migration.js +35 -0
  32. package/lib/module/migration.js.map +1 -0
  33. package/lib/typescript/Storage.nitro.d.ts +5 -6
  34. package/lib/typescript/Storage.nitro.d.ts.map +1 -1
  35. package/lib/typescript/Storage.types.d.ts +6 -0
  36. package/lib/typescript/Storage.types.d.ts.map +1 -0
  37. package/lib/typescript/index.d.ts +20 -4
  38. package/lib/typescript/index.d.ts.map +1 -1
  39. package/lib/typescript/index.web.d.ts +50 -0
  40. package/lib/typescript/index.web.d.ts.map +1 -0
  41. package/lib/typescript/migration.d.ts +12 -0
  42. package/lib/typescript/migration.d.ts.map +1 -0
  43. package/nitrogen/generated/android/NitroStorage+autolinking.cmake +1 -1
  44. package/nitrogen/generated/android/NitroStorage+autolinking.gradle +1 -1
  45. package/nitrogen/generated/android/NitroStorageOnLoad.cpp +1 -1
  46. package/nitrogen/generated/android/NitroStorageOnLoad.hpp +1 -1
  47. package/nitrogen/generated/android/kotlin/com/margelo/nitro/com/nitrostorage/NitroStorageOnLoad.kt +1 -1
  48. package/nitrogen/generated/ios/NitroStorage+autolinking.rb +2 -2
  49. package/nitrogen/generated/ios/NitroStorage-Swift-Cxx-Bridge.cpp +1 -1
  50. package/nitrogen/generated/ios/NitroStorage-Swift-Cxx-Bridge.hpp +1 -1
  51. package/nitrogen/generated/ios/NitroStorage-Swift-Cxx-Umbrella.hpp +1 -1
  52. package/nitrogen/generated/ios/NitroStorageAutolinking.mm +1 -1
  53. package/nitrogen/generated/ios/NitroStorageAutolinking.swift +1 -1
  54. package/nitrogen/generated/shared/c++/HybridStorageSpec.cpp +5 -1
  55. package/nitrogen/generated/shared/c++/HybridStorageSpec.hpp +6 -1
  56. package/package.json +7 -25
  57. package/src/Storage.nitro.ts +6 -7
  58. package/src/Storage.types.ts +5 -0
  59. package/src/index.ts +153 -16
  60. package/src/index.web.ts +341 -0
  61. package/src/migration.ts +53 -0
package/README.md CHANGED
@@ -35,7 +35,11 @@ Familiar, elegant API with `createStorageItem` and `useStorage`. Works inside an
35
35
 
36
36
  ### **Production-Ready**
37
37
 
38
- Thread-safe C++ core, comprehensive test coverage, and battle-tested on iOS and Android.
38
+ Thread-safe C++ core, comprehensive test coverage, and battle-tested on iOS, Android, and **Web**.
39
+
40
+ ### **Web Support**
41
+
42
+ Fully functional on the web via `localStorage` and `sessionStorage`. All hooks and storage atoms are fully reactive across all platforms.
39
43
 
40
44
  ---
41
45
 
@@ -139,17 +143,25 @@ const value = counterAtom.get(); // 42, instantly
139
143
 
140
144
  _Replaces: Zustand, Jotai, Redux_
141
145
 
142
- Fast, in-memory state. Perfect for global app state that doesn't need persistence.
146
+ Fast, in-memory state. **Now Pure JS** - can store complex objects, functions, and React nodes!
143
147
 
144
148
  ```typescript
145
- const userAtom = createStorageItem<User | null>({
146
- key: "current-user",
149
+ // Store a function
150
+ const callbackAtom = createStorageItem({
151
+ key: "on-click",
147
152
  scope: StorageScope.Memory,
148
- defaultValue: null,
153
+ defaultValue: () => console.log("Clicked!"),
154
+ });
155
+
156
+ // Store a React Component
157
+ const modalAtom = createStorageItem({
158
+ key: "active-modal",
159
+ scope: StorageScope.Memory,
160
+ defaultValue: <View />,
149
161
  });
150
162
  ```
151
163
 
152
- **Performance:** < 0.001ms per operation
164
+ **Performance:** < 0.001ms per operation (Zero JSI overhead)
153
165
 
154
166
  ### **Disk Storage**
155
167
 
@@ -299,6 +311,78 @@ const unsubscribe = counterAtom.subscribe(() => {
299
311
  unsubscribe();
300
312
  ```
301
313
 
314
+ ### Batch Operations
315
+
316
+ Read or write multiple items at once. This is highly optimized on the native side for minimum overhead.
317
+
318
+ ```typescript
319
+ import { getBatch, setBatch, removeBatch } from "react-native-nitro-storage";
320
+
321
+ // Write multiple items
322
+ setBatch(
323
+ [
324
+ { item: item1, value: "v1" },
325
+ { item: item2, value: "v2" },
326
+ ],
327
+ StorageScope.Disk
328
+ );
329
+
330
+ // Read multiple items
331
+ const [v1, v2] = getBatch([item1, item2], StorageScope.Disk);
332
+
333
+ // Remove multiple items
334
+ removeBatch([item1, item2], StorageScope.Disk);
335
+ ```
336
+
337
+ ### Functional Updates
338
+
339
+ Update state based on the previous value, just like `useState`.
340
+
341
+ ```typescript
342
+ // Increment counter
343
+ counterAtom.set((prev) => prev + 1);
344
+ ```
345
+
346
+ ### Optimized Writes
347
+
348
+ Use `useSetStorage` to set values without subscribing to updates (avoids re-renders).
349
+
350
+ ```typescript
351
+ import { useSetStorage } from "react-native-nitro-storage";
352
+
353
+ function IncrementButton() {
354
+ const setCount = useSetStorage(counterAtom);
355
+ return <Button onPress={() => setCount((c) => c + 1)} title="+" />;
356
+ }
357
+ ```
358
+
359
+ ### Clearing Data
360
+
361
+ Clear entire storage scopes at once.
362
+
363
+ ```typescript
364
+ import { storage } from "react-native-nitro-storage";
365
+
366
+ // Clear all storage (all scopes)
367
+ storage.clearAll();
368
+
369
+ // Clear specific scope
370
+ storage.clear(StorageScope.Memory);
371
+ storage.clear(StorageScope.Disk);
372
+ storage.clear(StorageScope.Secure);
373
+ ```
374
+
375
+ ### Migration from MMKV
376
+
377
+ Easily migrate data from `react-native-mmkv` to Nitro Storage.
378
+
379
+ ```typescript
380
+ import { migrateFromMMKV } from "react-native-nitro-storage/src/migration";
381
+
382
+ // Migrate 'user-settings' and delete from MMKV
383
+ migrateFromMMKV(mmkvInstance, settingsAtom, true);
384
+ ```
385
+
302
386
  ---
303
387
 
304
388
  ## 📊 Performance Benchmarks
@@ -344,7 +428,7 @@ Creates a storage atom.
344
428
  **Methods:**
345
429
 
346
430
  - `get(): T` - Get current value (synchronous)
347
- - `set(value: T): void` - Set new value (synchronous)
431
+ - `set(value: T | ((prev: T) => T)): void` - Set new value (synchronous)
348
432
  - `delete(): void` - Remove value (synchronous)
349
433
  - `subscribe(callback: () => void): () => void` - Subscribe to changes
350
434
 
@@ -352,7 +436,24 @@ Creates a storage atom.
352
436
 
353
437
  React hook using `useSyncExternalStore` for automatic re-renders.
354
438
 
355
- **Returns:** `[value: T, setValue: (value: T) => void]`
439
+ **Returns:** `[value: T, setValue: (value: T | ((prev: T) => T)) => void]`
440
+
441
+ ### `useSetStorage<T>(item: StorageItem<T>)`
442
+
443
+ Returns the setter function only. Does not subscribe to updates.
444
+
445
+ **Returns:** `(value: T | ((prev: T) => T)) => void`
446
+
447
+ ### `storage` Object
448
+
449
+ - `clearAll()`: Clears all storage across all scopes.
450
+ - `clear(scope)`: Clears a specific storage scope.
451
+
452
+ ### Batch Operations
453
+
454
+ - `getBatch(items, scope)`: Returns an array of values for the given items.
455
+ - `setBatch(items, scope)`: Sets multiple values at once.
456
+ - `removeBatch(items, scope)`: Removes multiple items at once.
356
457
 
357
458
  ---
358
459
 
@@ -420,27 +521,13 @@ Built on [Nitro Modules](https://nitro.margelo.com) for maximum performance:
420
521
  | Type-Safe | ✅ | ⚠️ | ⚠️ | ✅ | ⚠️ |
421
522
  | Unified API | ✅ | ❌ | ❌ | ❌ | ❌ |
422
523
  | React Hooks | ✅ | ❌ | ❌ | ✅ | ❌ |
524
+ | Web Support | ✅ | ❌ | ✅ | ✅ | ❌ |
423
525
 
424
526
  ---
425
527
 
426
528
  ## 📄 License
427
529
 
428
- MIT © [Your Name]
429
-
430
- ---
431
-
432
- ## 🙏 Acknowledgments
433
-
434
- Built with ❤️ using [Nitro Modules](https://nitro.margelo.com) by [Marc Rousavy](https://github.com/mrousavy)
435
-
436
- ---
437
-
438
- ## 📚 Learn More
439
-
440
- - [Nitro Modules Documentation](https://nitro.margelo.com)
441
- - [Example App](./apps/example)
442
- - [API Reference](#-api-reference)
443
- - [Performance Benchmarks](#-performance-benchmarks)
530
+ MIT
444
531
 
445
532
  ---
446
533
 
@@ -1,33 +1,39 @@
1
- cmake_minimum_required(VERSION 3.22.1)
1
+ cmake_minimum_required(VERSION 3.18.0)
2
+
2
3
  project(NitroStorage)
3
4
 
5
+ set(CMAKE_VERBOSE_MAKEFILE ON)
4
6
  set(CMAKE_CXX_STANDARD 20)
5
- set(CMAKE_CXX_STANDARD_REQUIRED ON)
6
- set(CMAKE_C_STANDARD 11)
7
- set(CMAKE_C_STANDARD_REQUIRED ON)
8
-
9
- # Define the path to our C++ sources
10
- set(CPP_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../cpp")
11
7
 
12
- # Collect source files
13
- file(GLOB CORE_SOURCES "${CPP_ROOT}/core/*.cpp")
14
- file(GLOB BINDING_SOURCES "${CPP_ROOT}/bindings/*.cpp")
8
+ # 1. Define source files (Manual implementation)
9
+ file(GLOB SOURCES
10
+ "../cpp/bindings/*.cpp"
11
+ "../cpp/core/*.cpp"
12
+ "./src/main/cpp/*.cpp"
13
+ )
15
14
 
16
- # Create the shared library with our sources
17
- add_library(${PROJECT_NAME} SHARED
18
- ${CORE_SOURCES}
19
- ${BINDING_SOURCES}
20
- # JNI adapter
21
- src/main/cpp/cpp-adapter.cpp
22
- src/main/cpp/AndroidStorageAdapterCpp.cpp
15
+ # 2. Create the library target
16
+ add_library(
17
+ NitroStorage
18
+ SHARED
19
+ ${SOURCES}
23
20
  )
24
21
 
25
- # Include directories
26
- target_include_directories(${PROJECT_NAME} PRIVATE
27
- "${CPP_ROOT}/core"
28
- "${CPP_ROOT}/bindings"
29
- "src/main/cpp"
22
+ # 3. Include directories for manual sources
23
+ target_include_directories(
24
+ NitroStorage
25
+ PRIVATE
26
+ "../cpp/core"
27
+ "../cpp/bindings"
28
+ "./src/main/cpp"
30
29
  )
31
30
 
32
- # Include Nitro autolinking (adds nitrogen sources, definitions, and links)
33
- include(${CMAKE_CURRENT_SOURCE_DIR}/../nitrogen/generated/android/NitroStorage+autolinking.cmake)
31
+ # 4. Include Nitrogen Autolinking (adds generated sources, finding packages, linking libs)
32
+ include("../nitrogen/generated/android/NitroStorage+autolinking.cmake")
33
+
34
+ # 5. Link standard Android libraries
35
+ target_link_libraries(
36
+ NitroStorage
37
+ android
38
+ log
39
+ )
@@ -46,4 +46,14 @@ void AndroidStorageAdapterCpp::deleteSecure(const std::string& key) {
46
46
  method(AndroidStorageAdapterJava::javaClassStatic(), key);
47
47
  }
48
48
 
49
+ void AndroidStorageAdapterCpp::clearDisk() {
50
+ static auto method = AndroidStorageAdapterJava::javaClassStatic()->getStaticMethod<void()>("clearDisk");
51
+ method(AndroidStorageAdapterJava::javaClassStatic());
52
+ }
53
+
54
+ void AndroidStorageAdapterCpp::clearSecure() {
55
+ static auto method = AndroidStorageAdapterJava::javaClassStatic()->getStaticMethod<void()>("clearSecure");
56
+ method(AndroidStorageAdapterJava::javaClassStatic());
57
+ }
58
+
49
59
  } // namespace NitroStorage
@@ -49,6 +49,16 @@ struct AndroidStorageAdapterJava : facebook::jni::JavaClass<AndroidStorageAdapte
49
49
  static auto method = javaClassStatic()->getMethod<void(std::string)>("deleteSecure");
50
50
  method(self(), key);
51
51
  }
52
+
53
+ void clearDisk() {
54
+ static auto method = javaClassStatic()->getStaticMethod<void()>("clearDisk");
55
+ method(javaClassStatic());
56
+ }
57
+
58
+ void clearSecure() {
59
+ static auto method = javaClassStatic()->getStaticMethod<void()>("clearSecure");
60
+ method(javaClassStatic());
61
+ }
52
62
  };
53
63
 
54
64
  class AndroidStorageAdapterCpp : public NativeStorageAdapter {
@@ -63,6 +73,9 @@ public:
63
73
  void setSecure(const std::string& key, const std::string& value) override;
64
74
  std::optional<std::string> getSecure(const std::string& key) override;
65
75
  void deleteSecure(const std::string& key) override;
76
+
77
+ void clearDisk() override;
78
+ void clearSecure() override;
66
79
  };
67
80
 
68
81
  } // namespace NitroStorage
@@ -1,6 +1,7 @@
1
1
  #include <jni.h>
2
- #include "NitroStorageOnLoad.hpp"
2
+ #include <fbjni/fbjni.h>
3
+ #include "../../../nitrogen/generated/android/NitroStorageOnLoad.hpp"
3
4
 
4
- JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
5
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
5
6
  return margelo::nitro::NitroStorage::initialize(vm);
6
7
  }
@@ -90,5 +90,15 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
90
90
  fun deleteSecure(key: String) {
91
91
  instance?.encryptedPreferences?.edit()?.remove(key)?.apply()
92
92
  }
93
+
94
+ @JvmStatic
95
+ fun clearDisk() {
96
+ instance?.sharedPreferences?.edit()?.clear()?.apply()
97
+ }
98
+
99
+ @JvmStatic
100
+ fun clearSecure() {
101
+ instance?.encryptedPreferences?.edit()?.clear()?.apply()
102
+ }
93
103
  }
94
104
  }
@@ -24,14 +24,7 @@ HybridStorage::HybridStorage(std::shared_ptr<::NitroStorage::NativeStorageAdapte
24
24
  : HybridObject(TAG), HybridStorageSpec(), nativeAdapter_(std::move(adapter)) {}
25
25
 
26
26
  HybridStorage::Scope HybridStorage::toScope(double scopeValue) {
27
- int intScope = static_cast<int>(scopeValue);
28
- if (intScope < 0 || intScope > 2) {
29
- throw std::invalid_argument(
30
- "Invalid storage scope: " + std::to_string(intScope) +
31
- ". Must be 0 (Memory), 1 (Disk), or 2 (Secure)"
32
- );
33
- }
34
- return static_cast<Scope>(intScope);
27
+ return static_cast<Scope>(static_cast<int>(scopeValue));
35
28
  }
36
29
 
37
30
  void HybridStorage::set(const std::string& key, const std::string& value, double scope) {
@@ -100,8 +93,8 @@ std::function<void()> HybridStorage::addOnChange(
100
93
  const std::function<void(const std::string&, const std::optional<std::string>&)>& callback
101
94
  ) {
102
95
  int intScope = static_cast<int>(scope);
103
-
104
96
  size_t listenerId;
97
+
105
98
  {
106
99
  std::lock_guard<std::mutex> lock(listenersMutex_);
107
100
  listenerId = nextListenerId_++;
@@ -111,17 +104,65 @@ std::function<void()> HybridStorage::addOnChange(
111
104
  return [this, intScope, listenerId]() {
112
105
  std::lock_guard<std::mutex> lock(listenersMutex_);
113
106
  auto& scopeListeners = listeners_[intScope];
114
- scopeListeners.erase(
115
- std::remove_if(
116
- scopeListeners.begin(),
117
- scopeListeners.end(),
118
- [listenerId](const Listener& l) { return l.id == listenerId; }
119
- ),
120
- scopeListeners.end()
121
- );
107
+ for (auto it = scopeListeners.begin(); it != scopeListeners.end(); ++it) {
108
+ if (it->id == listenerId) {
109
+ scopeListeners.erase(it);
110
+ break;
111
+ }
112
+ }
122
113
  };
123
114
  }
124
115
 
116
+ void HybridStorage::clear(double scope) {
117
+ Scope s = toScope(scope);
118
+
119
+ switch (s) {
120
+ case Scope::Memory: {
121
+ std::lock_guard<std::mutex> lock(memoryMutex_);
122
+ memoryStore_.clear();
123
+ break;
124
+ }
125
+ case Scope::Disk:
126
+ nativeAdapter_->clearDisk();
127
+ break;
128
+ case Scope::Secure:
129
+ nativeAdapter_->clearSecure();
130
+ break;
131
+ }
132
+
133
+ notifyListeners(static_cast<int>(s), "", std::nullopt);
134
+ }
135
+
136
+ void HybridStorage::setBatch(const std::vector<std::string>& keys, const std::vector<std::string>& values, double scope) {
137
+ if (keys.size() != values.size()) {
138
+ throw std::runtime_error("NitroStorage: Keys and values size mismatch in setBatch");
139
+ }
140
+
141
+ for (size_t i = 0; i < keys.size(); ++i) {
142
+ set(keys[i], values[i], scope);
143
+ }
144
+ }
145
+
146
+
147
+ std::vector<std::string> HybridStorage::getBatch(const std::vector<std::string>& keys, double scope) {
148
+ std::vector<std::string> results;
149
+ results.reserve(keys.size());
150
+
151
+ for (const auto& key : keys) {
152
+ auto val = get(key, scope);
153
+ results.push_back(val.value_or(""));
154
+ }
155
+
156
+ return results;
157
+ }
158
+
159
+
160
+ void HybridStorage::removeBatch(const std::vector<std::string>& keys, double scope) {
161
+ for (const auto& key : keys) {
162
+ remove(key, scope);
163
+ }
164
+ }
165
+
125
166
  void HybridStorage::notifyListeners(
126
167
  int scope,
127
168
  const std::string& key,
@@ -132,6 +173,7 @@ void HybridStorage::notifyListeners(
132
173
  std::lock_guard<std::mutex> lock(listenersMutex_);
133
174
  auto it = listeners_.find(scope);
134
175
  if (it != listeners_.end()) {
176
+ listenersCopy.reserve(it->second.size());
135
177
  listenersCopy = it->second;
136
178
  }
137
179
  }
@@ -19,6 +19,10 @@ public:
19
19
  void set(const std::string& key, const std::string& value, double scope) override;
20
20
  std::optional<std::string> get(const std::string& key, double scope) override;
21
21
  void remove(const std::string& key, double scope) override;
22
+ void clear(double scope) override;
23
+ void setBatch(const std::vector<std::string>& keys, const std::vector<std::string>& values, double scope) override;
24
+ std::vector<std::string> getBatch(const std::vector<std::string>& keys, double scope) override;
25
+ void removeBatch(const std::vector<std::string>& keys, double scope) override;
22
26
  std::function<void()> addOnChange(
23
27
  double scope,
24
28
  const std::function<void(const std::string&, const std::optional<std::string>&)>& callback
@@ -16,6 +16,9 @@ public:
16
16
  virtual void setSecure(const std::string& key, const std::string& value) = 0;
17
17
  virtual std::optional<std::string> getSecure(const std::string& key) = 0;
18
18
  virtual void deleteSecure(const std::string& key) = 0;
19
+
20
+ virtual void clearDisk() = 0;
21
+ virtual void clearSecure() = 0;
19
22
  };
20
23
 
21
24
  } // namespace NitroStorage
@@ -16,6 +16,9 @@ public:
16
16
  void setSecure(const std::string& key, const std::string& value) override;
17
17
  std::optional<std::string> getSecure(const std::string& key) override;
18
18
  void deleteSecure(const std::string& key) override;
19
+
20
+ void clearDisk() override;
21
+ void clearSecure() override;
19
22
  };
20
23
 
21
24
  } // namespace NitroStorage
@@ -4,124 +4,88 @@
4
4
 
5
5
  namespace NitroStorage {
6
6
 
7
- IOSStorageAdapterCpp::IOSStorageAdapterCpp() {}
7
+ static NSString* const kKeychainService = @"com.nitrostorage.keychain";
8
8
 
9
+ IOSStorageAdapterCpp::IOSStorageAdapterCpp() {}
9
10
  IOSStorageAdapterCpp::~IOSStorageAdapterCpp() {}
10
11
 
11
12
  void IOSStorageAdapterCpp::setDisk(const std::string& key, const std::string& value) {
12
- NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
13
- NSString* nsValue = [NSString stringWithUTF8String:value.c_str()];
14
- [[NSUserDefaults standardUserDefaults] setObject:nsValue forKey:nsKey];
13
+ [[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithUTF8String:value.c_str()]
14
+ forKey:[NSString stringWithUTF8String:key.c_str()]];
15
15
  }
16
16
 
17
17
  std::optional<std::string> IOSStorageAdapterCpp::getDisk(const std::string& key) {
18
- NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
19
- NSString* result = [[NSUserDefaults standardUserDefaults] stringForKey:nsKey];
20
-
21
- if (result) {
22
- const char* utf8String = [result UTF8String];
23
- if (utf8String) {
24
- std::string value;
25
- value.reserve([result lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
26
- value.assign(utf8String);
27
- return value;
28
- }
29
- }
30
- return std::nullopt;
18
+ NSString* result = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithUTF8String:key.c_str()]];
19
+ if (!result) return std::nullopt;
20
+ return std::string([result UTF8String]);
31
21
  }
32
22
 
33
23
  void IOSStorageAdapterCpp::deleteDisk(const std::string& key) {
34
- NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
35
- [[NSUserDefaults standardUserDefaults] removeObjectForKey:nsKey];
24
+ [[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithUTF8String:key.c_str()]];
36
25
  }
37
26
 
38
27
  void IOSStorageAdapterCpp::setSecure(const std::string& key, const std::string& value) {
39
28
  NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
40
- NSString* nsValue = [NSString stringWithUTF8String:value.c_str()];
41
- NSData* data = [nsValue dataUsingEncoding:NSUTF8StringEncoding];
42
-
43
- NSString* service = @"com.nitrostorage.keychain";
44
-
29
+ NSData* data = [[NSString stringWithUTF8String:value.c_str()] dataUsingEncoding:NSUTF8StringEncoding];
30
+
45
31
  NSDictionary* query = @{
46
32
  (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
47
- (__bridge id)kSecAttrService: service,
33
+ (__bridge id)kSecAttrService: kKeychainService,
48
34
  (__bridge id)kSecAttrAccount: nsKey
49
35
  };
50
-
36
+
51
37
  NSDictionary* updateAttributes = @{
52
38
  (__bridge id)kSecValueData: data
53
39
  };
40
+
41
+ OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)updateAttributes);
54
42
 
55
- // Try to update first (atomic operation)
56
- OSStatus updateStatus = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)updateAttributes);
57
-
58
- if (updateStatus == errSecItemNotFound) {
59
- // Item doesn't exist, add it
60
- NSDictionary* addQuery = @{
61
- (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
62
- (__bridge id)kSecAttrService: service,
63
- (__bridge id)kSecAttrAccount: nsKey,
64
- (__bridge id)kSecValueData: data,
65
- (__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleWhenUnlocked
66
- };
67
-
68
- OSStatus addStatus = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
69
- if (addStatus != errSecSuccess) {
70
- NSLog(@"NitroStorage: Failed to add to Keychain for key '%@'. Error: %d", nsKey, (int)addStatus);
71
- }
72
- } else if (updateStatus != errSecSuccess) {
73
- NSLog(@"NitroStorage: Failed to update Keychain item '%@'. Error: %d", nsKey, (int)updateStatus);
43
+ if (status == errSecItemNotFound) {
44
+ NSMutableDictionary* addQuery = [query mutableCopy];
45
+ addQuery[(__bridge id)kSecValueData] = data;
46
+ addQuery[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleWhenUnlocked;
47
+ SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
74
48
  }
75
49
  }
76
50
 
77
51
  std::optional<std::string> IOSStorageAdapterCpp::getSecure(const std::string& key) {
78
- NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
79
- NSString* service = @"com.nitrostorage.keychain";
80
-
81
52
  NSDictionary* query = @{
82
53
  (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
83
- (__bridge id)kSecAttrService: service,
84
- (__bridge id)kSecAttrAccount: nsKey,
54
+ (__bridge id)kSecAttrService: kKeychainService,
55
+ (__bridge id)kSecAttrAccount: [NSString stringWithUTF8String:key.c_str()],
85
56
  (__bridge id)kSecReturnData: @YES,
86
57
  (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne
87
58
  };
88
-
59
+
89
60
  CFTypeRef result = NULL;
90
- OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
91
-
92
- if (status == errSecSuccess && result) {
61
+ if (SecItemCopyMatching((__bridge CFDictionaryRef)query, &result) == errSecSuccess && result) {
93
62
  NSData* data = (__bridge_transfer NSData*)result;
94
- NSString* nsValue = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
95
- if (nsValue) {
96
- const char* utf8String = [nsValue UTF8String];
97
- if (utf8String) {
98
- std::string value;
99
- value.reserve([nsValue lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
100
- value.assign(utf8String);
101
- return value;
102
- }
103
- }
104
- } else if (status != errSecItemNotFound) {
105
- NSLog(@"NitroStorage: Failed to read from Keychain for key '%@'. Error: %d", nsKey, (int)status);
63
+ NSString* str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
64
+ if (str) return std::string([str UTF8String]);
106
65
  }
107
-
108
66
  return std::nullopt;
109
67
  }
110
68
 
111
69
  void IOSStorageAdapterCpp::deleteSecure(const std::string& key) {
112
- NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
113
- NSString* service = @"com.nitrostorage.keychain";
114
-
115
70
  NSDictionary* query = @{
116
71
  (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
117
- (__bridge id)kSecAttrService: service,
118
- (__bridge id)kSecAttrAccount: nsKey
72
+ (__bridge id)kSecAttrService: kKeychainService,
73
+ (__bridge id)kSecAttrAccount: [NSString stringWithUTF8String:key.c_str()]
119
74
  };
120
-
121
- OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
122
- if (status != errSecSuccess && status != errSecItemNotFound) {
123
- NSLog(@"NitroStorage: Failed to delete from Keychain for key '%@'. Error: %d", nsKey, (int)status);
124
- }
75
+ SecItemDelete((__bridge CFDictionaryRef)query);
76
+ }
77
+
78
+ void IOSStorageAdapterCpp::clearDisk() {
79
+ NSString* appDomain = [[NSBundle mainBundle] bundleIdentifier];
80
+ [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
81
+ }
82
+
83
+ void IOSStorageAdapterCpp::clearSecure() {
84
+ NSDictionary* query = @{
85
+ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
86
+ (__bridge id)kSecAttrService: kKeychainService
87
+ };
88
+ SecItemDelete((__bridge CFDictionaryRef)query);
125
89
  }
126
90
 
127
91
  } // namespace NitroStorage
@@ -3,11 +3,4 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.StorageScope = void 0;
7
- let StorageScope = exports.StorageScope = /*#__PURE__*/function (StorageScope) {
8
- StorageScope[StorageScope["Memory"] = 0] = "Memory";
9
- StorageScope[StorageScope["Disk"] = 1] = "Disk";
10
- StorageScope[StorageScope["Secure"] = 2] = "Secure";
11
- return StorageScope;
12
- }({});
13
6
  //# sourceMappingURL=Storage.nitro.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["StorageScope","exports"],"sourceRoot":"../../src","sources":["Storage.nitro.ts"],"mappings":";;;;;;IAEYA,YAAY,GAAAC,OAAA,CAAAD,YAAA,0BAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAA,OAAZA,YAAY;AAAA","ignoreList":[]}
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["Storage.nitro.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.StorageScope = void 0;
7
+ let StorageScope = exports.StorageScope = /*#__PURE__*/function (StorageScope) {
8
+ StorageScope[StorageScope["Memory"] = 0] = "Memory";
9
+ StorageScope[StorageScope["Disk"] = 1] = "Disk";
10
+ StorageScope[StorageScope["Secure"] = 2] = "Secure";
11
+ return StorageScope;
12
+ }({});
13
+ //# sourceMappingURL=Storage.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["StorageScope","exports"],"sourceRoot":"../../src","sources":["Storage.types.ts"],"mappings":";;;;;;IAAYA,YAAY,GAAAC,OAAA,CAAAD,YAAA,0BAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAA,OAAZA,YAAY;AAAA","ignoreList":[]}