@amazon-devices/expo-file-system 2.0.1758683737

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 (111) hide show
  1. package/.eslintrc.js +2 -0
  2. package/CHANGELOG.md +317 -0
  3. package/CMakeLists.txt +52 -0
  4. package/LICENSE +7 -0
  5. package/README.kepler.md +260 -0
  6. package/README.md +46 -0
  7. package/THIRD_PARTY_NOTICES.txt +24 -0
  8. package/android/build.gradle +118 -0
  9. package/android/src/main/AndroidManifest.xml +17 -0
  10. package/android/src/main/java/expo/modules/filesystem/AppDirectoriesModule.kt +26 -0
  11. package/android/src/main/java/expo/modules/filesystem/CountingRequestBody.kt +52 -0
  12. package/android/src/main/java/expo/modules/filesystem/FilePermissionModule.kt +48 -0
  13. package/android/src/main/java/expo/modules/filesystem/FileSystemExceptions.kt +48 -0
  14. package/android/src/main/java/expo/modules/filesystem/FileSystemFileProvider.kt +5 -0
  15. package/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt +1110 -0
  16. package/android/src/main/java/expo/modules/filesystem/FileSystemPackage.kt +10 -0
  17. package/android/src/main/java/expo/modules/filesystem/FileSystemRecords.kt +92 -0
  18. package/android/src/main/res/xml/file_system_provider_paths.xml +5 -0
  19. package/app.plugin.js +1 -0
  20. package/build/ExponentFileSystem.d.ts +4 -0
  21. package/build/ExponentFileSystem.d.ts.map +1 -0
  22. package/build/ExponentFileSystem.js +5 -0
  23. package/build/ExponentFileSystem.js.map +1 -0
  24. package/build/ExponentFileSystem.kepler.d.ts +4 -0
  25. package/build/ExponentFileSystem.kepler.d.ts.map +1 -0
  26. package/build/ExponentFileSystem.kepler.js +112 -0
  27. package/build/ExponentFileSystem.kepler.js.map +1 -0
  28. package/build/ExponentFileSystem.web.d.ts +3 -0
  29. package/build/ExponentFileSystem.web.d.ts.map +1 -0
  30. package/build/ExponentFileSystem.web.js +3 -0
  31. package/build/ExponentFileSystem.web.js.map +1 -0
  32. package/build/ExponentFileSystemShim.d.ts +4 -0
  33. package/build/ExponentFileSystemShim.d.ts.map +1 -0
  34. package/build/ExponentFileSystemShim.js +21 -0
  35. package/build/ExponentFileSystemShim.js.map +1 -0
  36. package/build/FileSystem.d.ts +361 -0
  37. package/build/FileSystem.d.ts.map +1 -0
  38. package/build/FileSystem.js +616 -0
  39. package/build/FileSystem.js.map +1 -0
  40. package/build/FileSystem.types.d.ts +304 -0
  41. package/build/FileSystem.types.d.ts.map +1 -0
  42. package/build/FileSystem.types.js +47 -0
  43. package/build/FileSystem.types.js.map +1 -0
  44. package/build/index.d.ts +3 -0
  45. package/build/index.d.ts.map +1 -0
  46. package/build/index.js +3 -0
  47. package/build/index.js.map +1 -0
  48. package/build/types.d.ts +35 -0
  49. package/build/types.d.ts.map +1 -0
  50. package/build/types.js +2 -0
  51. package/build/types.js.map +1 -0
  52. package/expo-module.config.json +11 -0
  53. package/ios/EXFilePermissionModule.h +16 -0
  54. package/ios/EXFilePermissionModule.m +68 -0
  55. package/ios/EXFileSystem.h +25 -0
  56. package/ios/EXFileSystem.m +1084 -0
  57. package/ios/EXFileSystemAssetLibraryHandler.h +6 -0
  58. package/ios/EXFileSystemAssetLibraryHandler.m +142 -0
  59. package/ios/EXFileSystemHandler.h +17 -0
  60. package/ios/EXFileSystemLocalFileHandler.h +7 -0
  61. package/ios/EXFileSystemLocalFileHandler.m +79 -0
  62. package/ios/EXSessionTasks/EXSessionCancelableUploadTaskDelegate.h +16 -0
  63. package/ios/EXSessionTasks/EXSessionCancelableUploadTaskDelegate.m +55 -0
  64. package/ios/EXSessionTasks/EXSessionDownloadTaskDelegate.h +13 -0
  65. package/ios/EXSessionTasks/EXSessionDownloadTaskDelegate.m +64 -0
  66. package/ios/EXSessionTasks/EXSessionHandler.h +19 -0
  67. package/ios/EXSessionTasks/EXSessionHandler.m +49 -0
  68. package/ios/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.h +18 -0
  69. package/ios/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.m +66 -0
  70. package/ios/EXSessionTasks/EXSessionTaskDelegate.h +32 -0
  71. package/ios/EXSessionTasks/EXSessionTaskDelegate.m +58 -0
  72. package/ios/EXSessionTasks/EXSessionTaskDispatcher.h +19 -0
  73. package/ios/EXSessionTasks/EXSessionTaskDispatcher.m +96 -0
  74. package/ios/EXSessionTasks/EXSessionUploadTaskDelegate.h +8 -0
  75. package/ios/EXSessionTasks/EXSessionUploadTaskDelegate.m +52 -0
  76. package/ios/EXSessionTasks/EXTaskHandlersManager.h +21 -0
  77. package/ios/EXSessionTasks/EXTaskHandlersManager.m +56 -0
  78. package/ios/Encoding.swift +88 -0
  79. package/ios/ExpoFileSystem.h +1 -0
  80. package/ios/ExpoFileSystem.podspec +32 -0
  81. package/ios/FileSystemBackgroundSessionHandler.swift +25 -0
  82. package/ios/FileSystemExceptions.swift +69 -0
  83. package/ios/FileSystemHelpers.swift +66 -0
  84. package/ios/FileSystemModule.swift +263 -0
  85. package/ios/FileSystemRecords.swift +74 -0
  86. package/ios/NSData+EXFileSystem.h +9 -0
  87. package/ios/NSData+EXFileSystem.m +19 -0
  88. package/ios/NetworkingHelpers.swift +84 -0
  89. package/ios/Tests/EXFileSystemSpec.swift +55 -0
  90. package/jest.config.js +3 -0
  91. package/kepler/ExponentFileSystem.cpp +498 -0
  92. package/kepler/ExponentFileSystem.h +60 -0
  93. package/kepler/KeplerInit.cpp +28 -0
  94. package/kepler/NetworkingRequestHandler.cpp +47 -0
  95. package/kepler/test/FileSystem.cpp +425 -0
  96. package/package.json +1 -0
  97. package/plugin/build/withFileSystem.d.ts +3 -0
  98. package/plugin/build/withFileSystem.js +12 -0
  99. package/plugin/src/withFileSystem.ts +13 -0
  100. package/plugin/tsconfig.json +9 -0
  101. package/plugin/tsconfig.tsbuildinfo +1 -0
  102. package/react-native.config.js +21 -0
  103. package/src/ExponentFileSystem.kepler.ts +167 -0
  104. package/src/ExponentFileSystem.ts +7 -0
  105. package/src/ExponentFileSystem.web.ts +2 -0
  106. package/src/ExponentFileSystemShim.ts +23 -0
  107. package/src/FileSystem.ts +756 -0
  108. package/src/FileSystem.types.ts +339 -0
  109. package/src/index.ts +2 -0
  110. package/src/types.ts +34 -0
  111. package/tsconfig.json +9 -0
