react-native-cloud-storage 2.2.1 → 2.3.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.
- package/LICENSE +1 -1
- package/android/build.gradle +101 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/voicekit/CloudStorageError.kt +86 -0
- package/android/src/main/java/com/voicekit/CloudStorageLocalFileSystemModule.kt +236 -0
- package/android/src/main/java/com/voicekit/CloudStoragePackage.kt +17 -0
- package/android/src/main/java/com/voicekit/FileUtils.kt +41 -0
- package/android/src/main/java/com/voicekit/Types.kt +6 -0
- package/app.plugin.js +1 -1
- package/{lib/commonjs/RNCloudStorage.js → dist/commonjs/cloud-storage.js} +130 -80
- package/dist/commonjs/cloud-storage.js.map +1 -0
- package/dist/commonjs/expo-plugin/index.js +13 -0
- package/dist/commonjs/expo-plugin/index.js.map +1 -0
- package/{lib/commonjs/expo-plugin/withRNCloudStorageIos.js → dist/commonjs/expo-plugin/ios.js} +1 -1
- package/dist/commonjs/expo-plugin/ios.js.map +1 -0
- package/{lib/commonjs/hooks/useCloudFile.js → dist/commonjs/hooks/use-cloud-file.js} +26 -8
- package/dist/commonjs/hooks/use-cloud-file.js.map +1 -0
- package/{lib/commonjs/hooks/useIsCloudAvailable.js → dist/commonjs/hooks/use-is-cloud-available.js} +3 -3
- package/dist/commonjs/hooks/use-is-cloud-available.js.map +1 -0
- package/{lib → dist}/commonjs/index.js +10 -10
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/storages/cloudkit.js +10 -0
- package/dist/commonjs/storages/cloudkit.js.map +1 -0
- package/{lib/commonjs → dist/commonjs/storages}/google-drive/client.js +82 -39
- package/dist/commonjs/storages/google-drive/client.js.map +1 -0
- package/{lib/commonjs → dist/commonjs/storages}/google-drive/index.js +120 -64
- package/dist/commonjs/storages/google-drive/index.js.map +1 -0
- package/dist/commonjs/storages/google-drive/types.js.map +1 -0
- package/dist/commonjs/types/native.js +28 -0
- package/dist/commonjs/types/native.js.map +1 -0
- package/{lib/commonjs/utils/CloudStorageError.js → dist/commonjs/utils/cloud-storage-error.js} +3 -1
- package/dist/commonjs/utils/cloud-storage-error.js.map +1 -0
- package/dist/commonjs/utils/constants.js +24 -0
- package/dist/commonjs/utils/constants.js.map +1 -0
- package/dist/commonjs/utils/local-fs.js +16 -0
- package/dist/commonjs/utils/local-fs.js.map +1 -0
- package/dist/commonjs/utils/native.js +35 -0
- package/dist/commonjs/utils/native.js.map +1 -0
- package/{lib/module/RNCloudStorage.js → dist/module/cloud-storage.js} +130 -80
- package/dist/module/cloud-storage.js.map +1 -0
- package/dist/module/expo-plugin/index.js +8 -0
- package/dist/module/expo-plugin/index.js.map +1 -0
- package/{lib/module/expo-plugin/withRNCloudStorageIos.js → dist/module/expo-plugin/ios.js} +1 -1
- package/dist/module/expo-plugin/ios.js.map +1 -0
- package/{lib/module/hooks/useCloudFile.js → dist/module/hooks/use-cloud-file.js} +25 -7
- package/dist/module/hooks/use-cloud-file.js.map +1 -0
- package/{lib/module/hooks/useIsCloudAvailable.js → dist/module/hooks/use-is-cloud-available.js} +2 -2
- package/dist/module/hooks/use-is-cloud-available.js.map +1 -0
- package/dist/module/index.js +9 -0
- package/dist/module/index.js.map +1 -0
- package/dist/module/storages/cloudkit.js +6 -0
- package/dist/module/storages/cloudkit.js.map +1 -0
- package/{lib/module → dist/module/storages}/google-drive/client.js +82 -39
- package/dist/module/storages/google-drive/client.js.map +1 -0
- package/{lib/module → dist/module/storages}/google-drive/index.js +119 -62
- package/dist/module/storages/google-drive/index.js.map +1 -0
- package/dist/module/storages/google-drive/types.js.map +1 -0
- package/dist/module/types/native.js +24 -0
- package/dist/module/types/native.js.map +1 -0
- package/{lib/module/utils/CloudStorageError.js → dist/module/utils/cloud-storage-error.js} +3 -1
- package/dist/module/utils/cloud-storage-error.js.map +1 -0
- package/dist/module/utils/constants.js +20 -0
- package/dist/module/utils/constants.js.map +1 -0
- package/dist/module/utils/local-fs.js +12 -0
- package/dist/module/utils/local-fs.js.map +1 -0
- package/dist/module/utils/native.js +30 -0
- package/dist/module/utils/native.js.map +1 -0
- package/{lib/typescript/RNCloudStorage.d.ts → dist/typescript/cloud-storage.d.ts} +60 -8
- package/dist/typescript/cloud-storage.d.ts.map +1 -0
- package/{lib/typescript/expo-plugin/withRNCloudStorage.d.ts → dist/typescript/expo-plugin/index.d.ts} +1 -1
- package/dist/typescript/expo-plugin/index.d.ts.map +1 -0
- package/{lib/typescript/expo-plugin/withRNCloudStorageIos.d.ts → dist/typescript/expo-plugin/ios.d.ts} +1 -1
- package/dist/typescript/expo-plugin/ios.d.ts.map +1 -0
- package/{lib/typescript/hooks/useCloudFile.d.ts → dist/typescript/hooks/use-cloud-file.d.ts} +22 -4
- package/dist/typescript/hooks/use-cloud-file.d.ts.map +1 -0
- package/{lib/typescript/hooks/useIsCloudAvailable.d.ts → dist/typescript/hooks/use-is-cloud-available.d.ts} +2 -2
- package/dist/typescript/hooks/use-is-cloud-available.d.ts.map +1 -0
- package/dist/typescript/index.d.ts +7 -0
- package/dist/typescript/index.d.ts.map +1 -0
- package/dist/typescript/storages/cloudkit.d.ts +3 -0
- package/dist/typescript/storages/cloudkit.d.ts.map +1 -0
- package/{lib/typescript → dist/typescript/storages}/google-drive/client.d.ts +9 -2
- package/dist/typescript/storages/google-drive/client.d.ts.map +1 -0
- package/dist/typescript/storages/google-drive/index.d.ts +35 -0
- package/dist/typescript/storages/google-drive/index.d.ts.map +1 -0
- package/dist/typescript/storages/google-drive/types.d.ts.map +1 -0
- package/dist/typescript/types/native.d.ts +64 -0
- package/dist/typescript/types/native.d.ts.map +1 -0
- package/dist/typescript/utils/cloud-storage-error.d.ts +8 -0
- package/dist/typescript/utils/cloud-storage-error.d.ts.map +1 -0
- package/dist/typescript/utils/constants.d.ts +4 -0
- package/dist/typescript/utils/constants.d.ts.map +1 -0
- package/{lib → dist}/typescript/utils/helpers.d.ts.map +1 -1
- package/dist/typescript/utils/local-fs.d.ts +3 -0
- package/dist/typescript/utils/local-fs.d.ts.map +1 -0
- package/dist/typescript/utils/native.d.ts +7 -0
- package/dist/typescript/utils/native.d.ts.map +1 -0
- package/ios/CloudStorage.xcodeproj/project.pbxproj +12 -6
- package/ios/{CloudStorage.m → CloudStorageCloudKit.m} +4 -2
- package/ios/{CloudStorage.swift → CloudStorageCloudKit.swift} +60 -5
- package/ios/CloudStorageLocalFileSystem.m +15 -0
- package/ios/CloudStorageLocalFileSystem.swift +215 -0
- package/ios/Utils/CloudKitUtils.swift +4 -4
- package/ios/Utils/CloudStorageError.swift +8 -0
- package/ios/Utils/FileUtils.swift +19 -0
- package/ios/Utils/Types.swift +7 -1
- package/package.json +44 -103
- package/src/{RNCloudStorage.ts → cloud-storage.ts} +147 -85
- package/src/expo-plugin/{withRNCloudStorage.ts → index.ts} +2 -2
- package/src/hooks/{useCloudFile.ts → use-cloud-file.ts} +24 -6
- package/src/hooks/{useIsCloudAvailable.ts → use-is-cloud-available.ts} +1 -1
- package/src/index.ts +5 -6
- package/src/storages/cloudkit.ts +5 -0
- package/src/{google-drive → storages/google-drive}/client.ts +99 -40
- package/src/{google-drive → storages/google-drive}/index.ts +172 -89
- package/src/types/native.ts +50 -14
- package/src/utils/cloud-storage-error.ts +15 -0
- package/src/utils/constants.ts +20 -0
- package/src/utils/local-fs.ts +19 -0
- package/src/utils/native.ts +40 -0
- package/lib/commonjs/RNCloudStorage.js.map +0 -1
- package/lib/commonjs/expo-plugin/withRNCloudStorage.js +0 -13
- package/lib/commonjs/expo-plugin/withRNCloudStorage.js.map +0 -1
- package/lib/commonjs/expo-plugin/withRNCloudStorageIos.js.map +0 -1
- package/lib/commonjs/google-drive/client.js.map +0 -1
- package/lib/commonjs/google-drive/index.js.map +0 -1
- package/lib/commonjs/google-drive/types.js.map +0 -1
- package/lib/commonjs/hooks/useCloudFile.js.map +0 -1
- package/lib/commonjs/hooks/useIsCloudAvailable.js.map +0 -1
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/types/native.js +0 -26
- package/lib/commonjs/types/native.js.map +0 -1
- package/lib/commonjs/utils/CloudStorageError.js.map +0 -1
- package/lib/module/RNCloudStorage.js.map +0 -1
- package/lib/module/expo-plugin/withRNCloudStorage.js +0 -8
- package/lib/module/expo-plugin/withRNCloudStorage.js.map +0 -1
- package/lib/module/expo-plugin/withRNCloudStorageIos.js.map +0 -1
- package/lib/module/google-drive/client.js.map +0 -1
- package/lib/module/google-drive/index.js.map +0 -1
- package/lib/module/google-drive/types.js.map +0 -1
- package/lib/module/hooks/useCloudFile.js.map +0 -1
- package/lib/module/hooks/useIsCloudAvailable.js.map +0 -1
- package/lib/module/index.js +0 -10
- package/lib/module/index.js.map +0 -1
- package/lib/module/types/native.js +0 -22
- package/lib/module/types/native.js.map +0 -1
- package/lib/module/utils/CloudStorageError.js.map +0 -1
- package/lib/typescript/RNCloudStorage.d.ts.map +0 -1
- package/lib/typescript/expo-plugin/withRNCloudStorage.d.ts.map +0 -1
- package/lib/typescript/expo-plugin/withRNCloudStorageIos.d.ts.map +0 -1
- package/lib/typescript/google-drive/client.d.ts.map +0 -1
- package/lib/typescript/google-drive/index.d.ts +0 -34
- package/lib/typescript/google-drive/index.d.ts.map +0 -1
- package/lib/typescript/google-drive/types.d.ts.map +0 -1
- package/lib/typescript/hooks/useCloudFile.d.ts.map +0 -1
- package/lib/typescript/hooks/useIsCloudAvailable.d.ts.map +0 -1
- package/lib/typescript/index.d.ts +0 -8
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/types/native.d.ts +0 -40
- package/lib/typescript/types/native.d.ts.map +0 -1
- package/lib/typescript/utils/CloudStorageError.d.ts +0 -8
- package/lib/typescript/utils/CloudStorageError.d.ts.map +0 -1
- package/src/utils/CloudStorageError.ts +0 -14
- /package/{lib → dist}/commonjs/expo-plugin/types/index.js +0 -0
- /package/{lib → dist}/commonjs/expo-plugin/types/index.js.map +0 -0
- /package/{lib/commonjs → dist/commonjs/storages}/google-drive/types.js +0 -0
- /package/{lib → dist}/commonjs/types/main.js +0 -0
- /package/{lib → dist}/commonjs/types/main.js.map +0 -0
- /package/{lib → dist}/commonjs/utils/helpers.js +0 -0
- /package/{lib → dist}/commonjs/utils/helpers.js.map +0 -0
- /package/{lib → dist}/module/expo-plugin/types/index.js +0 -0
- /package/{lib → dist}/module/expo-plugin/types/index.js.map +0 -0
- /package/{lib → dist}/module/package.json +0 -0
- /package/{lib/module → dist/module/storages}/google-drive/types.js +0 -0
- /package/{lib → dist}/module/types/main.js +0 -0
- /package/{lib → dist}/module/types/main.js.map +0 -0
- /package/{lib → dist}/module/utils/helpers.js +0 -0
- /package/{lib → dist}/module/utils/helpers.js.map +0 -0
- /package/{lib → dist}/typescript/expo-plugin/types/index.d.ts +0 -0
- /package/{lib → dist}/typescript/expo-plugin/types/index.d.ts.map +0 -0
- /package/{lib/typescript → dist/typescript/storages}/google-drive/types.d.ts +0 -0
- /package/{lib → dist}/typescript/types/main.d.ts +0 -0
- /package/{lib → dist}/typescript/types/main.d.ts.map +0 -0
- /package/{lib → dist}/typescript/utils/helpers.d.ts +0 -0
- /package/src/expo-plugin/{withRNCloudStorageIos.ts → ios.ts} +0 -0
- /package/src/{google-drive → storages/google-drive}/types.ts +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
|
|
3
|
-
@objc(
|
|
4
|
-
class
|
|
3
|
+
@objc(CloudStorageCloudKit)
|
|
4
|
+
class CloudStorageCloudKit: NSObject {
|
|
5
5
|
@objc(fileExists:withScope:withResolver:withRejecter:)
|
|
6
6
|
func fileExists(path: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
7
7
|
withPromise(resolve: resolve, reject: reject) {
|
|
@@ -62,11 +62,11 @@ class CloudStorage: NSObject {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
@objc(
|
|
66
|
-
func
|
|
65
|
+
@objc(triggerSync:withScope:withResolver:withRejecter:)
|
|
66
|
+
func triggerSync(path: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
67
67
|
withPromise(resolve: resolve, reject: reject) {
|
|
68
68
|
let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
|
|
69
|
-
return try CloudKitUtils.
|
|
69
|
+
return try CloudKitUtils.triggerSync(fileUrl: fileUrl)
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -94,6 +94,61 @@ class CloudStorage: NSObject {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
@objc(downloadFile:withLocalPath:withScope:withResolver:withRejecter:)
|
|
98
|
+
func downloadFile(remotePath: String, localPath: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
99
|
+
withPromise(resolve: resolve, reject: reject) {
|
|
100
|
+
let sourceUrl = try CloudKitUtils.getFileURL(path: remotePath, scope: scope, true)
|
|
101
|
+
|
|
102
|
+
let sourceStat = try FileUtils.statFile(fileUrl: sourceUrl)
|
|
103
|
+
if sourceStat.isDirectory {
|
|
104
|
+
throw CloudStorageError.pathIsDirectory(path: remotePath)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let destinationUrl = URL(fileURLWithPath: localPath)
|
|
108
|
+
let destinationDirectoryUrl = destinationUrl.deletingLastPathComponent()
|
|
109
|
+
|
|
110
|
+
if try !FileUtils.checkFileExists(fileUrl: destinationDirectoryUrl) {
|
|
111
|
+
throw CloudStorageError.directoryNotFound(path: destinationDirectoryUrl.path)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let destDirStat = try FileUtils.statFile(fileUrl: destinationDirectoryUrl)
|
|
115
|
+
if !destDirStat.isDirectory {
|
|
116
|
+
throw CloudStorageError.pathIsFile(path: destinationDirectoryUrl.path)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if try FileUtils.checkFileExists(fileUrl: destinationUrl) {
|
|
120
|
+
throw CloudStorageError.fileAlreadyExists(path: localPath)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return try FileUtils.copyFile(from: sourceUrl, to: destinationUrl)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@objc(uploadFile:withLocalPath:withMimeType:withScope:withOverwrite:withResolver:withRejecter:)
|
|
128
|
+
func uploadFile(remotePath: String, localPath: String, mimeType _: String, scope: String, overwrite: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
129
|
+
withPromise(resolve: resolve, reject: reject) {
|
|
130
|
+
let destinationUrl = try CloudKitUtils.getFileURL(path: remotePath, scope: scope)
|
|
131
|
+
let sourceUrl = URL(fileURLWithPath: localPath)
|
|
132
|
+
|
|
133
|
+
if try !FileUtils.checkFileExists(fileUrl: sourceUrl) {
|
|
134
|
+
throw CloudStorageError.fileNotFound(path: localPath)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let destinationDirectoryUrl = destinationUrl.deletingLastPathComponent()
|
|
138
|
+
try FileUtils.createDirectory(directoryUrl: destinationDirectoryUrl)
|
|
139
|
+
|
|
140
|
+
if try FileUtils.checkFileExists(fileUrl: destinationUrl) {
|
|
141
|
+
if overwrite {
|
|
142
|
+
try FileUtils.deleteFileOrDirectory(fileUrl: destinationUrl)
|
|
143
|
+
} else {
|
|
144
|
+
throw CloudStorageError.fileAlreadyExists(path: remotePath)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return try FileUtils.copyFile(from: sourceUrl, to: destinationUrl)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
97
152
|
@objc(isCloudAvailable:withRejecter:)
|
|
98
153
|
func isCloudAvailable(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
99
154
|
withPromise(resolve: resolve, reject: reject) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
|
|
3
|
+
@interface RCT_EXTERN_MODULE(CloudStorageLocalFileSystem, NSObject)
|
|
4
|
+
|
|
5
|
+
RCT_EXTERN_METHOD(readFile:(NSString *)path withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject)
|
|
6
|
+
RCT_EXTERN_METHOD(createFile:(NSString *)path withData:(NSString *)data withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject)
|
|
7
|
+
RCT_EXTERN_METHOD(downloadFile:(NSString *)remoteUri withLocalPath:(NSString *)localPath withOptions:(NSDictionary *)options withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject)
|
|
8
|
+
RCT_EXTERN_METHOD(uploadFile:(NSString *)localPath withRemoteUri:(NSString *)remoteUri withOptions:(NSDictionary *)options withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject)
|
|
9
|
+
|
|
10
|
+
+ (BOOL)requiresMainQueueSetup
|
|
11
|
+
{
|
|
12
|
+
return NO;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@end
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import MobileCoreServices
|
|
3
|
+
|
|
4
|
+
// MARK: - CloudStorageLocalFileSystem
|
|
5
|
+
|
|
6
|
+
@objc(CloudStorageLocalFileSystem)
|
|
7
|
+
class CloudStorageLocalFileSystem: NSObject {
|
|
8
|
+
@objc
|
|
9
|
+
func constantsToExport() -> [AnyHashable: Any]! {
|
|
10
|
+
[
|
|
11
|
+
"temporaryDirectory": FileUtils.temporaryDirectory.path,
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@objc(createFile:withData:withResolver:withRejecter:)
|
|
16
|
+
func createFile(path: String, data: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
17
|
+
withPromise(resolve: resolve, reject: reject) {
|
|
18
|
+
let fileUrl = URL(fileURLWithPath: path)
|
|
19
|
+
let directoryUrl = fileUrl.deletingLastPathComponent()
|
|
20
|
+
|
|
21
|
+
var isDirectory: ObjCBool = false
|
|
22
|
+
if !FileManager.default.fileExists(atPath: directoryUrl.path, isDirectory: &isDirectory) {
|
|
23
|
+
throw CloudStorageError.directoryNotFound(path: directoryUrl.path)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if !isDirectory.boolValue {
|
|
27
|
+
throw CloudStorageError.pathIsFile(path: directoryUrl.path)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try FileUtils.writeFile(fileUrl: fileUrl, content: data)
|
|
31
|
+
return fileUrl.path
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@objc(readFile:withResolver:withRejecter:)
|
|
36
|
+
func readFile(path: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
37
|
+
withPromise(resolve: resolve, reject: reject) {
|
|
38
|
+
let fileUrl = URL(fileURLWithPath: path)
|
|
39
|
+
return try FileUtils.readFile(fileUrl: fileUrl)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@objc(downloadFile:withLocalPath:withOptions:withResolver:withRejecter:)
|
|
44
|
+
func downloadFile(remoteUri: String, localPath: String, options: [String: Any]?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
45
|
+
guard let remoteUrl = URL(string: remoteUri) else {
|
|
46
|
+
let error = CloudStorageError.invalidUrl(url: remoteUri)
|
|
47
|
+
reject(error.code, error.message, nil)
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let sanitizedPath = sanitizePath(localPath)
|
|
52
|
+
let localUrl = URL(fileURLWithPath: sanitizedPath)
|
|
53
|
+
|
|
54
|
+
let configuration = URLSessionConfiguration.default
|
|
55
|
+
if let headers = options?["headers"] as? [String: String] {
|
|
56
|
+
configuration.httpAdditionalHeaders = headers
|
|
57
|
+
}
|
|
58
|
+
let session = URLSession(configuration: configuration)
|
|
59
|
+
|
|
60
|
+
let downloadTask = session.downloadTask(with: remoteUrl) { tempLocalUrl, _, error in
|
|
61
|
+
if let error {
|
|
62
|
+
let nsError = error as NSError
|
|
63
|
+
let cloudError = CloudStorageError.networkError(message: "Download error for path \(remoteUri): \(nsError.localizedDescription)")
|
|
64
|
+
reject(cloudError.code, cloudError.message, nsError)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
guard let tempLocalUrl else {
|
|
69
|
+
let cloudError = CloudStorageError.unknown(message: "Download failed: temporary file location is missing.")
|
|
70
|
+
reject(cloudError.code, cloudError.message, nil)
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
do {
|
|
75
|
+
let directory = localUrl.deletingLastPathComponent()
|
|
76
|
+
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil)
|
|
77
|
+
|
|
78
|
+
if FileManager.default.fileExists(atPath: localUrl.path) {
|
|
79
|
+
try FileManager.default.removeItem(at: localUrl)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try FileManager.default.moveItem(at: tempLocalUrl, to: localUrl)
|
|
83
|
+
resolve(nil)
|
|
84
|
+
} catch {
|
|
85
|
+
let nsError = error as NSError
|
|
86
|
+
let cloudError = CloudStorageError.writeError(path: localUrl.path)
|
|
87
|
+
reject(cloudError.code, cloudError.message, nsError)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
downloadTask.resume()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@objc(uploadFile:withRemoteUri:withOptions:withResolver:withRejecter:)
|
|
95
|
+
func uploadFile(localPath: String, remoteUri: String, options: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
96
|
+
guard let remoteUrl = URL(string: remoteUri) else {
|
|
97
|
+
let error = CloudStorageError.invalidUrl(url: remoteUri)
|
|
98
|
+
reject(error.code, error.message, nil)
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let sanitizedPath = sanitizePath(localPath)
|
|
103
|
+
let localUrl = URL(fileURLWithPath: sanitizedPath)
|
|
104
|
+
|
|
105
|
+
guard let uploadTypeString = options["uploadType"] as? String,
|
|
106
|
+
let uploadType = UploadType(rawValue: uploadTypeString) else {
|
|
107
|
+
let error = CloudStorageError.unknown(message: "uploadType is required and must be either 'multipart' or 'binary'")
|
|
108
|
+
reject(error.code, error.message, nil)
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
var request = URLRequest(url: remoteUrl)
|
|
113
|
+
request.httpMethod = (options["method"] as? String)?.uppercased() ?? "POST"
|
|
114
|
+
|
|
115
|
+
if let headers = options["headers"] as? [String: String] {
|
|
116
|
+
for (key, value) in headers {
|
|
117
|
+
request.setValue(value, forHTTPHeaderField: key)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
do {
|
|
122
|
+
let fileData = try Data(contentsOf: localUrl)
|
|
123
|
+
|
|
124
|
+
switch uploadType {
|
|
125
|
+
case .binary:
|
|
126
|
+
request.httpBody = fileData
|
|
127
|
+
if request.value(forHTTPHeaderField: "Content-Type") == nil {
|
|
128
|
+
request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
|
|
129
|
+
}
|
|
130
|
+
case .multipart:
|
|
131
|
+
guard let fieldName = options["fieldName"] as? String else {
|
|
132
|
+
let error = CloudStorageError.unknown(message: "fieldName is required for multipart uploads")
|
|
133
|
+
reject(error.code, error.message, nil)
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let boundary = "Boundary-\(UUID().uuidString)"
|
|
138
|
+
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
|
139
|
+
|
|
140
|
+
var body = Data()
|
|
141
|
+
let lineBreak = "\r\n"
|
|
142
|
+
|
|
143
|
+
if let parameters = options["parameters"] as? [String: String] {
|
|
144
|
+
for (key, value) in parameters {
|
|
145
|
+
body.append("--\(boundary)\(lineBreak)")
|
|
146
|
+
body.append("Content-Disposition: form-data; name=\"\(key)\"\(lineBreak)\(lineBreak)")
|
|
147
|
+
body.append("\(value)\(lineBreak)")
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
body.append("--\(boundary)\(lineBreak)")
|
|
152
|
+
body.append("Content-Disposition: form-data; name=\"\(fieldName)\"; filename=\"\(localUrl.lastPathComponent)\"\(lineBreak)")
|
|
153
|
+
if let mimeType = getMimeType(for: localUrl) {
|
|
154
|
+
body.append("Content-Type: \(mimeType)\(lineBreak)\(lineBreak)")
|
|
155
|
+
} else {
|
|
156
|
+
body.append("Content-Type: application/octet-stream\(lineBreak)\(lineBreak)")
|
|
157
|
+
}
|
|
158
|
+
body.append(fileData)
|
|
159
|
+
body.append(lineBreak)
|
|
160
|
+
body.append("--\(boundary)--\(lineBreak)")
|
|
161
|
+
|
|
162
|
+
request.httpBody = body
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let task = URLSession.shared.dataTask(with: request) { _, response, error in
|
|
166
|
+
if let error {
|
|
167
|
+
let nsError = error as NSError
|
|
168
|
+
let cloudError = CloudStorageError.networkError(message: "Upload error for path \(sanitizedPath): \(nsError.localizedDescription)")
|
|
169
|
+
reject(cloudError.code, cloudError.message, nsError)
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
guard let httpResponse = response as? HTTPURLResponse, (200 ... 299).contains(httpResponse.statusCode) else {
|
|
174
|
+
let httpResponse = response as? HTTPURLResponse
|
|
175
|
+
let message = "Upload failed for path \(sanitizedPath) with status code: \(httpResponse?.statusCode ?? -1)"
|
|
176
|
+
let cloudError = CloudStorageError.networkError(message: message)
|
|
177
|
+
reject(cloudError.code, cloudError.message, nil)
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
resolve(nil)
|
|
182
|
+
}
|
|
183
|
+
task.resume()
|
|
184
|
+
} catch {
|
|
185
|
+
let nsError = error as NSError
|
|
186
|
+
let cloudError = CloudStorageError.readError(path: sanitizedPath)
|
|
187
|
+
reject(cloudError.code, cloudError.message, nsError)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private func sanitizePath(_ path: String) -> String {
|
|
192
|
+
if path.hasPrefix("file://") {
|
|
193
|
+
return String(path.dropFirst("file://".count))
|
|
194
|
+
}
|
|
195
|
+
return path
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private func getMimeType(for url: URL) -> String? {
|
|
199
|
+
let pathExtension = url.pathExtension
|
|
200
|
+
if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue() {
|
|
201
|
+
if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
|
|
202
|
+
return mimetype as String
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return nil
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
extension Data {
|
|
210
|
+
mutating func append(_ string: String) {
|
|
211
|
+
if let data = string.data(using: .utf8) {
|
|
212
|
+
append(data)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -21,12 +21,12 @@ enum CloudKitUtils {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
|
|
24
|
+
Syncs a file from iCloud to the device.
|
|
25
25
|
|
|
26
|
-
- Parameter fileUrl: The URL of the file to
|
|
27
|
-
- Throws: An NSError if the file is not downloadable or the
|
|
26
|
+
- Parameter fileUrl: The URL of the file to sync.
|
|
27
|
+
- Throws: An NSError if the file is not downloadable or the sync failed.
|
|
28
28
|
*/
|
|
29
|
-
static func
|
|
29
|
+
static func triggerSync(fileUrl: URL) throws {
|
|
30
30
|
let isDownloadable = fileManager.isUbiquitousItem(at: fileUrl)
|
|
31
31
|
|
|
32
32
|
if !isDownloadable {
|
|
@@ -23,6 +23,8 @@ enum CloudStorageError: Error {
|
|
|
23
23
|
case statError(path: String)
|
|
24
24
|
case unknown(message: String = "An unknown error occurred")
|
|
25
25
|
case fileNotDownloadable(path: String)
|
|
26
|
+
case invalidUrl(url: String)
|
|
27
|
+
case networkError(message: String)
|
|
26
28
|
|
|
27
29
|
var code: String {
|
|
28
30
|
switch self {
|
|
@@ -40,6 +42,8 @@ enum CloudStorageError: Error {
|
|
|
40
42
|
case .statError: "ERR_STAT_ERROR"
|
|
41
43
|
case .unknown: "ERR_UNKNOWN"
|
|
42
44
|
case .fileNotDownloadable: "ERR_FILE_NOT_DOWNLOADABLE"
|
|
45
|
+
case .invalidUrl: "ERR_INVALID_URL"
|
|
46
|
+
case .networkError: "ERR_NETWORK_ERROR"
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
|
|
@@ -73,6 +77,10 @@ enum CloudStorageError: Error {
|
|
|
73
77
|
message
|
|
74
78
|
case let .fileNotDownloadable(path):
|
|
75
79
|
"File not downloadable at path \(path)"
|
|
80
|
+
case let .invalidUrl(url):
|
|
81
|
+
"Invalid URL provided: \(url)"
|
|
82
|
+
case let .networkError(message):
|
|
83
|
+
message
|
|
76
84
|
}
|
|
77
85
|
}
|
|
78
86
|
}
|
|
@@ -94,6 +94,21 @@ enum FileUtils {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
Copies a file from a source to a destination.
|
|
99
|
+
|
|
100
|
+
- Parameter sourceUrl: The URL of the file to copy from.
|
|
101
|
+
- Parameter destinationUrl: The URL to copy the file to.
|
|
102
|
+
- Throws: An NSError if the file couldn't be copied.
|
|
103
|
+
*/
|
|
104
|
+
static func copyFile(from sourceUrl: URL, to destinationUrl: URL) throws {
|
|
105
|
+
do {
|
|
106
|
+
try fileManager.copyItem(at: sourceUrl, to: destinationUrl)
|
|
107
|
+
} catch {
|
|
108
|
+
throw CloudStorageError.writeError(path: destinationUrl.path)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
97
112
|
/**
|
|
98
113
|
Gets the stats of a file.
|
|
99
114
|
|
|
@@ -129,4 +144,8 @@ enum FileUtils {
|
|
|
129
144
|
static func sanitizePath(path: String) -> String {
|
|
130
145
|
path.replacingOccurrences(of: "^/+", with: "", options: .regularExpression)
|
|
131
146
|
}
|
|
147
|
+
|
|
148
|
+
static var temporaryDirectory: URL {
|
|
149
|
+
fileManager.temporaryDirectory
|
|
150
|
+
}
|
|
132
151
|
}
|
package/ios/Utils/Types.swift
CHANGED
|
@@ -8,9 +8,15 @@
|
|
|
8
8
|
|
|
9
9
|
import Foundation
|
|
10
10
|
|
|
11
|
+
// MARK: - UploadType
|
|
12
|
+
|
|
13
|
+
enum UploadType: String {
|
|
14
|
+
case multipart
|
|
15
|
+
case binary
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
// MARK: - DirectoryScope
|
|
12
19
|
|
|
13
|
-
@frozen
|
|
14
20
|
enum DirectoryScope: String {
|
|
15
21
|
case appData = "app_data"
|
|
16
22
|
case documents
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-cloud-storage",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Save to & read from iCloud and Google Drive using React Native",
|
|
5
|
-
"main": "
|
|
6
|
-
"module": "
|
|
7
|
-
"types": "
|
|
3
|
+
"version": "2.3.0",
|
|
4
|
+
"description": "☁️ Save to & read from iCloud and Google Drive using React Native",
|
|
5
|
+
"main": "dist/commonjs/index",
|
|
6
|
+
"module": "dist/module/index",
|
|
7
|
+
"types": "dist/typescript/index.d.ts",
|
|
8
8
|
"react-native": "src/index",
|
|
9
9
|
"source": "src/index",
|
|
10
10
|
"files": [
|
|
11
11
|
"src",
|
|
12
|
-
"
|
|
12
|
+
"dist",
|
|
13
13
|
"android",
|
|
14
14
|
"ios",
|
|
15
15
|
"cpp",
|
|
16
16
|
"*.podspec",
|
|
17
17
|
"app.plugin.js",
|
|
18
|
-
"!
|
|
18
|
+
"!dist/typescript/example",
|
|
19
19
|
"!ios/build",
|
|
20
20
|
"!android/build",
|
|
21
21
|
"!android/gradle",
|
|
@@ -27,54 +27,48 @@
|
|
|
27
27
|
"!**/__mocks__",
|
|
28
28
|
"!**/.*"
|
|
29
29
|
],
|
|
30
|
+
"keywords": [
|
|
31
|
+
"react-native",
|
|
32
|
+
"ios",
|
|
33
|
+
"android",
|
|
34
|
+
"icloud",
|
|
35
|
+
"google-drive",
|
|
36
|
+
"file-system"
|
|
37
|
+
],
|
|
30
38
|
"scripts": {
|
|
39
|
+
"clean": "del-cli android/build ios/build dist",
|
|
40
|
+
"build": "yarn clean && bob build && rm -f dist/commonjs/package.json",
|
|
31
41
|
"test": "jest",
|
|
32
|
-
"example": "yarn workspace react-native-cloud-storage-example",
|
|
33
|
-
"docs": "yarn workspace react-native-cloud-storage-docs",
|
|
34
42
|
"typecheck": "tsc --noEmit",
|
|
35
|
-
"lint": "eslint
|
|
36
|
-
"
|
|
37
|
-
"prepare": "yarn clean && bob build && rm -f lib/commonjs/package.json",
|
|
43
|
+
"lint": "eslint src/**/*.ts",
|
|
44
|
+
"format": "prettier --write . && ./scripts/swiftformat.sh",
|
|
38
45
|
"release": "release-it",
|
|
39
|
-
"
|
|
46
|
+
"prepack": "cp ../../README.md ./README.md",
|
|
47
|
+
"postpack": "rm ./README.md"
|
|
40
48
|
},
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"repository": "https://github.com/Kuatsu/react-native-cloud-storage",
|
|
47
|
-
"author": "Kuatsu App Agency <hello@kuatsu.de> (https://github.com/Kuatsu)",
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/kuatsu/react-native-cloud-storage.git"
|
|
52
|
+
},
|
|
53
|
+
"author": "Kuatsu App Agency <hello@kuatsu.de>",
|
|
48
54
|
"license": "MIT",
|
|
49
55
|
"bugs": {
|
|
50
|
-
"url": "https://github.com/
|
|
56
|
+
"url": "https://github.com/kuatsu/react-native-cloud-storage/issues"
|
|
51
57
|
},
|
|
52
|
-
"homepage": "https://github.com/
|
|
58
|
+
"homepage": "https://github.com/kuatsu/react-native-cloud-storage#readme",
|
|
59
|
+
"packageManager": "yarn@3.6.1",
|
|
53
60
|
"publishConfig": {
|
|
54
61
|
"registry": "https://registry.npmjs.org/"
|
|
55
62
|
},
|
|
56
63
|
"devDependencies": {
|
|
57
|
-
"@
|
|
58
|
-
"@evilmartians/lefthook": "^1.5.0",
|
|
59
|
-
"@expo/config-plugins": "^7.2.5",
|
|
60
|
-
"@react-native-community/eslint-config": "^3.2.0",
|
|
61
|
-
"@react-native/eslint-config": "0.74.87",
|
|
64
|
+
"@expo/config-plugins": "^10.0.2",
|
|
62
65
|
"@release-it/conventional-changelog": "^5.0.0",
|
|
63
|
-
"@types/
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"del-cli": "^5.0.0",
|
|
67
|
-
"eslint": "^8.4.1",
|
|
68
|
-
"eslint-config-prettier": "^8.5.0",
|
|
69
|
-
"eslint-plugin-prettier": "^4.0.0",
|
|
70
|
-
"jest": "^28.1.1",
|
|
71
|
-
"pod-install": "^0.2.2",
|
|
72
|
-
"prettier": "^2.0.5",
|
|
73
|
-
"react": "18.2.0",
|
|
74
|
-
"react-native": "0.74.5",
|
|
66
|
+
"@types/react": "~19.0.10",
|
|
67
|
+
"react": "19.0.0",
|
|
68
|
+
"react-native": "0.79.3",
|
|
75
69
|
"react-native-builder-bob": "^0.30.2",
|
|
76
70
|
"release-it": "^15.0.0",
|
|
77
|
-
"typescript": "
|
|
71
|
+
"typescript": "~5.8.3"
|
|
78
72
|
},
|
|
79
73
|
"peerDependencies": {
|
|
80
74
|
"expo": ">=48.0.0",
|
|
@@ -86,24 +80,10 @@
|
|
|
86
80
|
"optional": true
|
|
87
81
|
}
|
|
88
82
|
},
|
|
89
|
-
"workspaces": [
|
|
90
|
-
"example",
|
|
91
|
-
"docs"
|
|
92
|
-
],
|
|
93
|
-
"engines": {
|
|
94
|
-
"node": ">= 18.0.0"
|
|
95
|
-
},
|
|
96
|
-
"packageManager": "yarn@3.6.1",
|
|
97
83
|
"jest": {
|
|
98
84
|
"preset": "react-native",
|
|
99
85
|
"modulePathIgnorePatterns": [
|
|
100
|
-
"<rootDir>/
|
|
101
|
-
"<rootDir>/lib/"
|
|
102
|
-
]
|
|
103
|
-
},
|
|
104
|
-
"commitlint": {
|
|
105
|
-
"extends": [
|
|
106
|
-
"@commitlint/config-conventional"
|
|
86
|
+
"<rootDir>/dist/"
|
|
107
87
|
]
|
|
108
88
|
},
|
|
109
89
|
"release-it": {
|
|
@@ -112,65 +92,26 @@
|
|
|
112
92
|
"tagName": "v${version}"
|
|
113
93
|
},
|
|
114
94
|
"npm": {
|
|
115
|
-
"publish": true
|
|
95
|
+
"publish": true,
|
|
96
|
+
"versionArgs": [
|
|
97
|
+
"--workspaces-update=false"
|
|
98
|
+
]
|
|
116
99
|
},
|
|
117
100
|
"github": {
|
|
118
101
|
"release": true
|
|
119
102
|
},
|
|
120
103
|
"plugins": {
|
|
121
104
|
"@release-it/conventional-changelog": {
|
|
122
|
-
"preset":
|
|
105
|
+
"preset": {
|
|
106
|
+
"name": "angular"
|
|
107
|
+
},
|
|
108
|
+
"infile": "CHANGELOG.md"
|
|
123
109
|
}
|
|
124
110
|
}
|
|
125
111
|
},
|
|
126
|
-
"eslintConfig": {
|
|
127
|
-
"root": true,
|
|
128
|
-
"extends": [
|
|
129
|
-
"@react-native-community",
|
|
130
|
-
"prettier"
|
|
131
|
-
],
|
|
132
|
-
"rules": {
|
|
133
|
-
"react-native/no-inline-styles": "off",
|
|
134
|
-
"prettier/prettier": [
|
|
135
|
-
"error",
|
|
136
|
-
{
|
|
137
|
-
"printWidth": 120,
|
|
138
|
-
"tabWidth": 2,
|
|
139
|
-
"useTabs": false,
|
|
140
|
-
"semi": true,
|
|
141
|
-
"singleQuote": true,
|
|
142
|
-
"quoteProps": "consistent",
|
|
143
|
-
"jsxSingleQuote": false,
|
|
144
|
-
"trailingComma": "es5",
|
|
145
|
-
"bracketSpacing": true,
|
|
146
|
-
"bracketSameLine": true,
|
|
147
|
-
"arrowParens": "always",
|
|
148
|
-
"endOfLine": "lf"
|
|
149
|
-
}
|
|
150
|
-
]
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
"eslintIgnore": [
|
|
154
|
-
"node_modules/",
|
|
155
|
-
"lib/"
|
|
156
|
-
],
|
|
157
|
-
"prettier": {
|
|
158
|
-
"printWidth": 120,
|
|
159
|
-
"tabWidth": 2,
|
|
160
|
-
"useTabs": false,
|
|
161
|
-
"semi": true,
|
|
162
|
-
"singleQuote": true,
|
|
163
|
-
"quoteProps": "consistent",
|
|
164
|
-
"jsxSingleQuote": false,
|
|
165
|
-
"trailingComma": "es5",
|
|
166
|
-
"bracketSpacing": true,
|
|
167
|
-
"bracketSameLine": true,
|
|
168
|
-
"arrowParens": "always",
|
|
169
|
-
"endOfLine": "lf"
|
|
170
|
-
},
|
|
171
112
|
"react-native-builder-bob": {
|
|
172
113
|
"source": "src",
|
|
173
|
-
"output": "
|
|
114
|
+
"output": "dist",
|
|
174
115
|
"targets": [
|
|
175
116
|
"commonjs",
|
|
176
117
|
"module",
|