react-native-cloud-storage 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +5 -6
  3. package/ios/CloudStorage.swift +262 -52
  4. package/ios/CloudStorage.xcodeproj/project.pbxproj +0 -28
  5. package/ios/CloudStorage.xcodeproj/project.xcworkspace/contents.xcworkspacedata +4 -0
  6. package/ios/CloudStorage.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  7. package/ios/CloudStorage.xcodeproj/project.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  8. package/ios/CloudStorage.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/xcschememanagement.plist +22 -0
  9. package/ios/CloudStorageEventEmitter.swift +4 -4
  10. package/lib/commonjs/RNCloudStorage.js +66 -361
  11. package/lib/commonjs/RNCloudStorage.js.map +1 -1
  12. package/lib/commonjs/createRNCloudStorage.js +48 -0
  13. package/lib/commonjs/createRNCloudStorage.js.map +1 -0
  14. package/lib/commonjs/expo-plugin/types/index.js.map +1 -1
  15. package/lib/commonjs/expo-plugin/withRNCloudStorage.js +3 -2
  16. package/lib/commonjs/expo-plugin/withRNCloudStorage.js.map +1 -1
  17. package/lib/commonjs/expo-plugin/withRNCloudStorageIos.js +7 -4
  18. package/lib/commonjs/expo-plugin/withRNCloudStorageIos.js.map +1 -1
  19. package/lib/commonjs/google-drive/client.js +20 -16
  20. package/lib/commonjs/google-drive/client.js.map +1 -1
  21. package/lib/commonjs/google-drive/index.js +64 -42
  22. package/lib/commonjs/google-drive/index.js.map +1 -1
  23. package/lib/commonjs/google-drive/types.js +2 -1
  24. package/lib/commonjs/google-drive/types.js.map +1 -1
  25. package/lib/commonjs/hooks/useCloudFile.js +17 -14
  26. package/lib/commonjs/hooks/useCloudFile.js.map +1 -1
  27. package/lib/commonjs/hooks/useIsCloudAvailable.js +21 -11
  28. package/lib/commonjs/hooks/useIsCloudAvailable.js.map +1 -1
  29. package/lib/commonjs/index.js +7 -1
  30. package/lib/commonjs/index.js.map +1 -1
  31. package/lib/commonjs/types/main.js +3 -8
  32. package/lib/commonjs/types/main.js.map +1 -1
  33. package/lib/commonjs/types/native.js +3 -3
  34. package/lib/commonjs/types/native.js.map +1 -1
  35. package/lib/commonjs/utils/CloudStorageError.js +2 -1
  36. package/lib/commonjs/utils/CloudStorageError.js.map +1 -1
  37. package/lib/commonjs/utils/helpers.js +15 -8
  38. package/lib/commonjs/utils/helpers.js.map +1 -1
  39. package/lib/module/RNCloudStorage.js +65 -362
  40. package/lib/module/RNCloudStorage.js.map +1 -1
  41. package/lib/module/createRNCloudStorage.js +41 -0
  42. package/lib/module/createRNCloudStorage.js.map +1 -0
  43. package/lib/module/expo-plugin/types/index.js +1 -1
  44. package/lib/module/expo-plugin/types/index.js.map +1 -1
  45. package/lib/module/expo-plugin/withRNCloudStorage.js +0 -2
  46. package/lib/module/expo-plugin/withRNCloudStorage.js.map +1 -1
  47. package/lib/module/expo-plugin/withRNCloudStorageIos.js +5 -5
  48. package/lib/module/expo-plugin/withRNCloudStorageIos.js.map +1 -1
  49. package/lib/module/google-drive/client.js +20 -18
  50. package/lib/module/google-drive/client.js.map +1 -1
  51. package/lib/module/google-drive/index.js +62 -41
  52. package/lib/module/google-drive/index.js.map +1 -1
  53. package/lib/module/google-drive/types.js +0 -2
  54. package/lib/module/google-drive/types.js.map +1 -1
  55. package/lib/module/hooks/useCloudFile.js +16 -15
  56. package/lib/module/hooks/useCloudFile.js.map +1 -1
  57. package/lib/module/hooks/useIsCloudAvailable.js +21 -13
  58. package/lib/module/hooks/useIsCloudAvailable.js.map +1 -1
  59. package/lib/module/index.js +5 -2
  60. package/lib/module/index.js.map +1 -1
  61. package/lib/module/types/main.js +0 -9
  62. package/lib/module/types/main.js.map +1 -1
  63. package/lib/module/types/native.js +1 -4
  64. package/lib/module/types/native.js.map +1 -1
  65. package/lib/module/utils/CloudStorageError.js +0 -2
  66. package/lib/module/utils/CloudStorageError.js.map +1 -1
  67. package/lib/module/utils/helpers.js +13 -8
  68. package/lib/module/utils/helpers.js.map +1 -1
  69. package/lib/typescript/RNCloudStorage.d.ts +39 -159
  70. package/lib/typescript/RNCloudStorage.d.ts.map +1 -1
  71. package/lib/typescript/createRNCloudStorage.d.ts +3 -0
  72. package/lib/typescript/createRNCloudStorage.d.ts.map +1 -0
  73. package/lib/typescript/google-drive/client.d.ts +3 -3
  74. package/lib/typescript/google-drive/client.d.ts.map +1 -1
  75. package/lib/typescript/google-drive/index.d.ts +18 -6
  76. package/lib/typescript/google-drive/index.d.ts.map +1 -1
  77. package/lib/typescript/hooks/useCloudFile.d.ts +7 -4
  78. package/lib/typescript/hooks/useCloudFile.d.ts.map +1 -1
  79. package/lib/typescript/hooks/useIsCloudAvailable.d.ts +2 -3
  80. package/lib/typescript/hooks/useIsCloudAvailable.d.ts.map +1 -1
  81. package/lib/typescript/index.d.ts +4 -0
  82. package/lib/typescript/index.d.ts.map +1 -1
  83. package/lib/typescript/types/main.d.ts +0 -33
  84. package/lib/typescript/types/main.d.ts.map +1 -1
  85. package/lib/typescript/types/native.d.ts +1 -2
  86. package/lib/typescript/types/native.d.ts.map +1 -1
  87. package/lib/typescript/utils/helpers.d.ts +9 -2
  88. package/lib/typescript/utils/helpers.d.ts.map +1 -1
  89. package/package.json +11 -9
  90. package/src/RNCloudStorage.ts +68 -387
  91. package/src/createRNCloudStorage.ts +53 -0
  92. package/src/google-drive/client.ts +7 -8
  93. package/src/google-drive/index.ts +63 -38
  94. package/src/hooks/useCloudFile.ts +16 -13
  95. package/src/hooks/useIsCloudAvailable.ts +25 -12
  96. package/src/index.ts +5 -0
  97. package/src/types/main.ts +0 -38
  98. package/src/types/native.ts +1 -2
  99. package/src/utils/helpers.ts +15 -8
  100. package/ios/Utils/CloudKitUtils.swift +0 -112
  101. package/ios/Utils/CloudStorageError.swift +0 -78
  102. package/ios/Utils/FileUtils.swift +0 -132
  103. package/ios/Utils/Promise.swift +0 -58
  104. package/ios/Utils/Types.swift +0 -36
  105. package/lib/commonjs/package.json +0 -1
  106. package/lib/module/package.json +0 -1
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023-2024 Kuatsu Digital Agency
3
+ Copyright (c) 2023 Kuatsu Digital Agency
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to deal
6
6
  in the Software without restriction, including without limitation the rights
