expo-file-system 16.0.4 β 16.0.6
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/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,18 @@
|
|
|
10
10
|
|
|
11
11
|
### π‘ Others
|
|
12
12
|
|
|
13
|
+
## 16.0.6 β 2024-02-06
|
|
14
|
+
|
|
15
|
+
### π Bug fixes
|
|
16
|
+
|
|
17
|
+
- On `iOS`, fix upload task requests. ([#26880](https://github.com/expo/expo/pull/26880) by [@alanjhughes](https://github.com/alanjhughes))
|
|
18
|
+
|
|
19
|
+
## 16.0.5 β 2024-01-23
|
|
20
|
+
|
|
21
|
+
### π Bug fixes
|
|
22
|
+
|
|
23
|
+
- On `iOS`, set `httpMethod` on upload requests. ([#26516](https://github.com/expo/expo/pull/26516) by [@alanjhughes](https://github.com/alanjhughes))
|
|
24
|
+
|
|
13
25
|
## 16.0.4 β 2024-01-18
|
|
14
26
|
|
|
15
27
|
_This version does not introduce any user-facing changes._
|
package/android/build.gradle
CHANGED
|
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
|
|
|
3
3
|
apply plugin: 'maven-publish'
|
|
4
4
|
|
|
5
5
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '16.0.
|
|
6
|
+
version = '16.0.6'
|
|
7
7
|
|
|
8
8
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
9
9
|
if (expoModulesCorePlugin.exists()) {
|
|
@@ -94,7 +94,7 @@ android {
|
|
|
94
94
|
namespace "expo.modules.filesystem"
|
|
95
95
|
defaultConfig {
|
|
96
96
|
versionCode 30
|
|
97
|
-
versionName "16.0.
|
|
97
|
+
versionName "16.0.6"
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -67,3 +67,15 @@ final class CannotDetermineDiskCapacity: Exception {
|
|
|
67
67
|
"Unable to determine free disk storage capacity"
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
final class FailedToCreateBodyException: Exception {
|
|
72
|
+
override var reason: String {
|
|
73
|
+
"Unable to create multipart body"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
final class FailedToAccessDirectoryException: Exception {
|
|
78
|
+
override var reason: String {
|
|
79
|
+
"Failed to access `Caches` directory"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -156,7 +156,7 @@ public final class FileSystemModule: Module {
|
|
|
156
156
|
throw FileNotExistsException(localUrl.path)
|
|
157
157
|
}
|
|
158
158
|
let session = options.sessionType == .background ? backgroundSession : foregroundSession
|
|
159
|
-
let task = createUploadTask(session: session, targetUrl: targetUrl, sourceUrl: localUrl, options: options)
|
|
159
|
+
let task = try createUploadTask(session: session, targetUrl: targetUrl, sourceUrl: localUrl, options: options)
|
|
160
160
|
let taskDelegate = EXSessionUploadTaskDelegate(resolve: promise.resolver, reject: promise.legacyRejecter)
|
|
161
161
|
|
|
162
162
|
sessionTaskDispatcher.register(taskDelegate, for: task)
|
|
@@ -165,7 +165,7 @@ public final class FileSystemModule: Module {
|
|
|
165
165
|
|
|
166
166
|
AsyncFunction("uploadTaskStartAsync") { (targetUrl: URL, localUrl: URL, uuid: String, options: UploadOptions, promise: Promise) in
|
|
167
167
|
let session = options.sessionType == .background ? backgroundSession : foregroundSession
|
|
168
|
-
let task = createUploadTask(session: session, targetUrl: targetUrl, sourceUrl: localUrl, options: options)
|
|
168
|
+
let task = try createUploadTask(session: session, targetUrl: targetUrl, sourceUrl: localUrl, options: options)
|
|
169
169
|
let onSend: EXUploadDelegateOnSendCallback = { [weak self] _, _, totalBytesSent, totalBytesExpectedToSend in
|
|
170
170
|
self?.sendEvent(EVENT_UPLOAD_PROGRESS, [
|
|
171
171
|
"uuid": uuid,
|
|
@@ -30,55 +30,69 @@ func createUrlRequest(url: URL, headers: [String: String]?) -> URLRequest {
|
|
|
30
30
|
return request
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
func createUploadTask(session: URLSession, targetUrl: URL, sourceUrl: URL, options: UploadOptions) -> URLSessionUploadTask {
|
|
33
|
+
func createUploadTask(session: URLSession, targetUrl: URL, sourceUrl: URL, options: UploadOptions) throws -> URLSessionUploadTask {
|
|
34
34
|
var request = createUrlRequest(url: targetUrl, headers: options.headers)
|
|
35
|
+
request.httpMethod = options.httpMethod.rawValue
|
|
35
36
|
|
|
36
37
|
switch options.uploadType {
|
|
37
38
|
case .binaryContent:
|
|
38
39
|
return session.uploadTask(with: request, fromFile: sourceUrl)
|
|
39
40
|
case .multipart:
|
|
40
41
|
let boundaryString = UUID().uuidString
|
|
41
|
-
let data =
|
|
42
|
+
guard let data = createMultipartBody(boundary: boundaryString, sourceUrl: sourceUrl, options: options) else {
|
|
43
|
+
throw FailedToCreateBodyException()
|
|
44
|
+
}
|
|
42
45
|
|
|
43
46
|
request.setValue("multipart/form-data; boundary=\(boundaryString)", forHTTPHeaderField: "Content-Type")
|
|
44
|
-
request.httpBody = data
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
let localURL = try createLocalUrl(from: sourceUrl)
|
|
49
|
+
try? data.write(to: localURL)
|
|
50
|
+
|
|
51
|
+
return session.uploadTask(with: request, fromFile: localURL)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func createLocalUrl(from sourceUrl: URL) throws -> URL {
|
|
56
|
+
guard let cachesDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
|
|
57
|
+
throw FailedToAccessDirectoryException()
|
|
47
58
|
}
|
|
59
|
+
let tempDir = cachesDir.appendingPathComponent("uploads")
|
|
60
|
+
FileSystemUtilities.ensureDirExists(at: tempDir)
|
|
61
|
+
return tempDir.appendingPathComponent(sourceUrl.lastPathComponent)
|
|
48
62
|
}
|
|
49
63
|
|
|
50
|
-
func createMultipartBody(boundary: String, sourceUrl: URL, options: UploadOptions)
|
|
51
|
-
let
|
|
52
|
-
|
|
53
|
-
let
|
|
64
|
+
func createMultipartBody(boundary: String, sourceUrl: URL, options: UploadOptions) -> Data? {
|
|
65
|
+
let fieldName = options.fieldName ?? sourceUrl.lastPathComponent
|
|
66
|
+
var mimeType = options.mimeType ?? findMimeType(forAttachment: sourceUrl)
|
|
67
|
+
guard let data = try? Data(contentsOf: sourceUrl) else {
|
|
68
|
+
return nil
|
|
69
|
+
}
|
|
54
70
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
--\(boundary)
|
|
58
|
-
Content-Disposition: form-data; name="\(fileName)"; filename="\(sourceUrl.lastPathComponent)"
|
|
59
|
-
Content-Type: \(mimeType)
|
|
71
|
+
var body = Data()
|
|
72
|
+
headersForMultipartParams(options.parameters, boundary: boundary, body: &body)
|
|
60
73
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
""
|
|
74
|
+
body.append("--\(boundary)\r\n".data)
|
|
75
|
+
body.append("Content-Disposition: form-data; name=\"\(fieldName)\"; filename=\"\(sourceUrl.lastPathComponent)\"\r\n".data)
|
|
76
|
+
body.append("Content-Type: \(mimeType)\r\n\r\n".data)
|
|
77
|
+
body.append(data)
|
|
78
|
+
body.append("\r\n".data)
|
|
79
|
+
body.append("--\(boundary)--\r\n".data)
|
|
64
80
|
|
|
65
|
-
|
|
66
|
-
throw HeaderEncodingFailedException(sourceUrl.absoluteString)
|
|
67
|
-
}
|
|
68
|
-
return bodyData
|
|
81
|
+
return body
|
|
69
82
|
}
|
|
70
83
|
|
|
71
|
-
func headersForMultipartParams(_ params: [String: String]?, boundary: String
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
func headersForMultipartParams(_ params: [String: String]?, boundary: String, body: inout Data) {
|
|
85
|
+
if let params {
|
|
86
|
+
for (key, value) in params {
|
|
87
|
+
body.append("--\(boundary)\r\n".data)
|
|
88
|
+
body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data)
|
|
89
|
+
body.append("\(value)\r\n".data)
|
|
90
|
+
}
|
|
74
91
|
}
|
|
75
|
-
|
|
76
|
-
"""
|
|
77
|
-
--\(boundary)
|
|
78
|
-
Content-Disposition: form-data; name="\(key)"
|
|
92
|
+
}
|
|
79
93
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.
|
|
94
|
+
// All swift strings are unicode correct.
|
|
95
|
+
// This avoids the optional created by string.data(using: .utf8)
|
|
96
|
+
private extension String {
|
|
97
|
+
var data: Data { Data(self.utf8) }
|
|
84
98
|
}
|
|
@@ -20,7 +20,7 @@ class EXFileSystemSpec: ExpoSpec {
|
|
|
20
20
|
it("should handle UTF-8 characters") {
|
|
21
21
|
let utf8UriInput = "file:///var/mobile/δΈζ"
|
|
22
22
|
let utf8UriExpectedOutput = "file:///var/mobile/%E4%B8%AD%E6%96%87"
|
|
23
|
-
let utf8Uri = fileSystem.percentEncodedURL(fromURIString:utf8UriInput)
|
|
23
|
+
let utf8Uri = fileSystem.percentEncodedURL(fromURIString: utf8UriInput)
|
|
24
24
|
|
|
25
25
|
expect(utf8Uri?.absoluteString) == utf8UriExpectedOutput
|
|
26
26
|
expect(utf8Uri?.scheme) == "file"
|
|
@@ -29,7 +29,7 @@ class EXFileSystemSpec: ExpoSpec {
|
|
|
29
29
|
it("should handle URI with percent, numbers and UTF-8 characters") {
|
|
30
30
|
let input = "file:///document/directory/%40%2FδΈζ"
|
|
31
31
|
let expectedOutput = "file:///document/directory/%40%2F%E4%B8%AD%E6%96%87"
|
|
32
|
-
let uri = fileSystem.percentEncodedURL(fromURIString:input)
|
|
32
|
+
let uri = fileSystem.percentEncodedURL(fromURIString: input)
|
|
33
33
|
|
|
34
34
|
expect(uri?.absoluteString) == expectedOutput
|
|
35
35
|
}
|
|
@@ -37,7 +37,7 @@ class EXFileSystemSpec: ExpoSpec {
|
|
|
37
37
|
it("should not decode percentages in URI") {
|
|
38
38
|
let input = "file:///document/hello%2Fworld.txt"
|
|
39
39
|
let unexpectedOutput = "file:///document/hello/world.txt"
|
|
40
|
-
let uri = fileSystem.percentEncodedURL(fromURIString:input)
|
|
40
|
+
let uri = fileSystem.percentEncodedURL(fromURIString: input)
|
|
41
41
|
|
|
42
42
|
// Should not create a directory named "hello"
|
|
43
43
|
expect(uri?.absoluteString) != unexpectedOutput
|
|
@@ -45,7 +45,7 @@ class EXFileSystemSpec: ExpoSpec {
|
|
|
45
45
|
|
|
46
46
|
it("should handle assets-library URIs") {
|
|
47
47
|
let assetsLibraryUriInput = "assets-library://asset/asset.JPG?id=3C1D9C54-9521-488F-BB27-AA1EA0F8AF04/L0/001&ext=JPG"
|
|
48
|
-
let assetsLibraryUri = fileSystem.percentEncodedURL(fromURIString:assetsLibraryUriInput)
|
|
48
|
+
let assetsLibraryUri = fileSystem.percentEncodedURL(fromURIString: assetsLibraryUriInput)
|
|
49
49
|
|
|
50
50
|
expect(assetsLibraryUri?.absoluteString) == assetsLibraryUriInput
|
|
51
51
|
expect(assetsLibraryUri?.scheme) == "assets-library"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-file-system",
|
|
3
|
-
"version": "16.0.
|
|
3
|
+
"version": "16.0.6",
|
|
4
4
|
"description": "Provides access to the local file system on the device.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -41,5 +41,5 @@
|
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"expo": "*"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "4f3dcf3e23eae997f884117fdd34ad734efad9fd"
|
|
45
45
|
}
|