react-native-cloud-storage 2.3.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +1 -1
  2. package/android/build.gradle +1 -14
  3. package/android/src/main/java/com/voicekit/CloudStorageLocalFileSystemModule.kt +16 -20
  4. package/android/src/main/java/com/voicekit/CloudStoragePackage.kt +23 -8
  5. package/dist/commonjs/cloud-storage.js +66 -31
  6. package/dist/commonjs/cloud-storage.js.map +1 -1
  7. package/dist/commonjs/specs/NativeCloudStorageCloudKitIOS.js +9 -0
  8. package/dist/commonjs/specs/NativeCloudStorageCloudKitIOS.js.map +1 -0
  9. package/dist/commonjs/specs/NativeCloudStorageLocalFileSystem.js +9 -0
  10. package/dist/commonjs/specs/NativeCloudStorageLocalFileSystem.js.map +1 -0
  11. package/dist/commonjs/storages/cloudkit.js +5 -3
  12. package/dist/commonjs/storages/cloudkit.js.map +1 -1
  13. package/dist/commonjs/storages/google-drive/client.js +3 -2
  14. package/dist/commonjs/storages/google-drive/client.js.map +1 -1
  15. package/dist/commonjs/storages/google-drive/index.js +99 -77
  16. package/dist/commonjs/storages/google-drive/index.js.map +1 -1
  17. package/dist/commonjs/types/main.js.map +1 -1
  18. package/dist/commonjs/utils/constants.js +2 -1
  19. package/dist/commonjs/utils/constants.js.map +1 -1
  20. package/dist/commonjs/utils/local-fs.js +3 -2
  21. package/dist/commonjs/utils/local-fs.js.map +1 -1
  22. package/dist/commonjs/utils/native.js.map +1 -1
  23. package/dist/module/cloud-storage.js +68 -33
  24. package/dist/module/cloud-storage.js.map +1 -1
  25. package/dist/module/specs/NativeCloudStorageCloudKitIOS.js +5 -0
  26. package/dist/module/specs/NativeCloudStorageCloudKitIOS.js.map +1 -0
  27. package/dist/module/specs/NativeCloudStorageLocalFileSystem.js +5 -0
  28. package/dist/module/specs/NativeCloudStorageLocalFileSystem.js.map +1 -0
  29. package/dist/module/storages/cloudkit.js +3 -2
  30. package/dist/module/storages/cloudkit.js.map +1 -1
  31. package/dist/module/storages/google-drive/client.js +3 -2
  32. package/dist/module/storages/google-drive/client.js.map +1 -1
  33. package/dist/module/storages/google-drive/index.js +99 -77
  34. package/dist/module/storages/google-drive/index.js.map +1 -1
  35. package/dist/module/types/main.js.map +1 -1
  36. package/dist/module/utils/constants.js +2 -1
  37. package/dist/module/utils/constants.js.map +1 -1
  38. package/dist/module/utils/local-fs.js +2 -2
  39. package/dist/module/utils/local-fs.js.map +1 -1
  40. package/dist/module/utils/native.js.map +1 -1
  41. package/dist/typescript/cloud-storage.d.ts +7 -0
  42. package/dist/typescript/cloud-storage.d.ts.map +1 -1
  43. package/dist/typescript/specs/NativeCloudStorageCloudKitIOS.d.ts +30 -0
  44. package/dist/typescript/specs/NativeCloudStorageCloudKitIOS.d.ts.map +1 -0
  45. package/dist/typescript/specs/NativeCloudStorageLocalFileSystem.d.ts +24 -0
  46. package/dist/typescript/specs/NativeCloudStorageLocalFileSystem.d.ts.map +1 -0
  47. package/dist/typescript/storages/cloudkit.d.ts +3 -0
  48. package/dist/typescript/storages/cloudkit.d.ts.map +1 -1
  49. package/dist/typescript/storages/google-drive/client.d.ts +1 -1
  50. package/dist/typescript/storages/google-drive/client.d.ts.map +1 -1
  51. package/dist/typescript/storages/google-drive/index.d.ts +7 -1
  52. package/dist/typescript/storages/google-drive/index.d.ts.map +1 -1
  53. package/dist/typescript/types/main.d.ts +8 -0
  54. package/dist/typescript/types/main.d.ts.map +1 -1
  55. package/dist/typescript/types/native.d.ts +6 -43
  56. package/dist/typescript/types/native.d.ts.map +1 -1
  57. package/dist/typescript/utils/constants.d.ts.map +1 -1
  58. package/dist/typescript/utils/local-fs.d.ts +1 -2
  59. package/dist/typescript/utils/local-fs.d.ts.map +1 -1
  60. package/dist/typescript/utils/native.d.ts +1 -1
  61. package/dist/typescript/utils/native.d.ts.map +1 -1
  62. package/ios/CloudStorage-Bridging-Header.h +0 -1
  63. package/ios/CloudStorageCloudKit.swift +15 -14
  64. package/ios/CloudStorageLocalFileSystem.swift +7 -6
  65. package/ios/RCTCloudStorageCloudKit.mm +209 -0
  66. package/ios/RCTCloudStorageLocalFileSystem.mm +149 -0
  67. package/ios/Utils/CloudKitUtils.swift +8 -2
  68. package/ios/Utils/FileUtils.swift +2 -4
  69. package/ios/Utils/Promise.swift +1 -0
  70. package/ios/Utils/Types.swift +1 -0
  71. package/ios/react_native_cloud_storage.h +6 -0
  72. package/package.json +30 -17
  73. package/react-native-cloud-storage.podspec +2 -0
  74. package/src/cloud-storage.ts +90 -42
  75. package/src/specs/NativeCloudStorageCloudKitIOS.ts +33 -0
  76. package/src/specs/NativeCloudStorageLocalFileSystem.ts +28 -0
  77. package/src/storages/cloudkit.ts +10 -2
  78. package/src/storages/google-drive/client.ts +2 -1
  79. package/src/storages/google-drive/index.ts +126 -120
  80. package/src/types/main.ts +9 -0
  81. package/src/types/native.ts +10 -54
  82. package/src/utils/constants.ts +1 -0
  83. package/src/utils/local-fs.ts +2 -2
  84. package/src/utils/native.ts +1 -1
  85. package/ios/CloudStorageCloudKit.m +0 -24
  86. package/ios/CloudStorageEventEmitter.m +0 -16
  87. package/ios/CloudStorageEventEmitter.swift +0 -30
  88. package/ios/CloudStorageLocalFileSystem.m +0 -15