package/README.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  ![npm bundle size](https://img.shields.io/bundlephobia/min/react-native-cloud-storage?style=flat-square) ![GitHub](https://img.shields.io/github/license/kuatsu/react-native-cloud-storage?style=flat-square) ![GitHub last commit](https://img.shields.io/github/last-commit/kuatsu/react-native-cloud-storage?style=flat-square)
4
4
 
5
- This library provides a unified and streamlined API for accessing cloud storage services on iOS, Android and Web. It supports iCloud (on iOS only) and Google Drive (all platforms).
5
+ This library provides a unified and streamlined API for accessing cloud storage services on iOS, Android and Web. It supports iCloud on iOS and Google Drive on all other platforms.
6
6
 
7
7
  - 💾 Read and write files to the cloud
8
8
  - 🧪 Fully compatible with Expo
9
9
  - 📱 iOS, Android & Web support
10
10
  - 🏎️ Lightning fast iCloud performance using native iOS APIs
11
- - 🌐 Google Drive REST API implementation for all platforms
11
+ - 🌐 Google Drive REST API implementation for other platforms
12
12
  - 🧬 Easy to use React Hooks API, or use the imperative `fs`-style API
13
13
  - 👌 Zero dependencies, small bundle size
14
14
 
@@ -36,15 +36,14 @@ Afterwards, [add the provided config plugin](https://react-native-cloud-storage.
36
36
  ```jsx
37
37
  import React from 'react';
38
38
  import { Platform, View, Text, Button } from 'react-native';
39
- import { CloudStorage, CloudStorageProvider, useIsCloudAvailable } from 'react-native-cloud-storage';
39
+ import { CloudStorage, useIsCloudAvailable } from 'react-native-cloud-storage';
40
40
 
41
41
  const App = () => {
42
42
  const cloudAvailable = useIsCloudAvailable();
43
43
 
44
44
  React.useEffect(() => {
45
- if (CloudStorage.getDefaultProvider() === CloudStorageProvider.GoogleDrive) {
46
- // get access token via @react-native-google-signin/google-signin or similar
47
- CloudStorage.setProviderOptions({ accessToken: 'some-access-token' });
45
+ if (Platform.OS !== 'ios') {
46
+ CloudStorage.setGoogleDriveAccessToken('some-access-token'); // get via @react-native-google-signin/google-signin or similar
48
47
  }
49
48
  }, []);
50
49
 
@@ -3,101 +3,311 @@ import Foundation
3
3
  @objc(CloudStorage)
4
4
  class CloudStorage: NSObject {
5
5
  @objc(fileExists:withScope:withResolver:withRejecter:)
6
- func fileExists(path: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
7
- withPromise(resolve: resolve, reject: reject) {
8
- let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
9
- return try FileUtils.checkFileExists(fileUrl: fileUrl)
6
+ func fileExists(path: String, scope: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
7
+ let fileUrl: URL?
8
+ do {
9
+ fileUrl = try getFileURL(path, scope)
10
+ } catch let error as NSError {
11
+ reject(error.domain, error.userInfo["message"] as? String, error)
12
+ return
10
13
  }
14
+
15
+ let fileManager = FileManager.default
16
+ let fileExists = fileManager.fileExists(atPath: fileUrl!.path)
17
+ resolve(fileExists)
11
18
  }
12
19
 
13
20
  @objc(appendToFile:withData:withScope:withResolver:withRejecter:)
14
- func appendToFile(path: String, data: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
15
- withPromise(resolve: resolve, reject: reject) {
16
- let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
21
+ func appendToFile(path: String, data: String, scope: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
22
+ // Append data to the file at path. If the file doesn't exist, create it.
23
+ let fileUrl: URL?
24
+ do {
25
+ fileUrl = try getFileURL(path, scope)
26
+ } catch let error as NSError {
27
+ reject(error.domain, error.userInfo["message"] as? String, error)
28
+ return
29
+ }
17
30
 
18
- var existingData = ""
19
- if try FileUtils.checkFileExists(fileUrl: fileUrl) {
20
- existingData = try FileUtils.readFile(fileUrl: fileUrl)
31
+ let fileManager = FileManager.default
32
+ if (!fileManager.fileExists(atPath: fileUrl!.path)) {
33
+ do {
34
+ try data.write(to: fileUrl!, atomically: true, encoding: .utf8)
35
+ resolve(true)
36
+ } catch {
37
+ reject("ERR_WRITE_ERROR", "Error writing file \(path)", error)
38
+ }
39
+ } else {
40
+ do {
41
+ let fileHandle = try FileHandle(forWritingTo: fileUrl!)
42
+ fileHandle.seekToEndOfFile()
43
+ fileHandle.write(data.data(using: .utf8)!)
44
+ fileHandle.closeFile()
45
+ resolve(true)
46
+ } catch {
47
+ reject("ERR_WRITE_ERROR", "Error writing file \(path)", error)
21
48
  }
22
-
23
- let newData = existingData + data
24
- return try FileUtils.writeFile(fileUrl: fileUrl, content: newData)
25
49
  }
26
50
  }
27
51
 
28
52
  @objc(createFile:withData:withScope:withOverwrite:withResolver:withRejecter:)
29
- func createFile(path: String, data: String, scope: String, overwrite: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
30
- withPromise(resolve: resolve, reject: reject) {
31
- let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
32
-
33
- if try (FileUtils.checkFileExists(fileUrl: fileUrl) && !overwrite) {
34
- throw CloudStorageError.fileAlreadyExists(path: path)
35
- }
53
+ func createFile(path: String, data: String, scope: String, overwrite: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
54
+ let fileUrl: URL?
55
+ do {
56
+ fileUrl = try getFileURL(path, scope, overwrite ? nil : false)
57
+ } catch let error as NSError {
58
+ reject(error.domain, error.userInfo["message"] as? String, error)
59
+ return
60
+ }
36
61
 
37
- return try FileUtils.writeFile(fileUrl: fileUrl, content: data)
62
+ do {
63
+ try data.write(to: fileUrl!, atomically: true, encoding: .utf8)
64
+ resolve(true)
65
+ } catch {
66
+ reject("ERR_WRITE_ERROR", "Error writing file \(path)", error)
38
67
  }
39
68
  }
40
69
 
41
70
  @objc(createDirectory:withScope:withResolver:withRejecter:)
42
- func createDirectory(path: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
43
- withPromise(resolve: resolve, reject: reject) {
44
- let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
45
- return try FileUtils.createDirectory(directoryUrl: fileUrl)
71
+ func createDirectory(path: String, scope: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
72
+ let directoryUrl: URL?
73
+ do {
74
+ directoryUrl = try getFileURL(path, scope, false)
75
+ } catch let error as NSError {
76
+ reject(error.domain, error.userInfo["message"] as? String, error)
77
+ return
78
+ }
79
+
80
+ let fileManager = FileManager.default
81
+ do {
82
+ try fileManager.createDirectory(at: directoryUrl!, withIntermediateDirectories: true, attributes: nil)
83
+ resolve(true)
84
+ } catch {
85
+ reject("ERR_WRITE_ERROR", "Error creating directory \(path)", error)
46
86
  }
47
87
  }
48
88
 
49
89
  @objc(listFiles:withScope:withResolver:withRejecter:)
50
- func listFiles(path: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
51
- withPromise(resolve: resolve, reject: reject) {
52
- let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
53
- return try FileUtils.listFiles(directoryUrl: fileUrl)
90
+ func listFiles(path: String, scope: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
91
+ let directoryUrl: URL?
92
+ do {
93
+ directoryUrl = try getFileURL(path, scope, true)
94
+ } catch let error as NSError {
95
+ reject(error.domain, error.userInfo["message"] as? String, error)
96
+ return
97
+ }
98
+
99
+ let fileManager = FileManager.default
100
+ do {
101
+ let files = try fileManager.contentsOfDirectory(atPath: directoryUrl!.path)
102
+ resolve(files)
103
+ } catch {
104
+ reject("ERR_READ_ERROR", "Error reading directory \(path)", error)
54
105
  }
55
106
  }
56
107
 
57
108
  @objc(readFile:withScope:withResolver:withRejecter:)
58
- func readFile(path: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
59
- withPromise(resolve: resolve, reject: reject) {
60
- let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
61
- return try FileUtils.readFile(fileUrl: fileUrl)
109
+ func readFile(path: String, scope: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
110
+ let fileUrl: URL?
111
+ do {
112
+ fileUrl = try getFileURL(path, scope, true)
113
+ } catch let error as NSError {
114
+ reject(error.domain, error.userInfo["message"] as? String, error)
115
+ return
116
+ }
117
+
118
+ do {
119
+ let fileContents = try String(contentsOf: fileUrl!, encoding: .utf8)
120
+ resolve(fileContents)
121
+ } catch {
122
+ reject("ERR_READ_ERROR", "Error reading file \(path)", error)
62
123
  }
63
124
  }
64
125
 
65
126
  @objc(downloadFile:withScope:withResolver:withRejecter:)
66
- func downloadFile(path: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
67
- withPromise(resolve: resolve, reject: reject) {
68
- let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
69
- return try CloudKitUtils.downloadFile(fileUrl: fileUrl)
127
+ func downloadFile(path: String, scope: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
128
+ let fileManager = FileManager.default
129
+
130
+ guard let directory = getDirectory(scope) else {
131
+ let error = NSError(domain: "", code: 200, userInfo: [NSLocalizedDescriptionKey : "Error reading directory \(scope)"])
132
+ reject("ERR_READ_ERROR", "Error reading directory \(scope)", error)
133
+ return
134
+ }
135
+
136
+ // remove leading slashes
137
+ let path = path.replacingOccurrences(of: "^/+", with: "", options: .regularExpression)
138
+
139
+ // append path to scope directory and return URL
140
+ let filePath = directory.appendingPathComponent(path)
141
+
142
+ let isDownloadable = fileManager.isUbiquitousItem(at: filePath)
143
+
144
+ if (!isDownloadable) {
145
+ reject("ERR_FILE_NOT_DOWNLOADABLE", "File or directory \(path) is not an iCloud file", NSError(domain: "", code: 202, userInfo: [NSLocalizedDescriptionKey : "File or directory \(path) is not an iCloud file"]))
146
+ return
147
+ }
148
+ do {
149
+ // trigger download of file
150
+ try fileManager.startDownloadingUbiquitousItem(at: filePath)
151
+ } catch {
152
+ let error = NSError(domain: "", code: 202, userInfo: [NSLocalizedDescriptionKey : "File or directory \(path) not downloadable"])
153
+ reject("ERR_FILE_NOT_DOWNLOADABLE", "File or directory \(path) not downloadable", error)
154
+ return
70
155
  }
156
+ resolve(true)
71
157
  }
72
158
 
159
+
73
160
  @objc(deleteFile:withScope:withResolver:withRejecter:)
74
- func deleteFile(path: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
75
- withPromise(resolve: resolve, reject: reject) {
76
- let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
77
- return try FileUtils.deleteFileOrDirectory(fileUrl: fileUrl)
161
+ func deleteFile(path: String, scope: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
162
+ let fileUrl: URL?
163
+ do {
164
+ fileUrl = try getFileURL(path, scope, true)
165
+ } catch let error as NSError {
166
+ reject(error.domain, error.userInfo["message"] as? String, error)
167
+ return
168
+ }
169
+
170
+ if (fileUrl!.hasDirectoryPath) {
171
+ reject("ERR_PATH_IS_DIRECTORY", "Path \(path) is a directory", nil)
172
+ return
173
+ }
174
+
175
+ let fileManager = FileManager.default
176
+ do {
177
+ try fileManager.removeItem(at: fileUrl!)
178
+ resolve(true)
179
+ } catch {
180
+ reject("ERR_DELETE_ERROR", "Error deleting file \(path)", error)
78
181
  }
79
182
  }
80
183
 
81
184
  @objc(deleteDirectory:withRecursive:withScope:withResolver:withRejecter:)
82
- func deleteDirectory(path: String, recursive _: Bool, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
83
- withPromise(resolve: resolve, reject: reject) {
84
- let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
85
- return try FileUtils.deleteFileOrDirectory(fileUrl: fileUrl)
185
+ func deleteDirectory(path: String, recursive: Bool, scope: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
186
+ let fileUrl: URL?
187
+ do {
188
+ fileUrl = try getFileURL(path, scope, true)
189
+ } catch let error as NSError {
190
+ reject(error.domain, error.userInfo["message"] as? String, error)
191
+ return
192
+ }
193
+
194
+ if (!fileUrl!.hasDirectoryPath) {
195
+ reject("ERR_PATH_IS_FILE", "Path \(path) is a file", nil)
196
+ return
197
+ }
198
+
199
+ if (!recursive) {
200
+ // check if directory is empty
201
+ let fileManager = FileManager.default
202
+ do {
203
+ print(fileUrl!.path)
204
+ let files = try fileManager.contentsOfDirectory(atPath: fileUrl!.path)
205
+ print(files)
206
+ if (files.count > 0) {
207
+ reject("ERR_DIRECTORY_NOT_EMPTY", "Directory \(path) is not empty", nil)
208
+ return
209
+ }
210
+ } catch {
211
+ reject("ERR_UNKNOWN", "Error reading directory \(path)", error)
212
+ return
213
+ }
214
+ }
215
+
216
+ let fileManager = FileManager.default
217
+ do {
218
+ try fileManager.removeItem(at: fileUrl!)
219
+ resolve(true)
220
+ } catch {
221
+ reject("ERR_DELETE_ERROR", "Error deleting directory \(path)", error)
86
222
  }
87
223
  }
88
224
 
89
225
  @objc(statFile:withScope:withResolver:withRejecter:)
90
- func statFile(path: String, scope: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
91
- withPromise(resolve: resolve, reject: reject) {
92
- let fileUrl = try CloudKitUtils.getFileURL(path: path, scope: scope)
93
- return try FileUtils.statFile(fileUrl: fileUrl).toDictionary()
226
+ func statFile(path: String, scope: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
227
+ let fileUrl: URL?
228
+ do {
229
+ fileUrl = try getFileURL(path, scope, true)
230
+ } catch let error as NSError {
231
+ reject(error.domain, error.userInfo["message"] as? String, error)
232
+ return
233
+ }
234
+
235
+ let fileManager = FileManager.default
236
+ do {
237
+ let attributes = try fileManager.attributesOfItem(atPath: fileUrl!.path)
238
+ let size = attributes[FileAttributeKey.size] as! UInt64
239
+ let birthtime = attributes[FileAttributeKey.creationDate] as! Date
240
+ let mtime = attributes[FileAttributeKey.modificationDate] as! Date
241
+ let isDirectory = attributes[FileAttributeKey.type] as! FileAttributeType == FileAttributeType.typeDirectory
242
+ let isFile = attributes[FileAttributeKey.type] as! FileAttributeType == FileAttributeType.typeRegular
243
+ let result = [
244
+ "size": size,
245
+ "birthtimeMs": birthtime.timeIntervalSince1970 * 1000,
246
+ "mtimeMs": mtime.timeIntervalSince1970 * 1000,
247
+ "isDirectory": isDirectory,
248
+ "isFile": isFile
249
+ ] as [String : Any]
250
+ resolve(result)
251
+ } catch {
252
+ reject("ERR_STAT_ERROR", "Error getting stats for file \(path)", error)
94
253
  }
95
254
  }
96
255
 
97
256
  @objc(isCloudAvailable:withRejecter:)
98
- func isCloudAvailable(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
99
- withPromise(resolve: resolve, reject: reject) {
100
- CloudKitUtils.isCloudKitAvailable()
257
+ func isCloudAvailable(resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
258
+ let token = FileManager.default.ubiquityIdentityToken
259
+ resolve(token != nil)
260
+ }
261
+
262
+ /**
263
+ Returns the iCloud directory URL for the given scope.
264
+
265
+ - Parameter scope: The scope of the directory. Can be either "documents" or "app_data".
266
+ - Returns: The URL of the iCloud directory.
267
+ */
268
+ private func getDirectory(_ scope: String) -> URL? {
269
+ let fileManager = FileManager.default
270
+ let isDocumentDirectory = scope.caseInsensitiveCompare("documents") == .orderedSame
271
+ let ubiquityURL = fileManager.url(forUbiquityContainerIdentifier: nil)
272
+ print(ubiquityURL)
273
+ if (isDocumentDirectory) {
274
+ return fileManager.urls(for: .documentDirectory, in: .userDomainMask).first
275
+ } else {
276
+ return ubiquityURL
277
+ }
278
+ }
279
+
280
+ /**
281
+ Parses a given path and directory scope to a full file URL. Does not check if the file exists.
282
+
283
+ - Parameter path: The path of the file.
284
+ - Parameter scope: The scope of the directory. Can be either "documents" or "app_data".
285
+ - Parameter shouldExist: Whether the file should exist. If true, throws an error if the file does not exist. If false, throws an error if the file exists. If nil, does not check if the file exists.
286
+ - Returns: The full URL of the file.
287
+ - Throws: An NSError if the scope directory couldn't be found or the file should exist but doesn't or vice versa.
288
+ */
289
+ private func getFileURL(_ path: String, _ scope: String, _ shouldExist: Bool? = nil) throws -> URL? {
290
+ let fileManager = FileManager.default
291
+
292
+ guard let directory = getDirectory(scope) else {
293
+ throw NSError(domain: "ERR_DIRECTORY_NOT_FOUND", code: 0, userInfo: ["message": "Directory for scope \(scope) not found"])
101
294
  }
295
+
296
+ // remove leading slashes
297
+ let path = path.replacingOccurrences(of: "^/+", with: "", options: .regularExpression)
298
+
299
+ // append path to scope directory and return URL
300
+ let filePath = directory.appendingPathComponent(path)
301
+
302
+ if (shouldExist != nil) {
303
+ let fileExists = fileManager.fileExists(atPath: filePath.path)
304
+ if (shouldExist! && !fileExists) {
305
+ throw NSError(domain: "ERR_FILE_NOT_FOUND", code: 0, userInfo: ["message": "File or directory \(path) not found"])
306
+ } else if (!shouldExist! && fileExists) {
307
+ throw NSError(domain: "ERR_FILE_EXISTS", code: 0, userInfo: ["message": "File or directory \(path) already exists"])
308
+ }
309
+ }
310
+
311
+ return filePath
102
312
  }
103
313
  }
@@ -8,11 +8,6 @@
8
8
 
9
9
  /* Begin PBXBuildFile section */
10
10
  50ADE3732B56EE1300DB5583 /* CloudStorageEventEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5009AB9B2B56ECD30058E83A /* CloudStorageEventEmitter.swift */; };
11
- 50BC353B2CA6ED940085E8B9 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BC353A2CA6ED940085E8B9 /* FileUtils.swift */; };
12
- 50BC353F2CA6EF760085E8B9 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BC353E2CA6EF760085E8B9 /* Types.swift */; };
13
- 50BC35412CA6F0E80085E8B9 /* CloudKitUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BC35402CA6F0E80085E8B9 /* CloudKitUtils.swift */; };
14
- 50BC35452CA6FA6D0085E8B9 /* CloudStorageError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BC35442CA6FA6D0085E8B9 /* CloudStorageError.swift */; };
15
- 50BC35472CA6FF3F0085E8B9 /* Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BC35462CA6FF3F0085E8B9 /* Promise.swift */; };
16
11
  F4FF95D7245B92E800C19C63 /* CloudStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* CloudStorage.swift */; };
17
12
  /* End PBXBuildFile section */
18
13
 
@@ -32,11 +27,6 @@
32
27
  134814201AA4EA6300B7C361 /* libCloudStorage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCloudStorage.a; sourceTree = BUILT_PRODUCTS_DIR; };
33
28
  5009AB9B2B56ECD30058E83A /* CloudStorageEventEmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudStorageEventEmitter.swift; sourceTree = "<group>"; };
34
29
  50ADE3712B56EDFB00DB5583 /* CloudStorageEventEmitter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CloudStorageEventEmitter.m; sourceTree = "<group>"; };
35
- 50BC353A2CA6ED940085E8B9 /* FileUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
36
- 50BC353E2CA6EF760085E8B9 /* Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = "<group>"; };
37
- 50BC35402CA6F0E80085E8B9 /* CloudKitUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudKitUtils.swift; sourceTree = "<group>"; };
38
- 50BC35442CA6FA6D0085E8B9 /* CloudStorageError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudStorageError.swift; sourceTree = "<group>"; };
39
- 50BC35462CA6FF3F0085E8B9 /* Promise.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Promise.swift; sourceTree = "<group>"; };
40
30
  B3E7B5891CC2AC0600A0062D /* CloudStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CloudStorage.m; sourceTree = "<group>"; };
41
31
  F4FF95D5245B92E700C19C63 /* CloudStorage-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CloudStorage-Bridging-Header.h"; sourceTree = "<group>"; };
42
32
  F4FF95D6245B92E800C19C63 /* CloudStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudStorage.swift; sourceTree = "<group>"; };
@@ -61,22 +51,9 @@
61
51
  name = Products;
62
52
  sourceTree = "<group>";
63
53
  };
64
- 50BC35482CA704A60085E8B9 /* Utils */ = {
65
- isa = PBXGroup;
66
- children = (
67
- 50BC35402CA6F0E80085E8B9 /* CloudKitUtils.swift */,
68
- 50BC35442CA6FA6D0085E8B9 /* CloudStorageError.swift */,
69
- 50BC353A2CA6ED940085E8B9 /* FileUtils.swift */,
70
- 50BC35462CA6FF3F0085E8B9 /* Promise.swift */,
71
- 50BC353E2CA6EF760085E8B9 /* Types.swift */,
72
- );
73
- path = Utils;
74
- sourceTree = "<group>";
75
- };
76
54
  58B511D21A9E6C8500147676 = {
77
55
  isa = PBXGroup;
78
56
  children = (
79
- 50BC35482CA704A60085E8B9 /* Utils */,
80
57
  50ADE3712B56EDFB00DB5583 /* CloudStorageEventEmitter.m */,
81
58
  5009AB9B2B56ECD30058E83A /* CloudStorageEventEmitter.swift */,
82
59
  F4FF95D6245B92E800C19C63 /* CloudStorage.swift */,
@@ -143,13 +120,8 @@
143
120
  isa = PBXSourcesBuildPhase;
144
121
  buildActionMask = 2147483647;
145
122
  files = (
146
- 50BC353B2CA6ED940085E8B9 /* FileUtils.swift in Sources */,
147
- 50BC35412CA6F0E80085E8B9 /* CloudKitUtils.swift in Sources */,
148
- 50BC35472CA6FF3F0085E8B9 /* Promise.swift in Sources */,
149
- 50BC35452CA6FA6D0085E8B9 /* CloudStorageError.swift in Sources */,
150
123
  F4FF95D7245B92E800C19C63 /* CloudStorage.swift in Sources */,
151
124
  50ADE3732B56EE1300DB5583 /* CloudStorageEventEmitter.swift in Sources */,
152
- 50BC353F2CA6EF760085E8B9 /* Types.swift in Sources */,
153
125
  );
154
126
  runOnlyForDeploymentPostprocessing = 0;
155
127
  };
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Workspace
3
+ version = "1.0">
4
+ </Workspace>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>IDEDidComputeMac32BitWarning</key>
6
+ <true/>
7
+ </dict>
8
+ </plist>
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>CloudStorage.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ <key>SuppressBuildableAutocreation</key>
14
+ <dict>
15
+ <key>58B511DA1A9E6C8500147676</key>
16
+ <dict>
17
+ <key>primary</key>
18
+ <true/>
19
+ </dict>
20
+ </dict>
21
+ </dict>
22
+ </plist>
@@ -10,7 +10,7 @@ class CloudStorageEventEmitter: RCTEventEmitter {
10
10
  }
11
11
 
12
12
  override func supportedEvents() -> [String]! {
13
- ["RNCloudStorage.cloud.availability-changed"]
13
+ return ["RNCloudStorage.cloud.availability-changed"]
14
14
  }
15
15
 
16
16
  override func startObserving() {
@@ -23,8 +23,8 @@ class CloudStorageEventEmitter: RCTEventEmitter {
23
23
  NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NSUbiquityIdentityDidChange, object: nil)
24
24
  }
25
25
 
26
- @objc func iCloudIdentityChanged(_: Notification? = nil) {
27
- let isAvailable = CloudKitUtils.isCloudKitAvailable()
28
- CloudStorageEventEmitter.shared.sendEvent(withName: "RNCloudStorage.cloud.availability-changed", body: ["available": isAvailable])
26
+ @objc func iCloudIdentityChanged(_ notification: Notification? = nil) {
27
+ let token = FileManager.default.ubiquityIdentityToken
28
+ CloudStorageEventEmitter.shared.sendEvent(withName: "RNCloudStorage.cloud.availability-changed", body: ["available": token != nil])
29
29
  }
30
30
  }