@onekeyfe/react-native-async-storage 1.1.55

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.
@@ -0,0 +1,19 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "AsyncStorage"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported }
14
+ s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-async-storage.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = "ios/**/*.{h,m,mm}"
17
+
18
+ install_modules_dependencies(s)
19
+ end
@@ -0,0 +1,27 @@
1
+ #import <AsyncStorageSpec/AsyncStorageSpec.h>
2
+
3
+ @interface AsyncStorage : NativeRNCAsyncStorageSpecBase <NativeRNCAsyncStorageSpec>
4
+
5
+ - (void)multiGet:(NSArray<NSString *> *)keys
6
+ resolve:(RCTPromiseResolveBlock)resolve
7
+ reject:(RCTPromiseRejectBlock)reject;
8
+
9
+ - (void)multiSet:(NSArray<NSArray<NSString *> *> *)keyValuePairs
10
+ resolve:(RCTPromiseResolveBlock)resolve
11
+ reject:(RCTPromiseRejectBlock)reject;
12
+
13
+ - (void)multiRemove:(NSArray<NSString *> *)keys
14
+ resolve:(RCTPromiseResolveBlock)resolve
15
+ reject:(RCTPromiseRejectBlock)reject;
16
+
17
+ - (void)multiMerge:(NSArray<NSArray<NSString *> *> *)keyValuePairs
18
+ resolve:(RCTPromiseResolveBlock)resolve
19
+ reject:(RCTPromiseRejectBlock)reject;
20
+
21
+ - (void)getAllKeys:(RCTPromiseResolveBlock)resolve
22
+ reject:(RCTPromiseRejectBlock)reject;
23
+
24
+ - (void)clear:(RCTPromiseResolveBlock)resolve
25
+ reject:(RCTPromiseRejectBlock)reject;
26
+
27
+ @end
@@ -0,0 +1,714 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * Adapted to a proper TurboModule (no RCT_EXPORT_MODULE / RCT_EXPORT_METHOD)
8
+ * so it works in both the main and background Hermes runtimes.
9
+ */
10
+
11
+ #import "AsyncStorage.h"
12
+
13
+ #import <React/RCTConvert.h>
14
+ #import <React/RCTLog.h>
15
+ #import <React/RCTUtils.h>
16
+
17
+ static NSString *const RCTStorageDirectory = @"RCTAsyncLocalStorage_V1";
18
+ static NSString *const RCTOldStorageDirectory = @"RNCAsyncLocalStorage_V1";
19
+ static NSString *const RCTExpoStorageDirectory = @"RCTAsyncLocalStorage";
20
+ static NSString *const RCTManifestFileName = @"manifest.json";
21
+ static const NSUInteger RCTInlineValueThreshold = 1024;
22
+
23
+ #pragma mark - Static helper functions
24
+
25
+ static NSDictionary *RCTErrorForKey(NSString *key)
26
+ {
27
+ if (![key isKindOfClass:[NSString class]]) {
28
+ return RCTMakeAndLogError(@"Invalid key - must be a string. Key: ", key, @{@"key": key});
29
+ } else if (key.length < 1) {
30
+ return RCTMakeAndLogError(
31
+ @"Invalid key - must be at least one character. Key: ", key, @{@"key": key});
32
+ } else {
33
+ return nil;
34
+ }
35
+ }
36
+
37
+ static BOOL RCTAsyncStorageSetExcludedFromBackup(NSString *path, NSNumber *isExcluded)
38
+ {
39
+ NSFileManager *fileManager = [[NSFileManager alloc] init];
40
+
41
+ BOOL isDir;
42
+ BOOL exists = [fileManager fileExistsAtPath:path isDirectory:&isDir];
43
+ BOOL success = false;
44
+
45
+ if (isDir && exists) {
46
+ NSURL *pathUrl = [NSURL fileURLWithPath:path];
47
+ NSError *error = nil;
48
+ success = [pathUrl setResourceValue:isExcluded
49
+ forKey:NSURLIsExcludedFromBackupKey
50
+ error:&error];
51
+
52
+ if (!success) {
53
+ NSLog(@"Could not exclude AsyncStorage dir from backup %@", error);
54
+ }
55
+ }
56
+ return success;
57
+ }
58
+
59
+ static void RCTAppendError(NSDictionary *error, NSMutableArray<NSDictionary *> **errors)
60
+ {
61
+ if (error && errors) {
62
+ if (!*errors) {
63
+ *errors = [NSMutableArray new];
64
+ }
65
+ [*errors addObject:error];
66
+ }
67
+ }
68
+
69
+ static NSString *RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut)
70
+ {
71
+ if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
72
+ NSError *error;
73
+ NSStringEncoding encoding;
74
+ NSString *entryString = [NSString stringWithContentsOfFile:filePath
75
+ usedEncoding:&encoding
76
+ error:&error];
77
+ NSDictionary *extraData = @{@"key": RCTNullIfNil(key)};
78
+
79
+ if (error) {
80
+ if (errorOut) {
81
+ *errorOut = RCTMakeError(@"Failed to read storage file.", error, extraData);
82
+ }
83
+ return nil;
84
+ }
85
+
86
+ if (encoding != NSUTF8StringEncoding) {
87
+ if (errorOut) {
88
+ *errorOut =
89
+ RCTMakeError(@"Incorrect encoding of storage file: ", @(encoding), extraData);
90
+ }
91
+ return nil;
92
+ }
93
+ return entryString;
94
+ }
95
+
96
+ return nil;
97
+ }
98
+
99
+ static NSString *RCTCreateStorageDirectoryPath_deprecated(NSString *storageDir)
100
+ {
101
+ NSString *storageDirectoryPath;
102
+ #if TARGET_OS_TV
103
+ storageDirectoryPath =
104
+ NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
105
+ #else
106
+ storageDirectoryPath =
107
+ NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
108
+ #endif
109
+ storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent:storageDir];
110
+ return storageDirectoryPath;
111
+ }
112
+
113
+ static NSString *RCTCreateStorageDirectoryPath(NSString *storageDir)
114
+ {
115
+ NSString *storageDirectoryPath = @"";
116
+
117
+ #if TARGET_OS_TV
118
+ storageDirectoryPath =
119
+ NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
120
+ #else
121
+ storageDirectoryPath =
122
+ NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)
123
+ .firstObject;
124
+ storageDirectoryPath = [storageDirectoryPath
125
+ stringByAppendingPathComponent:[[NSBundle mainBundle] bundleIdentifier]];
126
+ #endif
127
+
128
+ storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent:storageDir];
129
+
130
+ return storageDirectoryPath;
131
+ }
132
+
133
+ static NSString *RCTGetStorageDirectory()
134
+ {
135
+ static NSString *storageDirectory = nil;
136
+ static dispatch_once_t onceToken;
137
+ dispatch_once(&onceToken, ^{
138
+ #if TARGET_OS_TV
139
+ RCTLogWarn(
140
+ @"Persistent storage is not supported on tvOS, your data may be removed at any point.");
141
+ #endif
142
+ storageDirectory = RCTCreateStorageDirectoryPath(RCTStorageDirectory);
143
+ });
144
+ return storageDirectory;
145
+ }
146
+
147
+ static NSString *RCTCreateManifestFilePath(NSString *storageDirectory)
148
+ {
149
+ return [storageDirectory stringByAppendingPathComponent:RCTManifestFileName];
150
+ }
151
+
152
+ static NSString *RCTGetManifestFilePath()
153
+ {
154
+ static NSString *manifestFilePath = nil;
155
+ static dispatch_once_t onceToken;
156
+ dispatch_once(&onceToken, ^{
157
+ manifestFilePath = RCTCreateManifestFilePath(RCTStorageDirectory);
158
+ });
159
+ return manifestFilePath;
160
+ }
161
+
162
+ // Only merges objects - all other types are just clobbered (including arrays)
163
+ static BOOL RCTMergeRecursive(NSMutableDictionary *destination, NSDictionary *source)
164
+ {
165
+ BOOL modified = NO;
166
+ for (NSString *key in source) {
167
+ id sourceValue = source[key];
168
+ id destinationValue = destination[key];
169
+ if ([sourceValue isKindOfClass:[NSDictionary class]]) {
170
+ if ([destinationValue isKindOfClass:[NSDictionary class]]) {
171
+ if ([destinationValue classForCoder] != [NSMutableDictionary class]) {
172
+ destinationValue = [destinationValue mutableCopy];
173
+ }
174
+ if (RCTMergeRecursive(destinationValue, sourceValue)) {
175
+ destination[key] = destinationValue;
176
+ modified = YES;
177
+ }
178
+ } else {
179
+ destination[key] = [sourceValue copy];
180
+ modified = YES;
181
+ }
182
+ } else if (![source isEqual:destinationValue]) {
183
+ destination[key] = [sourceValue copy];
184
+ modified = YES;
185
+ }
186
+ }
187
+ return modified;
188
+ }
189
+
190
+ static dispatch_queue_t RCTGetMethodQueue()
191
+ {
192
+ // We want all instances to share the same queue since they will be reading/writing the same
193
+ // files.
194
+ static dispatch_queue_t queue;
195
+ static dispatch_once_t onceToken;
196
+ dispatch_once(&onceToken, ^{
197
+ queue =
198
+ dispatch_queue_create("com.facebook.react.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL);
199
+ });
200
+ return queue;
201
+ }
202
+
203
+ static NSCache *RCTGetCache()
204
+ {
205
+ // We want all instances to share the same cache since they will be reading/writing the same
206
+ // files.
207
+ static NSCache *cache;
208
+ static dispatch_once_t onceToken;
209
+ dispatch_once(&onceToken, ^{
210
+ cache = [NSCache new];
211
+ cache.totalCostLimit = 2 * 1024 * 1024; // 2MB
212
+
213
+ #if !TARGET_OS_OSX
214
+ // Clear cache in the event of a memory warning
215
+ [[NSNotificationCenter defaultCenter]
216
+ addObserverForName:UIApplicationDidReceiveMemoryWarningNotification
217
+ object:nil
218
+ queue:nil
219
+ usingBlock:^(__unused NSNotification *note) {
220
+ [cache removeAllObjects];
221
+ }];
222
+ #endif // !TARGET_OS_OSX
223
+ });
224
+ return cache;
225
+ }
226
+
227
+ static BOOL RCTHasCreatedStorageDirectory = NO;
228
+
229
+ static NSDictionary *RCTDeleteStorageDirectory()
230
+ {
231
+ NSError *error;
232
+ [[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDirectory() error:&error];
233
+ RCTHasCreatedStorageDirectory = NO;
234
+ if (error && error.code != NSFileNoSuchFileError) {
235
+ return RCTMakeError(@"Failed to delete storage directory.", error, nil);
236
+ }
237
+ return nil;
238
+ }
239
+
240
+ static NSDate *RCTManifestModificationDate(NSString *manifestFilePath)
241
+ {
242
+ NSDictionary *attributes =
243
+ [[NSFileManager defaultManager] attributesOfItemAtPath:manifestFilePath error:nil];
244
+ return [attributes fileModificationDate];
245
+ }
246
+
247
+ static void RCTStorageDirectoryMigrationLogError(NSString *reason, NSError *error)
248
+ {
249
+ RCTLogWarn(@"%@: %@", reason, error ? error.description : @"");
250
+ }
251
+
252
+ static void RCTStorageDirectoryCleanupOld(NSString *oldDirectoryPath)
253
+ {
254
+ NSError *error;
255
+ if (![[NSFileManager defaultManager] removeItemAtPath:oldDirectoryPath error:&error]) {
256
+ RCTStorageDirectoryMigrationLogError(
257
+ @"Failed to remove old storage directory during migration", error);
258
+ }
259
+ }
260
+
261
+ static void _createStorageDirectory(NSString *storageDirectory, NSError **error)
262
+ {
263
+ [[NSFileManager defaultManager] createDirectoryAtPath:storageDirectory
264
+ withIntermediateDirectories:YES
265
+ attributes:nil
266
+ error:error];
267
+ }
268
+
269
+ static void RCTStorageDirectoryMigrate(NSString *oldDirectoryPath,
270
+ NSString *newDirectoryPath,
271
+ BOOL shouldCleanupOldDirectory)
272
+ {
273
+ NSError *error;
274
+ if (![[NSFileManager defaultManager] copyItemAtPath:oldDirectoryPath
275
+ toPath:newDirectoryPath
276
+ error:&error]) {
277
+ if (error != nil && error.code == 4 &&
278
+ [newDirectoryPath isEqualToString:RCTGetStorageDirectory()]) {
279
+ error = nil;
280
+ _createStorageDirectory(RCTCreateStorageDirectoryPath(@""), &error);
281
+ if (error == nil) {
282
+ RCTStorageDirectoryMigrate(
283
+ oldDirectoryPath, newDirectoryPath, shouldCleanupOldDirectory);
284
+ } else {
285
+ RCTStorageDirectoryMigrationLogError(
286
+ @"Failed to create storage directory during migration.", error);
287
+ }
288
+ } else {
289
+ RCTStorageDirectoryMigrationLogError(
290
+ @"Failed to copy old storage directory to new storage directory location during "
291
+ @"migration",
292
+ error);
293
+ }
294
+ } else if (shouldCleanupOldDirectory) {
295
+ RCTStorageDirectoryCleanupOld(oldDirectoryPath);
296
+ }
297
+ }
298
+
299
+ static NSString *RCTGetStoragePathForMigration()
300
+ {
301
+ BOOL isDir;
302
+ NSString *oldStoragePath = RCTCreateStorageDirectoryPath_deprecated(RCTOldStorageDirectory);
303
+ NSString *expoStoragePath = RCTCreateStorageDirectoryPath_deprecated(RCTExpoStorageDirectory);
304
+ NSFileManager *fileManager = [NSFileManager defaultManager];
305
+ BOOL oldStorageDirectoryExists =
306
+ [fileManager fileExistsAtPath:oldStoragePath isDirectory:&isDir] && isDir;
307
+ BOOL expoStorageDirectoryExists =
308
+ [fileManager fileExistsAtPath:expoStoragePath isDirectory:&isDir] && isDir;
309
+
310
+ if (oldStorageDirectoryExists && expoStorageDirectoryExists) {
311
+ if ([RCTManifestModificationDate(RCTCreateManifestFilePath(oldStoragePath))
312
+ compare:RCTManifestModificationDate(RCTCreateManifestFilePath(expoStoragePath))] ==
313
+ NSOrderedDescending) {
314
+ RCTStorageDirectoryCleanupOld(expoStoragePath);
315
+ return oldStoragePath;
316
+ } else {
317
+ RCTStorageDirectoryCleanupOld(oldStoragePath);
318
+ return expoStoragePath;
319
+ }
320
+ } else if (oldStorageDirectoryExists) {
321
+ return oldStoragePath;
322
+ } else if (expoStorageDirectoryExists) {
323
+ return expoStoragePath;
324
+ } else {
325
+ return nil;
326
+ }
327
+ }
328
+
329
+ static void RCTStorageDirectoryMigrationCheck(NSString *fromStorageDirectory,
330
+ NSString *toStorageDirectory,
331
+ BOOL shouldCleanupOldDirectoryAndOverwriteNewDirectory)
332
+ {
333
+ NSError *error;
334
+ BOOL isDir;
335
+ NSFileManager *fileManager = [NSFileManager defaultManager];
336
+ if ([fileManager fileExistsAtPath:fromStorageDirectory isDirectory:&isDir] && isDir) {
337
+ if ([fileManager fileExistsAtPath:toStorageDirectory]) {
338
+ if ([RCTManifestModificationDate(RCTCreateManifestFilePath(toStorageDirectory))
339
+ compare:RCTManifestModificationDate(
340
+ RCTCreateManifestFilePath(fromStorageDirectory))] == 1) {
341
+ if (shouldCleanupOldDirectoryAndOverwriteNewDirectory) {
342
+ RCTStorageDirectoryCleanupOld(fromStorageDirectory);
343
+ }
344
+ } else if (shouldCleanupOldDirectoryAndOverwriteNewDirectory) {
345
+ if (![fileManager removeItemAtPath:toStorageDirectory error:&error]) {
346
+ RCTStorageDirectoryMigrationLogError(
347
+ @"Failed to remove new storage directory during migration", error);
348
+ } else {
349
+ RCTStorageDirectoryMigrate(fromStorageDirectory,
350
+ toStorageDirectory,
351
+ shouldCleanupOldDirectoryAndOverwriteNewDirectory);
352
+ }
353
+ }
354
+ } else {
355
+ RCTStorageDirectoryMigrate(fromStorageDirectory,
356
+ toStorageDirectory,
357
+ shouldCleanupOldDirectoryAndOverwriteNewDirectory);
358
+ }
359
+ }
360
+ }
361
+
362
+ #pragma mark - AsyncStorage
363
+
364
+ @implementation AsyncStorage {
365
+ BOOL _haveSetup;
366
+ // The manifest is a dictionary of all keys with small values inlined. Null values indicate
367
+ // values that are stored in separate files (as opposed to nil values which don't exist). The
368
+ // manifest is read off disk at startup, and written to disk after all mutations.
369
+ NSMutableDictionary<NSString *, NSString *> *_manifest;
370
+ }
371
+
372
+ + (NSString *)moduleName
373
+ {
374
+ return @"RNCAsyncStorage";
375
+ }
376
+
377
+ + (BOOL)requiresMainQueueSetup
378
+ {
379
+ return NO;
380
+ }
381
+
382
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
383
+ (const facebook::react::ObjCTurboModule::InitParams &)params
384
+ {
385
+ return std::make_shared<facebook::react::NativeRNCAsyncStorageSpecJSI>(params);
386
+ }
387
+
388
+ - (instancetype)init
389
+ {
390
+ if (!(self = [super init])) {
391
+ return nil;
392
+ }
393
+
394
+ NSString *oldStoragePath = RCTGetStoragePathForMigration();
395
+ if (oldStoragePath != nil) {
396
+ RCTStorageDirectoryMigrationCheck(
397
+ oldStoragePath, RCTCreateStorageDirectoryPath_deprecated(RCTStorageDirectory), YES);
398
+ }
399
+
400
+ RCTStorageDirectoryMigrationCheck(RCTCreateStorageDirectoryPath_deprecated(RCTStorageDirectory),
401
+ RCTCreateStorageDirectoryPath(RCTStorageDirectory),
402
+ NO);
403
+
404
+ return self;
405
+ }
406
+
407
+ - (NSString *)_filePathForKey:(NSString *)key
408
+ {
409
+ NSString *safeFileName = RCTMD5Hash(key);
410
+ return [RCTGetStorageDirectory() stringByAppendingPathComponent:safeFileName];
411
+ }
412
+
413
+ - (NSDictionary *)_ensureSetup
414
+ {
415
+ NSError *error = nil;
416
+ if (!RCTHasCreatedStorageDirectory) {
417
+ _createStorageDirectory(RCTGetStorageDirectory(), &error);
418
+ if (error) {
419
+ return RCTMakeError(@"Failed to create storage directory.", error, nil);
420
+ }
421
+ RCTHasCreatedStorageDirectory = YES;
422
+ }
423
+
424
+ if (!_haveSetup) {
425
+ NSNumber *isExcludedFromBackup =
426
+ [[NSBundle mainBundle] objectForInfoDictionaryKey:@"RCTAsyncStorageExcludeFromBackup"];
427
+ if (isExcludedFromBackup == nil) {
428
+ isExcludedFromBackup = @YES;
429
+ }
430
+ RCTAsyncStorageSetExcludedFromBackup(RCTCreateStorageDirectoryPath(RCTStorageDirectory),
431
+ isExcludedFromBackup);
432
+
433
+ NSDictionary *errorOut = nil;
434
+ NSString *serialized = RCTReadFile(RCTCreateStorageDirectoryPath(RCTGetManifestFilePath()),
435
+ RCTManifestFileName,
436
+ &errorOut);
437
+ if (!serialized) {
438
+ if (errorOut) {
439
+ RCTLogError(
440
+ @"Could not open the existing manifest, perhaps data protection is "
441
+ @"enabled?\n\n%@",
442
+ errorOut);
443
+ return errorOut;
444
+ } else {
445
+ _manifest = [NSMutableDictionary new];
446
+ }
447
+ } else {
448
+ _manifest = RCTJSONParseMutable(serialized, &error);
449
+ if (!_manifest) {
450
+ RCTLogError(@"Failed to parse manifest - creating a new one.\n\n%@", error);
451
+ _manifest = [NSMutableDictionary new];
452
+ }
453
+ }
454
+ _haveSetup = YES;
455
+ }
456
+
457
+ return nil;
458
+ }
459
+
460
+ - (NSDictionary *)_writeManifest:(NSMutableArray<NSDictionary *> *__autoreleasing *)errors
461
+ {
462
+ NSError *error;
463
+ NSString *serialized = RCTJSONStringify(_manifest, &error);
464
+ [serialized writeToFile:RCTCreateStorageDirectoryPath(RCTGetManifestFilePath())
465
+ atomically:YES
466
+ encoding:NSUTF8StringEncoding
467
+ error:&error];
468
+ NSDictionary *errorOut;
469
+ if (error) {
470
+ errorOut = RCTMakeError(@"Failed to write manifest file.", error, nil);
471
+ RCTAppendError(errorOut, errors);
472
+ }
473
+ return errorOut;
474
+ }
475
+
476
+ - (NSString *)_getValueForKey:(NSString *)key errorOut:(NSDictionary *__autoreleasing *)errorOut
477
+ {
478
+ NSString *value = _manifest[key];
479
+ if (value == (id)kCFNull) {
480
+ value = [RCTGetCache() objectForKey:key];
481
+ if (!value) {
482
+ NSString *filePath = [self _filePathForKey:key];
483
+ value = RCTReadFile(filePath, key, errorOut);
484
+ if (value) {
485
+ [RCTGetCache() setObject:value forKey:key cost:value.length];
486
+ } else {
487
+ [_manifest removeObjectForKey:key];
488
+ }
489
+ }
490
+ }
491
+ return value;
492
+ }
493
+
494
+ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL *)changedManifest
495
+ {
496
+ if (entry.count != 2) {
497
+ return RCTMakeAndLogError(
498
+ @"Entries must be arrays of the form [key: string, value: string], got: ", entry, nil);
499
+ }
500
+ NSString *key = entry[0];
501
+ NSDictionary *errorOut = RCTErrorForKey(key);
502
+ if (errorOut) {
503
+ return errorOut;
504
+ }
505
+ NSString *value = entry[1];
506
+ NSString *filePath = [self _filePathForKey:key];
507
+ NSError *error;
508
+ if (value.length <= RCTInlineValueThreshold) {
509
+ if (_manifest[key] == (id)kCFNull) {
510
+ [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
511
+ [RCTGetCache() removeObjectForKey:key];
512
+ }
513
+ *changedManifest = YES;
514
+ _manifest[key] = value;
515
+ return nil;
516
+ }
517
+ [value writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
518
+ [RCTGetCache() setObject:value forKey:key cost:value.length];
519
+ if (error) {
520
+ errorOut = RCTMakeError(@"Failed to write value.", error, @{@"key": key});
521
+ } else if (_manifest[key] != (id)kCFNull) {
522
+ *changedManifest = YES;
523
+ _manifest[key] = (id)kCFNull;
524
+ }
525
+ return errorOut;
526
+ }
527
+
528
+ #pragma mark - TurboModule methods
529
+
530
+ - (void)multiGet:(NSArray<NSString *> *)keys
531
+ resolve:(RCTPromiseResolveBlock)resolve
532
+ reject:(RCTPromiseRejectBlock)reject
533
+ {
534
+ dispatch_async(RCTGetMethodQueue(), ^{
535
+ NSDictionary *ensureSetupError = [self _ensureSetup];
536
+ if (ensureSetupError) {
537
+ reject(@"ASYNC_STORAGE_ERROR",
538
+ ensureSetupError[@"message"] ?: @"Storage setup failed",
539
+ nil);
540
+ return;
541
+ }
542
+
543
+ NSMutableArray<NSArray *> *result = [NSMutableArray arrayWithCapacity:keys.count];
544
+ for (NSString *key in keys) {
545
+ NSDictionary *keyError = RCTErrorForKey(key);
546
+ if (keyError) {
547
+ [result addObject:@[RCTNullIfNil(key), (id)kCFNull]];
548
+ } else {
549
+ NSDictionary *errorOut = nil;
550
+ NSString *value = [self _getValueForKey:key errorOut:&errorOut];
551
+ [result addObject:@[key, RCTNullIfNil(value)]];
552
+ }
553
+ }
554
+ resolve(result);
555
+ });
556
+ }
557
+
558
+ - (void)multiSet:(NSArray<NSArray<NSString *> *> *)keyValuePairs
559
+ resolve:(RCTPromiseResolveBlock)resolve
560
+ reject:(RCTPromiseRejectBlock)reject
561
+ {
562
+ dispatch_async(RCTGetMethodQueue(), ^{
563
+ NSDictionary *ensureSetupError = [self _ensureSetup];
564
+ if (ensureSetupError) {
565
+ reject(@"ASYNC_STORAGE_ERROR",
566
+ ensureSetupError[@"message"] ?: @"Storage setup failed",
567
+ nil);
568
+ return;
569
+ }
570
+
571
+ BOOL changedManifest = NO;
572
+ NSMutableArray<NSDictionary *> *errors;
573
+ for (NSArray<NSString *> *entry in keyValuePairs) {
574
+ NSDictionary *keyError = [self _writeEntry:entry changedManifest:&changedManifest];
575
+ RCTAppendError(keyError, &errors);
576
+ }
577
+ if (changedManifest) {
578
+ [self _writeManifest:&errors];
579
+ }
580
+ if (errors.count > 0) {
581
+ reject(@"ASYNC_STORAGE_ERROR",
582
+ @"One or more keys failed to set",
583
+ nil);
584
+ } else {
585
+ resolve(nil);
586
+ }
587
+ });
588
+ }
589
+
590
+ - (void)multiRemove:(NSArray<NSString *> *)keys
591
+ resolve:(RCTPromiseResolveBlock)resolve
592
+ reject:(RCTPromiseRejectBlock)reject
593
+ {
594
+ dispatch_async(RCTGetMethodQueue(), ^{
595
+ NSDictionary *ensureSetupError = [self _ensureSetup];
596
+ if (ensureSetupError) {
597
+ reject(@"ASYNC_STORAGE_ERROR",
598
+ ensureSetupError[@"message"] ?: @"Storage setup failed",
599
+ nil);
600
+ return;
601
+ }
602
+
603
+ NSMutableArray<NSDictionary *> *errors;
604
+ BOOL changedManifest = NO;
605
+ for (NSString *key in keys) {
606
+ NSDictionary *keyError = RCTErrorForKey(key);
607
+ if (!keyError) {
608
+ if (self->_manifest[key] == (id)kCFNull) {
609
+ NSString *filePath = [self _filePathForKey:key];
610
+ [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
611
+ [RCTGetCache() removeObjectForKey:key];
612
+ }
613
+ if (self->_manifest[key]) {
614
+ changedManifest = YES;
615
+ [self->_manifest removeObjectForKey:key];
616
+ }
617
+ }
618
+ RCTAppendError(keyError, &errors);
619
+ }
620
+ if (changedManifest) {
621
+ [self _writeManifest:&errors];
622
+ }
623
+ if (errors.count > 0) {
624
+ reject(@"ASYNC_STORAGE_ERROR",
625
+ @"One or more keys failed to remove",
626
+ nil);
627
+ } else {
628
+ resolve(nil);
629
+ }
630
+ });
631
+ }
632
+
633
+ - (void)multiMerge:(NSArray<NSArray<NSString *> *> *)keyValuePairs
634
+ resolve:(RCTPromiseResolveBlock)resolve
635
+ reject:(RCTPromiseRejectBlock)reject
636
+ {
637
+ dispatch_async(RCTGetMethodQueue(), ^{
638
+ NSDictionary *ensureSetupError = [self _ensureSetup];
639
+ if (ensureSetupError) {
640
+ reject(@"ASYNC_STORAGE_ERROR",
641
+ ensureSetupError[@"message"] ?: @"Storage setup failed",
642
+ nil);
643
+ return;
644
+ }
645
+
646
+ BOOL changedManifest = NO;
647
+ NSMutableArray<NSDictionary *> *errors;
648
+ for (__strong NSArray<NSString *> *entry in keyValuePairs) {
649
+ NSDictionary *keyError;
650
+ NSString *value = [self _getValueForKey:entry[0] errorOut:&keyError];
651
+ if (!keyError) {
652
+ if (value) {
653
+ NSError *jsonError;
654
+ NSMutableDictionary *mergedVal = RCTJSONParseMutable(value, &jsonError);
655
+ NSDictionary *mergingValue = RCTJSONParse(entry[1], &jsonError);
656
+ if (!mergingValue.count || RCTMergeRecursive(mergedVal, mergingValue)) {
657
+ entry = @[entry[0], RCTNullIfNil(RCTJSONStringify(mergedVal, NULL))];
658
+ }
659
+ if (jsonError) {
660
+ keyError = RCTJSErrorFromNSError(jsonError);
661
+ }
662
+ }
663
+ if (!keyError) {
664
+ keyError = [self _writeEntry:entry changedManifest:&changedManifest];
665
+ }
666
+ }
667
+ RCTAppendError(keyError, &errors);
668
+ }
669
+ if (changedManifest) {
670
+ [self _writeManifest:&errors];
671
+ }
672
+ if (errors.count > 0) {
673
+ reject(@"ASYNC_STORAGE_ERROR",
674
+ @"One or more keys failed to merge",
675
+ nil);
676
+ } else {
677
+ resolve(nil);
678
+ }
679
+ });
680
+ }
681
+
682
+ - (void)getAllKeys:(RCTPromiseResolveBlock)resolve
683
+ reject:(RCTPromiseRejectBlock)reject
684
+ {
685
+ dispatch_async(RCTGetMethodQueue(), ^{
686
+ NSDictionary *ensureSetupError = [self _ensureSetup];
687
+ if (ensureSetupError) {
688
+ reject(@"ASYNC_STORAGE_ERROR",
689
+ ensureSetupError[@"message"] ?: @"Storage setup failed",
690
+ nil);
691
+ return;
692
+ }
693
+ resolve(self->_manifest.allKeys);
694
+ });
695
+ }
696
+
697
+ - (void)clear:(RCTPromiseResolveBlock)resolve
698
+ reject:(RCTPromiseRejectBlock)reject
699
+ {
700
+ dispatch_async(RCTGetMethodQueue(), ^{
701
+ [self->_manifest removeAllObjects];
702
+ [RCTGetCache() removeAllObjects];
703
+ NSDictionary *error = RCTDeleteStorageDirectory();
704
+ if (error) {
705
+ reject(@"ASYNC_STORAGE_ERROR",
706
+ error[@"message"] ?: @"Failed to clear storage",
707
+ nil);
708
+ } else {
709
+ resolve(nil);
710
+ }
711
+ });
712
+ }
713
+
714
+ @end
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+ export default TurboModuleRegistry.getEnforcing('RNCAsyncStorage');
5
+ //# sourceMappingURL=NativeAsyncStorage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeAsyncStorage.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAYlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,iBAAiB,CAAC","ignoreList":[]}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ import NativeAsyncStorage from "./NativeAsyncStorage.js";
4
+ export default NativeAsyncStorage;
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NativeAsyncStorage"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,kBAAkB,MAAM,yBAAsB;AAErD,eAAeA,kBAAkB","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,12 @@
1
+ import type { TurboModule } from 'react-native';
2
+ export interface Spec extends TurboModule {
3
+ multiGet(keys: string[]): Promise<[string, string | null][]>;
4
+ multiSet(keyValuePairs: [string, string][]): Promise<void>;
5
+ multiRemove(keys: string[]): Promise<void>;
6
+ multiMerge(keyValuePairs: [string, string][]): Promise<void>;
7
+ getAllKeys(): Promise<string[]>;
8
+ clear(): Promise<void>;
9
+ }
10
+ declare const _default: Spec;
11
+ export default _default;
12
+ //# sourceMappingURL=NativeAsyncStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeAsyncStorage.d.ts","sourceRoot":"","sources":["../../../src/NativeAsyncStorage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7D,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,UAAU,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAChC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;;AAED,wBAAyE"}
@@ -0,0 +1,4 @@
1
+ import NativeAsyncStorage from './NativeAsyncStorage';
2
+ export default NativeAsyncStorage;
3
+ export type { Spec as AsyncStorageSpec } from './NativeAsyncStorage';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AAEtD,eAAe,kBAAkB,CAAC;AAClC,YAAY,EAAE,IAAI,IAAI,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,155 @@
1
+ {
2
+ "name": "@onekeyfe/react-native-async-storage",
3
+ "version": "1.1.55",
4
+ "description": "react-native-async-storage",
5
+ "main": "./lib/module/index.js",
6
+ "types": "./lib/typescript/src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "source": "./src/index.tsx",
10
+ "types": "./lib/typescript/src/index.d.ts",
11
+ "default": "./lib/module/index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "files": [
16
+ "src",
17
+ "lib",
18
+ "ios",
19
+ "*.podspec",
20
+ "!ios/build",
21
+ "!**/__tests__",
22
+ "!**/__fixtures__",
23
+ "!**/__mocks__",
24
+ "!**/.*"
25
+ ],
26
+ "scripts": {
27
+ "clean": "del-cli ios/build lib",
28
+ "prepare": "bob build",
29
+ "typecheck": "tsc",
30
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
31
+ "test": "jest",
32
+ "release": "yarn prepare && npm whoami && npm publish --access public"
33
+ },
34
+ "keywords": [
35
+ "react-native",
36
+ "ios",
37
+ "async-storage"
38
+ ],
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-async-storage.git"
42
+ },
43
+ "author": "@onekeyhq <huanming@onekey.so> (https://github.com/OneKeyHQ/app-modules)",
44
+ "license": "MIT",
45
+ "bugs": {
46
+ "url": "https://github.com/OneKeyHQ/app-modules/react-native-async-storage/issues"
47
+ },
48
+ "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-async-storage#readme",
49
+ "publishConfig": {
50
+ "registry": "https://registry.npmjs.org/"
51
+ },
52
+ "devDependencies": {
53
+ "@commitlint/config-conventional": "^19.8.1",
54
+ "@eslint/compat": "^1.3.2",
55
+ "@eslint/eslintrc": "^3.3.1",
56
+ "@eslint/js": "^9.35.0",
57
+ "@react-native/babel-preset": "0.83.0",
58
+ "@react-native/eslint-config": "0.83.0",
59
+ "@release-it/conventional-changelog": "^10.0.1",
60
+ "@types/jest": "^29.5.14",
61
+ "@types/react": "^19.2.0",
62
+ "commitlint": "^19.8.1",
63
+ "del-cli": "^6.0.0",
64
+ "eslint": "^9.35.0",
65
+ "eslint-config-prettier": "^10.1.8",
66
+ "eslint-plugin-prettier": "^5.5.4",
67
+ "jest": "^29.7.0",
68
+ "lefthook": "^2.0.3",
69
+ "prettier": "^2.8.8",
70
+ "react": "19.2.0",
71
+ "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch",
72
+ "react-native-builder-bob": "^0.40.17",
73
+ "release-it": "^19.0.4",
74
+ "turbo": "^2.5.6",
75
+ "typescript": "^5.9.2"
76
+ },
77
+ "peerDependencies": {
78
+ "react": "*",
79
+ "react-native": "*"
80
+ },
81
+ "react-native-builder-bob": {
82
+ "source": "src",
83
+ "output": "lib",
84
+ "targets": [
85
+ [
86
+ "module",
87
+ {
88
+ "esm": true
89
+ }
90
+ ],
91
+ [
92
+ "typescript",
93
+ {
94
+ "project": "tsconfig.build.json"
95
+ }
96
+ ]
97
+ ]
98
+ },
99
+ "codegenConfig": {
100
+ "name": "AsyncStorageSpec",
101
+ "type": "modules",
102
+ "jsSrcsDir": "src",
103
+ "android": {
104
+ "javaPackageName": "com.asyncstorage"
105
+ }
106
+ },
107
+ "prettier": {
108
+ "quoteProps": "consistent",
109
+ "singleQuote": true,
110
+ "tabWidth": 2,
111
+ "trailingComma": "es5",
112
+ "useTabs": false
113
+ },
114
+ "jest": {
115
+ "preset": "react-native",
116
+ "modulePathIgnorePatterns": [
117
+ "<rootDir>/lib/"
118
+ ]
119
+ },
120
+ "commitlint": {
121
+ "extends": [
122
+ "@commitlint/config-conventional"
123
+ ]
124
+ },
125
+ "release-it": {
126
+ "git": {
127
+ "commitMessage": "chore: release ${version}",
128
+ "tagName": "v${version}"
129
+ },
130
+ "npm": {
131
+ "publish": true
132
+ },
133
+ "github": {
134
+ "release": true
135
+ },
136
+ "plugins": {
137
+ "@release-it/conventional-changelog": {
138
+ "preset": {
139
+ "name": "angular"
140
+ }
141
+ }
142
+ }
143
+ },
144
+ "create-react-native-library": {
145
+ "type": "turbo-module",
146
+ "languages": "kotlin-objc",
147
+ "tools": [
148
+ "eslint",
149
+ "jest",
150
+ "lefthook",
151
+ "release-it"
152
+ ],
153
+ "version": "0.56.0"
154
+ }
155
+ }
@@ -0,0 +1,13 @@
1
+ import { TurboModuleRegistry } from 'react-native';
2
+ import type { TurboModule } from 'react-native';
3
+
4
+ export interface Spec extends TurboModule {
5
+ multiGet(keys: string[]): Promise<[string, string | null][]>;
6
+ multiSet(keyValuePairs: [string, string][]): Promise<void>;
7
+ multiRemove(keys: string[]): Promise<void>;
8
+ multiMerge(keyValuePairs: [string, string][]): Promise<void>;
9
+ getAllKeys(): Promise<string[]>;
10
+ clear(): Promise<void>;
11
+ }
12
+
13
+ export default TurboModuleRegistry.getEnforcing<Spec>('RNCAsyncStorage');
package/src/index.tsx ADDED
@@ -0,0 +1,4 @@
1
+ import NativeAsyncStorage from './NativeAsyncStorage';
2
+
3
+ export default NativeAsyncStorage;
4
+ export type { Spec as AsyncStorageSpec } from './NativeAsyncStorage';