@@ -0,0 +1,149 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ #import <CloudStorageSpec/CloudStorageSpec.h>
4
+
5
+ #if __has_include("react_native_cloud_storage-Swift.h")
6
+ #import "react_native_cloud_storage-Swift.h"
7
+ #elif __has_include(<react_native_cloud_storage/react_native_cloud_storage-Swift.h>)
8
+ #import <react_native_cloud_storage/react_native_cloud_storage-Swift.h>
9
+ #else
10
+ #error "Unable to locate Swift compatibility header for react-native-cloud-storage."
11
+ #endif
12
+
13
+ @interface RCTCloudStorageLocalFileSystem : NSObject <NativeCloudStorageLocalFileSystemSpec>
14
+ @end
15
+
16
+ @implementation RCTCloudStorageLocalFileSystem {
17
+ CloudStorageLocalFileSystem *_cloudStorageLocalFileSystem;
18
+ }
19
+
20
+ + (NSString *)moduleName
21
+ {
22
+ return @"CloudStorageLocalFileSystem";
23
+ }
24
+
25
+ + (BOOL)requiresMainQueueSetup
26
+ {
27
+ return NO;
28
+ }
29
+
30
+ - (instancetype)init
31
+ {
32
+ if (self = [super init]) {
33
+ _cloudStorageLocalFileSystem = [CloudStorageLocalFileSystem new];
34
+ }
35
+
36
+ return self;
37
+ }
38
+
39
+ - (NSDictionary<NSString *, id> *)serializeDownloadOptions:
40
+ (JS::NativeCloudStorageLocalFileSystem::LocalFileSystemDownloadOptions &)options
41
+ {
42
+ NSMutableDictionary<NSString *, id> *serializedOptions = [NSMutableDictionary new];
43
+
44
+ id<NSObject> headers = options.headers();
45
+ if (headers != nil) {
46
+ serializedOptions[@"headers"] = headers;
47
+ }
48
+
49
+ return serializedOptions;
50
+ }
51
+
52
+ - (NSDictionary<NSString *, id> *)serializeUploadOptions:
53
+ (JS::NativeCloudStorageLocalFileSystem::LocalFileSystemUploadOptions &)options
54
+ {
55
+ NSMutableDictionary<NSString *, id> *serializedOptions = [NSMutableDictionary new];
56
+
57
+ id<NSObject> headers = options.headers();
58
+ if (headers != nil) {
59
+ serializedOptions[@"headers"] = headers;
60
+ }
61
+
62
+ NSString *method = options.method();
63
+ if (method != nil) {
64
+ serializedOptions[@"method"] = method;
65
+ }
66
+
67
+ NSString *uploadType = options.uploadType();
68
+ if (uploadType != nil) {
69
+ serializedOptions[@"uploadType"] = uploadType;
70
+ }
71
+
72
+ NSString *fieldName = options.fieldName();
73
+ if (fieldName != nil) {
74
+ serializedOptions[@"fieldName"] = fieldName;
75
+ }
76
+
77
+ id<NSObject> parameters = options.parameters();
78
+ if (parameters != nil) {
79
+ serializedOptions[@"parameters"] = parameters;
80
+ }
81
+
82
+ return serializedOptions;
83
+ }
84
+
85
+ - (facebook::react::ModuleConstants<JS::NativeCloudStorageLocalFileSystem::Constants::Builder>)constantsToExport
86
+ {
87
+ return (facebook::react::ModuleConstants<JS::NativeCloudStorageLocalFileSystem::Constants::Builder>)[self getConstants];
88
+ }
89
+
90
+ - (facebook::react::ModuleConstants<JS::NativeCloudStorageLocalFileSystem::Constants::Builder>)getConstants
91
+ {
92
+ NSDictionary<NSString *, id> *constants = [_cloudStorageLocalFileSystem constantsToExport];
93
+ NSString *temporaryDirectory = constants[@"temporaryDirectory"];
94
+
95
+ return facebook::react::typedConstants<JS::NativeCloudStorageLocalFileSystem::Constants::Builder>({
96
+ .temporaryDirectory = temporaryDirectory ?: NSTemporaryDirectory(),
97
+ });
98
+ }
99
+
100
+ - (void)createFile:(NSString *)path
101
+ data:(NSString *)data
102
+ resolve:(RCTPromiseResolveBlock)resolve
103
+ reject:(RCTPromiseRejectBlock)reject
104
+ {
105
+ [_cloudStorageLocalFileSystem createFile:path withData:data withResolver:resolve withRejecter:reject];
106
+ }
107
+
108
+ - (void)readFile:(NSString *)path
109
+ resolve:(RCTPromiseResolveBlock)resolve
110
+ reject:(RCTPromiseRejectBlock)reject
111
+ {
112
+ [_cloudStorageLocalFileSystem readFile:path withResolver:resolve withRejecter:reject];
113
+ }
114
+
115
+ - (void)downloadFile:(NSString *)remoteUri
116
+ localPath:(NSString *)localPath
117
+ options:(JS::NativeCloudStorageLocalFileSystem::LocalFileSystemDownloadOptions &)options
118
+ resolve:(RCTPromiseResolveBlock)resolve
119
+ reject:(RCTPromiseRejectBlock)reject
120
+ {
121
+ [_cloudStorageLocalFileSystem
122
+ downloadFile:remoteUri
123
+ withLocalPath:localPath
124
+ withOptions:[self serializeDownloadOptions:options]
125
+ withResolver:resolve
126
+ withRejecter:reject];
127
+ }
128
+
129
+ - (void)uploadFile:(NSString *)localPath
130
+ remoteUri:(NSString *)remoteUri
131
+ options:(JS::NativeCloudStorageLocalFileSystem::LocalFileSystemUploadOptions &)options
132
+ resolve:(RCTPromiseResolveBlock)resolve
133
+ reject:(RCTPromiseRejectBlock)reject
134
+ {
135
+ [_cloudStorageLocalFileSystem
136
+ uploadFile:localPath
137
+ withRemoteUri:remoteUri
138
+ withOptions:[self serializeUploadOptions:options]
139
+ withResolver:resolve
140
+ withRejecter:reject];
141
+ }
142
+
143
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
144
+ (const facebook::react::ObjCTurboModule::InitParams &)params
145
+ {
146
+ return std::make_shared<facebook::react::NativeCloudStorageLocalFileSystemSpecJSI>(params);
147
+ }
148
+
149
+ @end
@@ -42,10 +42,10 @@ enum CloudKitUtils {
42
42
  }