@@ -0,0 +1,425 @@
1
+ /*
2
+ * Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ *
4
+ * PROPRIETARY/CONFIDENTIAL
5
+ *
6
+ * Use is subject to license terms.
7
+ */
8
+
9
+ #include <KeplerScript/utils/KeplerUIManager.h>
10
+ #include <gmock/gmock-actions.h>
11
+ #include <gmock/gmock.h>
12
+ #include <gtest/gtest.h>
13
+
14
+ #include <iostream>
15
+
16
+ #include "../ExponentFileSystem.h"
17
+ #include "JSObjectsConversion.h"
18
+ #include "catch.hpp"
19
+
20
+ namespace {
21
+ void handlePromiseRejection(volta::react::NativeJSObject payload) {
22
+ std::string rejectionMessage = std::get<std::string>(payload["message"]);
23
+ FAIL(rejectionMessage);
24
+ }
25
+ } // namespace
26
+
27
+ SCENARIO("Testing Expo FileSystem module") {
28
+ ExponentFileSystem fileSystemModule;
29
+
30
+ WHEN("documentDirectory method is called") {
31
+ auto documentDirectory = fileSystemModule.documentDirectory();
32
+
33
+ THEN("Proper value is returned") {
34
+ REQUIRE(documentDirectory == "/data");
35
+ }
36
+ }
37
+
38
+ WHEN("cacheDirectory method is called") {
39
+ auto cacheDirectory = fileSystemModule.cacheDirectory();
40
+
41
+ THEN("Proper value is returned") {
42
+ REQUIRE(cacheDirectory == "/cache");
43
+ }
44
+ }
45
+
46
+ WHEN("bundleDirectory method is called") {
47
+ auto bundleDirectory = fileSystemModule.bundleDirectory();
48
+
49
+ THEN("Proper value is returned") {
50
+ REQUIRE(bundleDirectory == "");
51
+ }
52
+ }
53
+
54
+ // Unable to test due to lack of 'Promise' support
55
+ // WHEN("getInfoAsync is called for a nonexisting file") {
56
+ // auto promise = fileSystemModule.getInfoAsync("/data/nonExistingFile.txt", {});
57
+
58
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
59
+ // volta::react::Callback([](auto args) {
60
+ // THEN("Resolved promise contains appropriate file info for non existing file") {
61
+ // REQUIRE(args.size() == 1);
62
+ // REQUIRE(std::holds_alternative<volta::react::NativeJSObject>(args[0]));
63
+
64
+ // volta::react::NativeJSObject fileInfo = std::get<volta::react::NativeJSObject>(args[0]);
65
+
66
+ // REQUIRE(std::holds_alternative<bool>(fileInfo["exists"]));
67
+ // REQUIRE(std::holds_alternative<bool>(fileInfo["isDirectory"]));
68
+
69
+ // REQUIRE_FALSE(std::get<bool>(fileInfo["exists"]));
70
+ // REQUIRE_FALSE(std::get<bool>(fileInfo["isDirectory"]));
71
+ // }
72
+ // }),
73
+ // volta::react::Callback([](auto args) {
74
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
75
+ // std::get<utils::json::JsonContainer>(args[0]));
76
+ // handlePromiseRejection(payload);
77
+ // })));
78
+ // }
79
+
80
+ // Unable to test due to lack of 'Promise' support
81
+ // WHEN("getInfoAsync is called for an existing file") {
82
+ // auto promise =
83
+ // fileSystemModule.getInfoAsync("/data/expo-unit-tests", volta::react::NativeJSObject{{"size",
84
+ // true}});
85
+
86
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
87
+ // volta::react::Callback([](auto args) {
88
+ // THEN("Resolved promise contains appropriate file info for existing file") {
89
+ // REQUIRE(args.size() == 1);
90
+ // REQUIRE(std::holds_alternative<volta::react::NativeJSObject>(args[0]));
91
+
92
+ // volta::react::NativeJSObject fileInfo = std::get<volta::react::NativeJSObject>(args[0]);
93
+
94
+ // REQUIRE(std::holds_alternative<bool>(fileInfo["exists"]));
95
+ // REQUIRE(std::holds_alternative<bool>(fileInfo["isDirectory"]));
96
+ // REQUIRE(std::holds_alternative<std::string>(fileInfo["size"]));
97
+ // REQUIRE(std::holds_alternative<std::string>(fileInfo["modification"]));
98
+
99
+ // REQUIRE(std::get<bool>(fileInfo["exists"]));
100
+ // REQUIRE_FALSE(std::get<bool>(fileInfo["isDirectory"]));
101
+ // REQUIRE(std::get<std::string>(fileInfo["size"]) > "1024");
102
+ // REQUIRE(std::get<std::string>(fileInfo["modification"]) > "1718788070");
103
+ // }
104
+ // }),
105
+ // volta::react::Callback([](auto args) {
106
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
107
+ // std::get<utils::json::JsonContainer>(args[0]));
108
+ // handlePromiseRejection(payload);
109
+ // })));
110
+ // }
111
+
112
+ // Unable to test due to lack of 'Promise' support
113
+ // WHEN("getContentUriAsync is called") {
114
+ // auto promise = fileSystemModule.getContentUriAsync("expo-unit-tests");
115
+
116
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
117
+ // volta::react::Callback([](auto args) {
118
+ // THEN("Resolved promise contains formatted URI") {
119
+ // REQUIRE(args.size() == 1);
120
+ // REQUIRE(std::holds_alternative<std::string>(args[0]));
121
+
122
+ // REQUIRE(std::get<std::string>(args[0]) == "/data/expo-unit-tests");
123
+ // }
124
+ // }),
125
+ // volta::react::Callback([](auto args) {
126
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
127
+ // std::get<utils::json::JsonContainer>(args[0]));
128
+ // handlePromiseRejection(payload);
129
+ // })));
130
+ // }
131
+
132
+ // Unable to test due to lack of 'Promise' support
133
+ // WHEN("writeAsStringAsync is called") {
134
+ // auto promise = fileSystemModule.writeAsStringAsync("/data/hello-world.txt", "Hello world!", {});
135
+
136
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
137
+ // volta::react::Callback([](auto args) {
138
+ // THEN("Promise is resolved on success") {
139
+ // REQUIRE(args.size() == 0);
140
+ // }
141
+ // }),
142
+ // volta::react::Callback([](auto args) {
143
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
144
+ // std::get<utils::json::JsonContainer>(args[0]));
145
+ // handlePromiseRejection(payload);
146
+ // })));
147
+ // }
148
+
149
+ // Unable to test due to lack of 'Promise' support
150
+ // WHEN("readAsStringAsync is called") {
151
+ // auto promise = fileSystemModule.readAsStringAsync("/data/hello-world.txt", {});
152
+
153
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
154
+ // volta::react::Callback([](auto args) {
155
+ // THEN("Resolved promise contains file content") {
156
+ // REQUIRE(args.size() == 1);
157
+ // REQUIRE(std::holds_alternative<std::string>(args[0]));
158
+
159
+ // REQUIRE(std::get<std::string>(args[0]) == "Hello world!");
160
+ // }
161
+ // }),
162
+ // volta::react::Callback([](auto args) {
163
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
164
+ // std::get<utils::json::JsonContainer>(args[0]));
165
+ // handlePromiseRejection(payload);
166
+ // })));
167
+ // }
168
+
169
+ // Unable to test due to lack of 'Promise' support
170
+ // WHEN("makeDirectoryAsync is called") {
171
+ // auto promise = fileSystemModule.makeDirectoryAsync("/data/hello", {});
172
+
173
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
174
+ // volta::react::Callback([](auto args) {
175
+ // THEN("Promise is resolved on success") {
176
+ // REQUIRE(args.size() == 0);
177
+ // }
178
+ // }),
179
+ // volta::react::Callback([](auto args) {
180
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
181
+ // std::get<utils::json::JsonContainer>(args[0]));
182
+ // std::string rejectionMessage = std::get<std::string>(payload["message"]);
183
+ // if (rejectionMessage.find("already exists") != std::string::npos) {
184
+ // THEN("Promise is rejected with appropriate error message when the test is run more than
185
+ // once") {
186
+ // REQUIRE(rejectionMessage == "Directory already exists!");
187
+ // }
188
+ // } else {
189
+ // handlePromiseRejection(payload);
190
+ // }
191
+ // })));
192
+ // }
193
+
194
+ // Unable to test due to lack of 'Promise' support
195
+ // WHEN("copyAsync is called") {
196
+ // auto promise = fileSystemModule.copyAsync(
197
+ // volta::react::NativeJSObject{{"from", "data/hello-world.txt"}, {"to", "data/hello/world.txt"}});
198
+
199
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
200
+ // volta::react::Callback([](auto args) {
201
+ // THEN("Promise is resolved on success") {
202
+ // REQUIRE(args.size() == 0);
203
+ // }
204
+ // }),
205
+ // volta::react::Callback([](auto args) {
206
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
207
+ // std::get<utils::json::JsonContainer>(args[0]));
208
+ // std::string rejectionMessage = std::get<std::string>(payload["message"]);
209
+ // if (rejectionMessage.find("cannot copy: File exists") != std::string::npos) {
210
+ // THEN("Promise is rejected with appropriate error message when the test is run more than
211
+ // once") {
212
+ // }
213
+ // } else {
214
+ // handlePromiseRejection(payload);
215
+ // }
216
+ // })));
217
+ // }
218
+
219
+ // Unable to test due to lack of 'Promise' support
220
+ // WHEN("moveAsync is called") {
221
+ // auto promise = fileSystemModule.moveAsync(
222
+ // volta::react::NativeJSObject{{"from", "data/hello-world.txt"}, {"to",
223
+ // "data/hello/hello-world.txt"}});
224
+
225
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
226
+ // volta::react::Callback([](auto args) {
227
+ // THEN("Promise is resolved on success") {
228
+ // REQUIRE(args.size() == 0);
229
+ // }
230
+ // }),
231
+ // volta::react::Callback([](auto args) {
232
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
233
+ // std::get<utils::json::JsonContainer>(args[0]));
234
+ // handlePromiseRejection(payload);
235
+ // })));
236
+ // }
237
+
238
+ // Unable to test due to lack of 'Promise' support
239
+ // WHEN("deleteAsync is called") {
240
+ // auto promise = fileSystemModule.deleteAsync("data/hello/hello-world.txt", {});
241
+
242
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
243
+ // volta::react::Callback([](auto args) {
244
+ // THEN("Promise is resolved on success") {
245
+ // REQUIRE(args.size() == 0);
246
+ // }
247
+ // }),
248
+ // volta::react::Callback([](auto args) {
249
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
250
+ // std::get<utils::json::JsonContainer>(args[0]));
251
+ // handlePromiseRejection(payload);
252
+ // })));
253
+ // }
254
+
255
+ // Unable to test due to lack of 'Promise' support
256
+ // WHEN("readDirectoryAsync is called") {
257
+ // auto promise = fileSystemModule.readDirectoryAsync("/data/hello");
258
+
259
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
260
+ // volta::react::Callback([](auto args) {
261
+ // THEN("Resolved promise contains directory content") {
262
+ // REQUIRE(args.size() == 1);
263
+ // REQUIRE(std::holds_alternative<volta::react::NativeJSArray>(args[0]));
264
+
265
+ // volta::react::NativeJSArray directoryContent =
266
+ // std::get<volta::react::NativeJSArray>(args[0]);
267
+
268
+ // REQUIRE(directoryContent.size() > 0);
269
+
270
+ // for (volta::react::NativeJSValue entry : directoryContent)
271
+ // REQUIRE(std::holds_alternative<std::string>(entry));
272
+ // }
273
+ // }),
274
+ // volta::react::Callback([](auto args) {
275
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
276
+ // std::get<utils::json::JsonContainer>(args[0]));
277
+ // handlePromiseRejection(payload);
278
+ // })));
279
+ // }
280
+
281
+ // Unable to test due to lack of 'Promise' support
282
+ // WHEN("getFreeDiskStorageAsync is called") {
283
+ // auto promise = fileSystemModule.getFreeDiskStorageAsync();
284
+
285
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
286
+ // volta::react::Callback([](auto args) {
287
+ // THEN("Resolved promise contains free disk capacity in bytes") {
288
+ // REQUIRE(args.size() == 1);
289
+ // REQUIRE(std::holds_alternative<std::string>(args[0]));
290
+ // }
291
+ // }),
292
+ // volta::react::Callback([](auto args) {
293
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
294
+ // std::get<utils::json::JsonContainer>(args[0]));
295
+ // handlePromiseRejection(payload);
296
+ // })));
297
+ // }
298
+
299
+ // Unable to test due to lack of 'Promise' support
300
+ // WHEN("getTotalDiskCapacityAsync is called") {
301
+ // auto promise = fileSystemModule.getTotalDiskCapacityAsync();
302
+
303
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
304
+ // volta::react::Callback([](auto args) {
305
+ // THEN("Resolved promise does not contain free disk capacity information") {
306
+ // REQUIRE(args.size() == 0);
307
+ // }
308
+ // }),
309
+ // volta::react::Callback([](auto args) {
310
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
311
+ // std::get<utils::json::JsonContainer>(args[0]));
312
+ // handlePromiseRejection(payload);
313
+ // })));
314
+ // }
315
+
316
+ // Unable to test due to lack of 'Promise' support
317
+ // Sidenote: wifi connection is required to perform below testcase
318
+ // WHEN("downloadAsync is called") {
319
+ // std::vector<utils::json::JsonContainer> headers;
320
+ // auto headerAccept = utils::json::JsonContainer::createJsonObject();
321
+ // headerAccept.insert("Accept", 'application/json');
322
+ // headers.push_back(headerAccept);
323
+
324
+ // auto promise =
325
+ // fileSystemModule
326
+ // .downloadAsync("https://httpbin.org/get", "/data/hello/downloadResponse.json", {}, 1,
327
+ // headers);
328
+
329
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
330
+ // volta::react::Callback([](auto args) {
331
+ // THEN("Resolved promise contains download response") {
332
+ // REQUIRE(args.size() == 1);
333
+ // REQUIRE(std::holds_alternative<volta::react::NativeJSObject>(args[0]));
334
+
335
+ // volta::react::NativeJSObject fileInfo = std::get<volta::react::NativeJSObject>(args[0]);
336
+
337
+ // REQUIRE(std::holds_alternative<std::string>(fileInfo["uri"]));
338
+
339
+ // REQUIRE(std::get<std::string>(fileInfo["uri"]) == "/data/hello/downloadResponse.json");
340
+ // }
341
+ // }),
342
+ // volta::react::Callback([](auto args) {
343
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
344
+ // std::get<utils::json::JsonContainer>(args[0]));
345
+ // handlePromiseRejection(payload);
346
+ // })));
347
+ // }
348
+
349
+ // Unable to test due to lack of 'Promise' support
350
+ // Sidenote: wifi connection is required to perform below testcase
351
+ // WHEN("uploadAsync is called") {
352
+ // std::vector<utils::json::JsonContainer> headers;
353
+ // auto headerAccept = utils::json::JsonContainer::createJsonObject();
354
+ // headerAccept.insert("Accept", 'application/json');
355
+ // headers.push_back(headerAccept);
356
+
357
+ // auto promise =
358
+ // fileSystemModule
359
+ // .uploadAsync("https://httpbin.org/post", "/data/hello/uploadResponse.json", {}, 2,
360
+ // headers);
361
+
362
+ // promise.promiseOperation_(std::make_shared<volta::react::Promise>(
363
+ // volta::react::Callback([](auto args) {
364
+ // THEN("Resolved promise contains upload response") {
365
+ // REQUIRE(args.size() == 1);
366
+ // REQUIRE(std::holds_alternative<volta::react::NativeJSObject>(args[0]));
367
+
368
+ // volta::react::NativeJSObject fileInfo = std::get<volta::react::NativeJSObject>(args[0]);
369
+
370
+ // REQUIRE(std::holds_alternative<std::string>(fileInfo["uri"]));
371
+
372
+ // REQUIRE(std::get<std::string>(fileInfo["uri"]) == "/data/hello/uploadResponse.json");
373
+ // }
374
+ // }),
375
+ // volta::react::Callback([](auto args) {
376
+ // volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
377
+ // std::get<utils::json::JsonContainer>(args[0]));
378
+ // handlePromiseRejection(payload);
379
+ // })));
380
+ // }
381
+
382
+ WHEN("aggregateMethods is called") {
383
+ std::weak_ptr<facebook::react::Instance> instance;
384
+ fileSystemModule.triggerMethodAggregation(*fileSystemModule.jsQueue_, instance);
385
+
386
+ THEN("methodContainerMap contains expected methods") {
387
+ REQUIRE(fileSystemModule.methodContainerMap_.find("documentDirectory") !=
388
+ fileSystemModule.methodContainerMap_.end());
389
+ REQUIRE(fileSystemModule.methodContainerMap_.find("cacheDirectory") !=
390
+ fileSystemModule.methodContainerMap_.end());
391
+ REQUIRE(fileSystemModule.methodContainerMap_.find("bundleDirectory") !=
392
+ fileSystemModule.methodContainerMap_.end());
393
+ REQUIRE(fileSystemModule.methodContainerMap_.find("getInfoAsync") !=
394
+ fileSystemModule.methodContainerMap_.end());
395
+ REQUIRE(fileSystemModule.methodContainerMap_.find("readAsStringAsync") !=
396
+ fileSystemModule.methodContainerMap_.end());
397
+ REQUIRE(fileSystemModule.methodContainerMap_.find("getContentUriAsync") !=
398
+ fileSystemModule.methodContainerMap_.end());
399
+ REQUIRE(fileSystemModule.methodContainerMap_.find("writeAsStringAsync") !=
400
+ fileSystemModule.methodContainerMap_.end());
401
+ REQUIRE(fileSystemModule.methodContainerMap_.find("deleteAsync") !=
402
+ fileSystemModule.methodContainerMap_.end());
403
+ REQUIRE(fileSystemModule.methodContainerMap_.find("moveAsync") !=
404
+ fileSystemModule.methodContainerMap_.end());
405
+ REQUIRE(fileSystemModule.methodContainerMap_.find("copyAsync") !=
406
+ fileSystemModule.methodContainerMap_.end());
407
+ REQUIRE(fileSystemModule.methodContainerMap_.find("makeDirectoryAsync") !=
408
+ fileSystemModule.methodContainerMap_.end());
409
+ REQUIRE(fileSystemModule.methodContainerMap_.find("readDirectoryAsync") !=
410
+ fileSystemModule.methodContainerMap_.end());
411
+ REQUIRE(fileSystemModule.methodContainerMap_.find("getFreeDiskStorageAsync") !=
412
+ fileSystemModule.methodContainerMap_.end());
413
+ REQUIRE(fileSystemModule.methodContainerMap_.find("getTotalDiskCapacityAsync") !=
414
+ fileSystemModule.methodContainerMap_.end());
415
+ REQUIRE(fileSystemModule.methodContainerMap_.find("downloadAsync") !=
416
+ fileSystemModule.methodContainerMap_.end());
417
+ REQUIRE(fileSystemModule.methodContainerMap_.find("uploadAsync") !=
418
+ fileSystemModule.methodContainerMap_.end());
419
+ }
420
+
421
+ THEN("size of methodContainerMap is increased by addListener and removeListeners") {
422
+ REQUIRE(fileSystemModule.methodContainerMap_.size() == 19);
423
+ }
424
+ }
425
+ }
package/package.json ADDED
@@ -0,0 +1 @@
1
+ {"name": "@amazon-devices/expo-file-system", "version": "2.0.1758683737+15.8.0", "description": "Provides access to the local file system on the device.", "main": "build/index.js", "types": "build/index.d.ts", "sideEffects": false, "scripts": {"build": "expo-module build", "clean": "expo-module clean", "lint": "expo-module lint", "test": "expo-module test", "expo-module": "expo-module"}, "kepler": {"temporary-alias-for-package": {"name": "expo-file-system", "version": "15.8.0"}}, "keywords": ["react-native", "expo", "file-system", "file"], "repository": {"type": "git", "url": "https://github.com/expo/expo.git", "directory": "packages/expo-file-system"}, "bugs": {"url": "https://github.com/expo/expo/issues"}, "author": "650 Industries, Inc.", "license": "See license in LICENSE", "homepage": "https://docs.expo.dev/versions/latest/sdk/filesystem/", "dependencies": {"uuid": "^3.4.0", "@amazon-devices/keplerscript-turbomodule-api": "^1.0.0"}, "devDependencies": {"expo-module-scripts": "^3.0.0", "jest-expo": "~50.0.0-alpha.0"}, "peerDependencies": {"expo": "*"}}
@@ -0,0 +1,3 @@
1
+ import { ConfigPlugin } from 'expo/config-plugins';
2
+ declare const _default: ConfigPlugin<void>;
3
+ export default _default;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config_plugins_1 = require("expo/config-plugins");
4
+ const pkg = require('expo-file-system/package.json');
5
+ const withFileSystem = (config) => {
6
+ return config_plugins_1.AndroidConfig.Permissions.withPermissions(config, [
7
+ 'android.permission.READ_EXTERNAL_STORAGE',
8
+ 'android.permission.WRITE_EXTERNAL_STORAGE',
9
+ 'android.permission.INTERNET',
10
+ ]);
11
+ };
12
+ exports.default = (0, config_plugins_1.createRunOncePlugin)(withFileSystem, pkg.name, pkg.version);
@@ -0,0 +1,13 @@
1
+ import { AndroidConfig, ConfigPlugin, createRunOncePlugin } from 'expo/config-plugins';
2
+
3
+ const pkg = require('expo-file-system/package.json');
4
+
5
+ const withFileSystem: ConfigPlugin = (config) => {
6
+ return AndroidConfig.Permissions.withPermissions(config, [
7
+ 'android.permission.READ_EXTERNAL_STORAGE',
8
+ 'android.permission.WRITE_EXTERNAL_STORAGE',
9
+ 'android.permission.INTERNET',
10
+ ]);
11
+ };
12
+
13
+ export default createRunOncePlugin(withFileSystem, pkg.name, pkg.version);
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "expo-module-scripts/tsconfig.plugin",
3
+ "compilerOptions": {
4
+ "outDir": "build",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["./src"],
8
+ "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/withFileSystem.ts"],"version":"5.7.2"}
@@ -0,0 +1,21 @@
1
+ module.exports = {
2
+ dependencies: {
3
+ '@amazon-devices/react-native-kepler': {
4
+ platforms: {
5
+ kepler: null, // do not use platform definition from @react-native-kepler
6
+ },
7
+ },
8
+ },
9
+ dependency: {
10
+ platforms: {
11
+ kepler: {
12
+ autolink: {
13
+ ExponentFileSystemLib: {
14
+ provider: 'system',
15
+ turbomodules: ['ExponentFileSystem'],
16
+ },
17
+ },
18
+ },
19
+ },
20
+ },
21
+ };
@@ -0,0 +1,167 @@
1
+ import { KeplerTurboModule, TurboModuleRegistry } from '@amazon-devices/keplerscript-turbomodule-api';
2
+
3
+ import {
4
+ DeletingOptions,
5
+ DownloadOptions,
6
+ FileInfo,
7
+ FileSystemDownloadResult,
8
+ FileSystemUploadOptions,
9
+ FileSystemUploadResult,
10
+ InfoOptions,
11
+ MakeDirectoryOptions,
12
+ ReadingOptions,
13
+ RelocatingOptions,
14
+ WritingOptions,
15
+ FileSystemHttpResult,
16
+ } from './FileSystem.types';
17
+ import { ExponentFileSystemModule } from './types';
18
+
19
+ interface Spec extends KeplerTurboModule {
20
+ readonly documentDirectory: () => string;
21
+ readonly cacheDirectory: () => string;
22
+ /**
23
+ * @deprecated this property was removed from expo
24
+ */
25
+ readonly bundledAssets: () => string;
26
+ readonly bundleDirectory: () => string;
27
+ readonly getInfoAsync: (fileUri: string, options: InfoOptions) => Promise<FileInfo>;
28
+ readonly readAsStringAsync: (fileUri: string, options: ReadingOptions) => Promise<string>;
29
+ readonly getContentUriAsync: (fileUri: string) => Promise<string>;
30
+ readonly writeAsStringAsync: (fileUri: string, contents: string, options: WritingOptions) => Promise<void>;
31
+ readonly writeArrayBufferAsync: (fileUri: string, contents: ArrayBuffer) => Promise<void>;
32
+ readonly deleteAsync: (fileUri: string, options: DeletingOptions) => Promise<void>;
33
+ readonly moveAsync: (options: RelocatingOptions) => Promise<void>;
34
+ readonly copyAsync: (options: RelocatingOptions) => Promise<void>;
35
+ readonly makeDirectoryAsync: (fileUri: string, options: MakeDirectoryOptions) => Promise<void>;
36
+ readonly readDirectoryAsync: (fileUri: string) => Promise<string[]>;
37
+ readonly getFreeDiskStorageAsync: () => Promise<string>;
38
+ readonly getTotalDiskCapacityAsync: () => Promise<string | undefined>;
39
+ }
40
+
41
+ const nativeModule = TurboModuleRegistry.getEnforcing<Spec>('ExponentFileSystem') as Spec;
42
+ const expoCryptoNativeModule = TurboModuleRegistry.getEnforcing<any>('ExpoCrypto');
43
+
44
+ function getHeadersFromResponse(response: Response): FileSystemHttpResult['headers'] {
45
+ const responseHeaders: FileSystemDownloadResult['headers'] = {};
46
+ response.headers.forEach((value: string, key: string) => {
47
+ responseHeaders[key] = value;
48
+ })
49
+ return responseHeaders;
50
+ }
51
+
52
+ function getMimeTypeFromHeaders(responseHeaders: FileSystemHttpResult['headers']): FileSystemHttpResult['mimeType'] {
53
+ const contentTypeKey = Object.keys(responseHeaders).find((key) => key.toLowerCase() === "content-type");
54
+ return contentTypeKey ? responseHeaders[contentTypeKey].split(';')[0] : null;
55
+ }
56
+
57
+ const module: ExponentFileSystemModule = {
58
+ get name(): 'ExponentFileSystem' {
59
+ return 'ExponentFileSystem';
60
+ },
61
+ get documentDirectory() {
62
+ return nativeModule.documentDirectory();
63
+ },
64
+ get cacheDirectory() {
65
+ return nativeModule.cacheDirectory();
66
+ },
67
+ /**
68
+ * @deprecated this property was removed from expo
69
+ */
70
+ get bundledAssets() {
71
+ return null;
72
+ },
73
+ get bundleDirectory() {
74
+ return nativeModule.bundleDirectory();
75
+ },
76
+ async getInfoAsync(fileUri: string, options: InfoOptions) {
77
+ return nativeModule.getInfoAsync(fileUri, options);
78
+ },
79
+ async readAsStringAsync(fileUri: string, options: ReadingOptions) {
80
+ return nativeModule.readAsStringAsync(fileUri, options);
81
+ },
82
+ async getContentUriAsync(fileUri: string) {
83
+ return nativeModule.getContentUriAsync(fileUri);
84
+ },
85
+ async writeAsStringAsync(fileUri: string, contents: string, options: WritingOptions) {
86
+ return nativeModule.writeAsStringAsync(fileUri, contents, options);
87
+ },
88
+ async deleteAsync(fileUri: string, options: DeletingOptions) {
89
+ return nativeModule.deleteAsync(fileUri, options);
90
+ },
91
+ async moveAsync(options: RelocatingOptions) {
92
+ return nativeModule.moveAsync(options);
93
+ },
94
+ async copyAsync(options: RelocatingOptions) {
95
+ return nativeModule.copyAsync(options);
96
+ },
97
+ async makeDirectoryAsync(fileUri: string, options: MakeDirectoryOptions) {
98
+ return nativeModule.makeDirectoryAsync(fileUri, options);
99
+ },
100
+ async readDirectoryAsync(fileUri: string) {
101
+ return nativeModule.readDirectoryAsync(fileUri);
102
+ },
103
+ async getFreeDiskStorageAsync() {
104
+ return nativeModule.getFreeDiskStorageAsync().then(parseInt);
105
+ },
106
+ async getTotalDiskCapacityAsync() {
107
+ const result = await nativeModule.getTotalDiskCapacityAsync();
108
+ return result ? parseInt(result) : 0;
109
+ },
110
+ async downloadAsync(url: string, fileUri: string, options: DownloadOptions): Promise<FileSystemDownloadResult> {
111
+ const { headers, md5 } = options;
112
+ const response = await fetch(url, { headers });
113
+
114
+ if (!response.ok) {
115
+ throw new Error('Failed to download the file!');
116
+ }
117
+
118
+ const data = await response.arrayBuffer();
119
+
120
+ await nativeModule.writeArrayBufferAsync(fileUri, data);
121
+
122
+ const responseHeaders = getHeadersFromResponse(response);
123
+
124
+ let downloadResult: FileSystemDownloadResult = {
125
+ uri: fileUri,
126
+ headers: responseHeaders,
127
+ status: response.status,
128
+ mimeType: getMimeTypeFromHeaders(responseHeaders)
129
+ };
130
+
131
+ if (md5) {
132
+ const md5ArrayBuffer = await expoCryptoNativeModule.digestAsync("MD5", data);
133
+ downloadResult.md5 = [...new Uint8Array(md5ArrayBuffer)]
134
+ .map(x => x.toString(16).padStart(2, '0'))
135
+ .join('');
136
+ }
137
+
138
+ return downloadResult;
139
+ },
140
+ async uploadAsync(url: string, fileUri: string, options: FileSystemUploadOptions): Promise<FileSystemUploadResult> {
141
+ const { headers, httpMethod } = options;
142
+ const method = httpMethod ?? "POST";
143
+
144
+ const data = await nativeModule.readAsStringAsync(fileUri, {});
145
+
146
+ const response = await fetch(url, { method, headers, body: data });
147
+
148
+ if (!response.ok) {
149
+ throw new Error('Failed to upload the file!');
150
+ }
151
+
152
+ const uploadResult = await response.text();
153
+
154
+ const responseHeaders = getHeadersFromResponse(response);
155
+
156
+ return {
157
+ body: uploadResult,
158
+ headers: responseHeaders,
159
+ status: response.status,
160
+ mimeType: getMimeTypeFromHeaders(responseHeaders)
161
+ };
162
+ },
163
+ addListener(eventName: string): void{},
164
+ removeListeners(count: number): void{},
165
+ };
166
+
167
+ export default module;