43
43
 
44
44
  /**
45
- Returns the iCloud directory URL for the given scope.
45
+ Returns the directory URL for the given scope.
46
46
 
47
47
  - Parameter scope: The scope of the directory.
48
- - Returns: The URL of the iCloud directory, or nil if no directory is found.
48
+ - Returns: The URL of the scope directory, or nil if no directory is found.
49
49
  */
50
50
  private static func getScopeDirectory(scope: DirectoryScope) -> URL? {
51
51
  switch scope {
@@ -53,6 +53,8 @@ enum CloudKitUtils {
53
53
  appDataDirectory
54
54
  case .documents:
55
55
  documentsDirectory
56
+ case .documentsLegacy:
57
+ legacyDocumentsDirectory
56
58
  }
57
59
  }
58
60
 
@@ -107,6 +109,10 @@ enum CloudKitUtils {
107
109
  }
108
110
 
109
111
  static var documentsDirectory: URL? {
112
+ fileManager.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")
113
+ }
114
+
115
+ static var legacyDocumentsDirectory: URL? {
110
116
  fileManager.urls(for: .documentDirectory, in: .userDomainMask).first
111
117
  }
112
118
  }
@@ -28,8 +28,7 @@ enum FileUtils {
28
28
  }
29
29
 
30
30
  do {
31
- let fileContents = try String(contentsOf: fileUrl, encoding: .utf8)
32
- return fileContents
31
+ return try String(contentsOf: fileUrl, encoding: .utf8)
33
32
  } catch {
34
33
  throw CloudStorageError.readError(path: fileUrl.path)
35
34
  }
@@ -73,8 +72,7 @@ enum FileUtils {
73
72
  */
74
73
  static func listFiles(directoryUrl: URL) throws -> [String] {
75
74
  do {
76
- let fileUrls = try fileManager.contentsOfDirectory(atPath: directoryUrl.path)
77
- return fileUrls
75
+ return try fileManager.contentsOfDirectory(atPath: directoryUrl.path)
78
76
  } catch {
79
77
  throw CloudStorageError.readError(path: directoryUrl.path)
80
78
  }
@@ -7,6 +7,7 @@
7
7
  //
8
8
 
9
9
  import Foundation
10
+ import React
10
11
 
11
12
  // MARK: - Promise
12
13
 
@@ -20,6 +20,7 @@ enum UploadType: String {
20
20
  enum DirectoryScope: String {
21
21
  case appData = "app_data"
22
22
  case documents
23
+ case documentsLegacy = "documents_legacy"
23
24
  }
24
25
 
25
26
  // MARK: - FileStat
@@ -0,0 +1,6 @@
1
+ #ifndef REACT_NATIVE_CLOUD_STORAGE_H
2
+ #define REACT_NATIVE_CLOUD_STORAGE_H
3
+
4
+ #import <Foundation/Foundation.h>
5
+
6
+ #endif
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-cloud-storage",
3
- "version": "2.3.0",
3
+ "version": "3.0.0",
4
4
  "description": "☁️ Save to & read from iCloud and Google Drive using React Native",
5
5
  "main": "dist/commonjs/index",
6
6
  "module": "dist/module/index",
@@ -37,11 +37,12 @@
37
37
  ],
38
38
  "scripts": {
39
39
  "clean": "del-cli android/build ios/build dist",
40
- "build": "yarn clean && bob build && rm -f dist/commonjs/package.json",
41
- "test": "jest",
40
+ "build": "pnpm clean && bob build && rm -f dist/commonjs/package.json",
41
+ "codegen": "pnpm run codegen:clean && pnpm run codegen:ios && pnpm run codegen:android",
42
+ "codegen:clean": "del-cli android/generated ios/generated",
43
+ "codegen:ios": "node ../../node_modules/react-native/scripts/generate-codegen-artifacts.js --path . --targetPlatform ios --outputPath ios/generated",
44
+ "codegen:android": "node ../../node_modules/react-native/scripts/generate-codegen-artifacts.js --path . --targetPlatform android --outputPath android/generated",
42
45
  "typecheck": "tsc --noEmit",
43
- "lint": "eslint src/**/*.ts",
44
- "format": "prettier --write . && ./scripts/swiftformat.sh",
45
46
  "release": "release-it",
46
47
  "prepack": "cp ../../README.md ./README.md",
47
48
  "postpack": "rm ./README.md"
@@ -56,36 +57,30 @@
56
57
  "url": "https://github.com/kuatsu/react-native-cloud-storage/issues"
57
58
  },
58
59
  "homepage": "https://github.com/kuatsu/react-native-cloud-storage#readme",
59
- "packageManager": "yarn@3.6.1",
60
+ "packageManager": "pnpm@10.28.2",
60
61
  "publishConfig": {
61
62
  "registry": "https://registry.npmjs.org/"
62
63
  },
63
64
  "devDependencies": {
64
65
  "@expo/config-plugins": "^10.0.2",
65
66
  "@release-it/conventional-changelog": "^5.0.0",
66
- "@types/react": "~19.0.10",
67
- "react": "19.0.0",
68
- "react-native": "0.79.3",
67
+ "@types/react": "~19.2.14",
68
+ "react": "19.2.0",
69
+ "react-native": "0.83.2",
69
70
  "react-native-builder-bob": "^0.30.2",
70
71
  "release-it": "^15.0.0",
71
- "typescript": "~5.8.3"
72
+ "typescript": "~5.9.3"
72
73
  },
73
74
  "peerDependencies": {
74
75
  "expo": ">=48.0.0",
75
76
  "react": "*",
76
- "react-native": "*"
77
+ "react-native": ">=0.76"
77
78
  },
78
79
  "peerDependenciesMeta": {
79
80
  "expo": {
80
81
  "optional": true
81
82
  }
82
83
  },
83
- "jest": {
84
- "preset": "react-native",
85
- "modulePathIgnorePatterns": [
86
- "<rootDir>/dist/"
87
- ]
88
- },
89
84
  "release-it": {
90
85
  "git": {
91
86
  "commitMessage": "chore: release ${version}",
@@ -122,5 +117,23 @@
122
117
  }
123
118
  ]
124
119
  ]
120
+ },
121
+ "codegenConfig": {
122
+ "name": "CloudStorageSpec",
123
+ "type": "modules",
124
+ "jsSrcsDir": "src/specs",
125
+ "android": {
126
+ "javaPackageName": "com.cloudstorage"
127
+ },
128
+ "ios": {
129
+ "modules": {
130
+ "CloudStorageCloudKit": {
131
+ "className": "RCTCloudStorageCloudKit"
132
+ },
133
+ "CloudStorageLocalFileSystem": {
134
+ "className": "RCTCloudStorageLocalFileSystem"
135
+ }
136
+ }
137
+ }
125
138
  }
126
139
  }
@@ -15,6 +15,8 @@ Pod::Spec.new do |s|
15
15
  s.source = { :git => "https://github.com/Kuatsu/react-native-cloud-storage.git", :tag => "#{s.version}" }
16
16
 
17
17
  s.source_files = "ios/**/*.{h,m,mm,swift}"
18
+ s.exclude_files = "ios/generated/**/*"
19
+ s.public_header_files = "ios/react_native_cloud_storage.h"
18
20
 
19
21
  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
20
22
  # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
@@ -5,11 +5,11 @@ import {
5
5
  type CloudStorageProviderOptions,
6
6
  type DeepRequired,
7
7
  } from './types/main';
8
- import { NativeCloudStorageErrorCode, type NativeStorage } from './types/native';
8
+ import { NativeCloudStorageErrorCode, type NativeStorage, type NativeStorageScope } from './types/native';
9
9
  import { isProviderSupported } from './utils/helpers';
10
- import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
10
+ import { Platform, type EventSubscription } from 'react-native';
11
11
  import GoogleDrive from './storages/google-drive';
12
- import { NativeCloudKit } from './storages/cloudkit';
12
+ import { NativeCloudKit, NativeCloudKitModule, type NativeCloudStorageCloudKitTurboModule } from './storages/cloudkit';
13
13
  import { DEFAULT_PROVIDER_OPTIONS, LINKING_ERROR } from './utils/constants';
14
14
  import CloudStorageError from './utils/cloud-storage-error';
15
15
 
@@ -20,6 +20,7 @@ export default class RNCloudStorage {
20
20
  options: (typeof DEFAULT_PROVIDER_OPTIONS)[keyof typeof DEFAULT_PROVIDER_OPTIONS];
21
21
  };
22
22
  private cloudAvailabilityListeners: ((available: boolean) => void)[] = [];
23
+ private cloudAvailabilitySubscription: EventSubscription | null = null;
23
24
 
24
25
  //#region Constructor and configuration
25
26
  /**
@@ -97,6 +98,49 @@ export default class RNCloudStorage {
97
98
  return this.provider.provider;
98
99
  }
99
100
 
101
+ private notifyCloudAvailabilityListeners(available: boolean): void {
102
+ for (const listener of this.cloudAvailabilityListeners) {
103
+ listener(available);
104
+ }
105
+ }
106
+
107
+ private refreshCloudAvailability(): void {
108
+ this.nativeStorage
109
+ .isCloudAvailable()
110
+ .then((available) => {
111
+ this.notifyCloudAvailabilityListeners(available);
112
+ })
113
+ .catch(() => {
114
+ // ignore errors when refreshing availability after provider changes
115
+ });
116
+ }
117
+
118
+ private getNativeCloudKitModule(): NativeCloudStorageCloudKitTurboModule | null {
119
+ return this.provider.provider === CloudStorageProvider.ICloud ? NativeCloudKitModule : null;
120
+ }
121
+
122
+ private removeCloudAvailabilitySubscription(): void {
123
+ this.cloudAvailabilitySubscription?.remove();
124
+ this.cloudAvailabilitySubscription = null;
125
+ }
126
+
127
+ private configureCloudAvailabilitySubscription(): void {
128
+ this.removeCloudAvailabilitySubscription();
129
+
130
+ if (this.cloudAvailabilityListeners.length === 0) {
131
+ return;
132
+ }
133
+
134
+ const nativeCloudKitModule = this.getNativeCloudKitModule();
135
+ if (!nativeCloudKitModule) {
136
+ return;
137
+ }
138
+
139
+ this.cloudAvailabilitySubscription = nativeCloudKitModule.onCloudAvailabilityChanged((event) => {
140
+ this.notifyCloudAvailabilityListeners(event.available);
141
+ });
142
+ }
143
+
100
144
  /**
101
145
  * Sets the current CloudStorageProvider.
102
146
  * @param provider The provider to set.
@@ -111,22 +155,8 @@ export default class RNCloudStorage {
111
155
  options: DEFAULT_PROVIDER_OPTIONS[provider],
112
156
  };
113
157
 
114
- // Emit an event to notify useIsCloudAvailable() hook consumers of the new cloud availability status
115
- this.nativeStorage.isCloudAvailable().then((available) => {
116
- for (const listener of this.cloudAvailabilityListeners) {
117
- listener(available);
118
- }
119
- });
120
-
121
- if (provider === CloudStorageProvider.ICloud) {
122
- // Listen to native cloud availability change events
123
- const eventEmitter = new NativeEventEmitter(NativeModules.CloudStorageEventEmitter);
124
- eventEmitter.addListener('RNCloudStorage.cloud.availability-changed', (event: { available: boolean }) => {
125
- for (const listener of this.cloudAvailabilityListeners) {
126
- listener(event.available);
127
- }
128
- });
129
- }
158
+ this.refreshCloudAvailability();
159
+ this.configureCloudAvailabilitySubscription();
130
160
  }
131
161
 
132
162
  /**
@@ -150,20 +180,44 @@ export default class RNCloudStorage {
150
180
 
151
181
  if (this.provider.provider === CloudStorageProvider.GoogleDrive && 'accessToken' in newOptions) {
152
182
  // Emit an event to notify useIsCloudAvailable() hook consumers of the new cloud availability status
153
- for (const listener of this.cloudAvailabilityListeners) {
154
- listener(
155
- !!(newOptions as Required<CloudStorageProviderOptions[CloudStorageProvider.GoogleDrive]>).accessToken?.length
156
- );
157
- }
183
+ this.notifyCloudAvailabilityListeners(
184
+ !!(newOptions as Required<CloudStorageProviderOptions[CloudStorageProvider.GoogleDrive]>).accessToken?.length
185
+ );
158
186
  }
159
187
  }
160
188
 
161
189
  subscribeToCloudAvailability(listener: (available: boolean) => void): void {
162
190
  this.cloudAvailabilityListeners.push(listener);
191
+
192
+ if (this.cloudAvailabilityListeners.length === 1) {
193
+ this.configureCloudAvailabilitySubscription();
194
+ this.refreshCloudAvailability();
195
+ }
163
196
  }
164
197
 
165
198
  unsubscribeFromCloudAvailability(listener: (available: boolean) => void): void {
166
199
  this.cloudAvailabilityListeners = this.cloudAvailabilityListeners.filter((l) => l !== listener);
200
+
201
+ if (this.cloudAvailabilityListeners.length === 0) {
202
+ this.removeCloudAvailabilitySubscription();
203
+ }
204
+ }
205
+
206
+ private resolveNativeScope(scope?: CloudStorageScope): NativeStorageScope {
207
+ const resolvedScope = scope ?? this.provider.options.scope;
208
+
209
+ if (this.provider.provider !== CloudStorageProvider.ICloud || resolvedScope !== CloudStorageScope.Documents) {
210
+ return resolvedScope;
211
+ }
212
+
213
+ const iCloudOptions = this.provider.options as DeepRequired<
214
+ CloudStorageProviderOptions[CloudStorageProvider.ICloud]
215
+ >;
216
+ if (iCloudOptions.documentsMode === 'legacy_sandbox') {
217
+ return 'documents_legacy';
218
+ }
219
+
220
+ return resolvedScope;
167
221
  }
168
222
  //#endregion
169
223
 
@@ -185,7 +239,7 @@ export default class RNCloudStorage {
185
239
  * @returns A promise that resolves when the data has been appended.
186
240
  */
187
241
  appendFile(path: string, data: string, scope?: CloudStorageScope): Promise<void> {
188
- return this.nativeStorage.appendToFile(path, data, scope ?? this.provider.options.scope);
242
+ return this.nativeStorage.appendToFile(path, data, this.resolveNativeScope(scope));
189
243
  }
190
244
 
191
245
  /**
@@ -195,7 +249,7 @@ export default class RNCloudStorage {
195
249
  * @returns A promise that resolves to true if the path exists, false otherwise.
196
250
  */
197
251
  exists(path: string, scope?: CloudStorageScope): Promise<boolean> {
198
- return this.nativeStorage.fileExists(path, scope ?? this.provider.options.scope);
252
+ return this.nativeStorage.fileExists(path, this.resolveNativeScope(scope));
199
253
  }
200
254
 
201
255
  /**
@@ -206,7 +260,7 @@ export default class RNCloudStorage {
206
260
  * @returns A promise that resolves when the file has been written.
207
261
  */
208
262
  writeFile(path: string, data: string, scope?: CloudStorageScope): Promise<void> {
209
- return this.nativeStorage.createFile(path, data, scope ?? this.provider.options.scope, true);
263
+ return this.nativeStorage.createFile(path, data, this.resolveNativeScope(scope), true);
210
264
  }
211
265
 
212
266
  /**
@@ -216,7 +270,7 @@ export default class RNCloudStorage {
216
270
  * @returns A promise that resolves when the directory has been created.
217
271
  */
218
272
  mkdir(path: string, scope?: CloudStorageScope): Promise<void> {
219
- return this.nativeStorage.createDirectory(path, scope ?? this.provider.options.scope);
273
+ return this.nativeStorage.createDirectory(path, this.resolveNativeScope(scope));
220
274
  }
221
275
 
222
276
  /**
@@ -226,7 +280,7 @@ export default class RNCloudStorage {
226
280
  * @returns A promise that resolves to an array of file names, excluding '.' and '..'.
227
281
  */
228
282
  readdir(path: string, scope?: CloudStorageScope): Promise<string[]> {
229
- return this.nativeStorage.listFiles(path, scope ?? this.provider.options.scope);
283
+ return this.nativeStorage.listFiles(path, this.resolveNativeScope(scope));
230
284
  }
231
285
 
232
286
  /**
@@ -236,7 +290,7 @@ export default class RNCloudStorage {
236
290
  * @returns A promise that resolves to the contents of the file.
237
291
  */
238
292
  readFile(path: string, scope?: CloudStorageScope): Promise<string> {
239
- return this.nativeStorage.readFile(path, scope ?? this.provider.options.scope);
293
+ return this.nativeStorage.readFile(path, this.resolveNativeScope(scope));
240
294
  }
241
295
 
242
296
  /**
@@ -246,7 +300,7 @@ export default class RNCloudStorage {
246
300
  * @returns A promise that resolves once the synchronization has been triggered.
247
301
  */
248
302
  triggerSync(path: string, scope?: CloudStorageScope): Promise<void> {
249
- return this.nativeStorage.triggerSync(path, scope ?? this.provider.options.scope);
303
+ return this.nativeStorage.triggerSync(path, this.resolveNativeScope(scope));
250
304
  }
251
305
 
252
306
  /**
@@ -263,13 +317,7 @@ export default class RNCloudStorage {
263
317
  options: { mimeType: string },
264
318
  scope?: CloudStorageScope
265
319
  ): Promise<void> {
266
- return this.nativeStorage.uploadFile(
267
- remotePath,
268
- localPath,
269
- options.mimeType,
270
- scope ?? this.provider.options.scope,
271
- true
272
- );
320
+ return this.nativeStorage.uploadFile(remotePath, localPath, options.mimeType, this.resolveNativeScope(scope), true);
273
321
  }
274
322
 
275
323
  /**
@@ -301,7 +349,7 @@ export default class RNCloudStorage {
301
349
  if (!localPathOrScope) {
302
350
  throw new CloudStorageError('Invalid arguments provided to downloadFile', NativeCloudStorageErrorCode.UNKNOWN);
303
351
  }
304
- return this.nativeStorage.downloadFile(remotePathOrPath, localPathOrScope, scope ?? this.provider.options.scope);
352
+ return this.nativeStorage.downloadFile(remotePathOrPath, localPathOrScope, this.resolveNativeScope(scope));
305
353
  }
306
354
 
307
355
  /**
@@ -311,7 +359,7 @@ export default class RNCloudStorage {
311
359
  * @returns A promise that resolves when the file has been deleted.
312
360
  */
313
361
  unlink(path: string, scope?: CloudStorageScope): Promise<void> {
314
- return this.nativeStorage.deleteFile(path, scope ?? this.provider.options.scope);
362
+ return this.nativeStorage.deleteFile(path, this.resolveNativeScope(scope));
315
363
  }
316
364
 
317
365
  /**
@@ -322,7 +370,7 @@ export default class RNCloudStorage {
322
370
  * @returns A promise that resolves when the directory has been deleted.
323
371
  */
324
372
  rmdir(path: string, options?: { recursive?: boolean }, scope?: CloudStorageScope): Promise<void> {
325
- return this.nativeStorage.deleteDirectory(path, options?.recursive ?? false, scope ?? this.provider.options.scope);
373
+ return this.nativeStorage.deleteDirectory(path, options?.recursive ?? false, this.resolveNativeScope(scope));
326
374
  }
327
375
 
328
376
  /**
@@ -332,7 +380,7 @@ export default class RNCloudStorage {
332
380
  * @returns A promise that resolves to the CloudStorageFileStat object.
333
381
  */
334
382
  async stat(path: string, scope?: CloudStorageScope): Promise<CloudStorageFileStat> {
335
- const native = await this.nativeStorage.statFile(path, scope ?? this.provider.options.scope);
383
+ const native = await this.nativeStorage.statFile(path, this.resolveNativeScope(scope));
336
384
 
337
385
  return {
338
386
  ...native,
@@ -0,0 +1,33 @@
1
+ import type { CodegenTypes, TurboModule } from 'react-native';
2
+ import { TurboModuleRegistry } from 'react-native';
3
+
4
+ export type CloudStorageFileStat = {
5
+ size: number;
6
+ birthtimeMs: number;
7
+ mtimeMs: number;
8
+ isDirectory: boolean;
9
+ isFile: boolean;
10
+ };
11
+
12
+ export type CloudAvailabilityChangedEvent = {
13
+ available: boolean;
14
+ };
15
+
16
+ export interface Spec extends TurboModule {
17
+ fileExists(path: string, scope: string): Promise<boolean>;
18
+ appendToFile(path: string, data: string, scope: string): Promise<void>;
19
+ createFile(path: string, data: string, scope: string, overwrite: boolean): Promise<void>;
20
+ createDirectory(path: string, scope: string): Promise<void>;
21
+ listFiles(path: string, scope: string): Promise<Array<string>>;
22
+ readFile(path: string, scope: string): Promise<string>;
23
+ triggerSync(path: string, scope: string): Promise<void>;
24
+ deleteFile(path: string, scope: string): Promise<void>;
25
+ deleteDirectory(path: string, recursive: boolean, scope: string): Promise<void>;
26
+ statFile(path: string, scope: string): Promise<CloudStorageFileStat>;
27
+ downloadFile(remotePath: string, localPath: string, scope: string): Promise<void>;
28
+ uploadFile(remotePath: string, localPath: string, mimeType: string, scope: string, overwrite: boolean): Promise<void>;
29
+ isCloudAvailable(): Promise<boolean>;
30
+ readonly onCloudAvailabilityChanged: CodegenTypes.EventEmitter<CloudAvailabilityChangedEvent>;
31
+ }
32
+
33
+ export default TurboModuleRegistry.get<Spec>('CloudStorageCloudKit');
@@ -0,0 +1,28 @@
1
+ import type { CodegenTypes, TurboModule } from 'react-native';
2
+ import { TurboModuleRegistry } from 'react-native';
3
+
4
+ export type LocalFileSystemConstants = {
5
+ temporaryDirectory: string;
6
+ };
7
+
8
+ export type LocalFileSystemDownloadOptions = {
9
+ headers?: CodegenTypes.UnsafeObject;
10
+ };
11
+
12
+ export type LocalFileSystemUploadOptions = {
13
+ headers?: CodegenTypes.UnsafeObject;
14
+ method?: string;
15
+ uploadType?: string;
16
+ fieldName?: string;
17
+ parameters?: CodegenTypes.UnsafeObject;
18
+ };
19
+
20
+ export interface Spec extends TurboModule {
21
+ getConstants(): LocalFileSystemConstants;
22
+ createFile(path: string, data: string): Promise<string>;
23
+ readFile(path: string): Promise<string>;
24
+ downloadFile(remoteUri: string, localPath: string, options?: LocalFileSystemDownloadOptions): Promise<void>;
25
+ uploadFile(localPath: string, remoteUri: string, options: LocalFileSystemUploadOptions): Promise<void>;
26
+ }
27
+
28
+ export default TurboModuleRegistry.get<Spec>('CloudStorageLocalFileSystem');
@@ -1,5 +1,13 @@
1
- import { NativeModules } from 'react-native';
1
+ import NativeCloudStorageCloudKitIOS, {
2
+ type Spec as NativeCloudStorageCloudKitTurboModule,
3
+ } from '../specs/NativeCloudStorageCloudKitIOS';
2
4
  import { NativeStorage } from '../types/native';
3
5
  import { createProxiedNativeModule } from '../utils/native';
4
6
 
5
- export const NativeCloudKit = createProxiedNativeModule<NativeStorage>(NativeModules.CloudStorageCloudKit);
7
+ export const NativeCloudKitModule = NativeCloudStorageCloudKitIOS;
8
+
9
+ export const NativeCloudKit = createProxiedNativeModule<NativeStorage>(
10
+ NativeCloudStorageCloudKitIOS as unknown as NativeStorage | null
11
+ );
12
+
13
+ export type { NativeCloudStorageCloudKitTurboModule };