18285c032STomasz Sapetaimport { EventEmitter, UnavailabilityError } from 'expo-modules-core'; 21da2f189STomasz Sapetaimport { Platform } from 'react-native'; 37f896a5fSGiau. Tran Minhimport { v4 as uuidv4 } from 'uuid'; 479a5fc63SJames Ideimport ExponentFileSystem from './ExponentFileSystem'; 56b7802baSBartosz Kaszubowskiimport { FileSystemSessionType, FileSystemUploadType, } from './FileSystem.types'; 67e929553SEvan Baconif (!ExponentFileSystem) { 72307aaceSEvan Bacon console.warn("No native ExponentFileSystem module found, are you sure the expo-file-system's module is linked properly?"); 82307aaceSEvan Bacon} 98f6e1365SEvan Bacon// Prevent webpack from pruning this. 1079a5fc63SJames Ideconst _unused = new EventEmitter(ExponentFileSystem); // eslint-disable-line 112307aaceSEvan Baconfunction normalizeEndingSlash(p) { 122307aaceSEvan Bacon if (p != null) { 132307aaceSEvan Bacon return p.replace(/\/*$/, '') + '/'; 142307aaceSEvan Bacon } 152307aaceSEvan Bacon return null; 162307aaceSEvan Bacon} 176b7802baSBartosz Kaszubowski/** 186b7802baSBartosz Kaszubowski * `file://` URI pointing to the directory where user documents for this app will be stored. 196b7802baSBartosz Kaszubowski * Files stored here will remain until explicitly deleted by the app. Ends with a trailing `/`. 206b7802baSBartosz Kaszubowski * Example uses are for files the user saves that they expect to see again. 216b7802baSBartosz Kaszubowski */ 227e929553SEvan Baconexport const documentDirectory = normalizeEndingSlash(ExponentFileSystem.documentDirectory); 236b7802baSBartosz Kaszubowski/** 246b7802baSBartosz Kaszubowski * `file://` URI pointing to the directory where temporary files used by this app will be stored. 256b7802baSBartosz Kaszubowski * Files stored here may be automatically deleted by the system when low on storage. 266b7802baSBartosz Kaszubowski * Example uses are for downloaded or generated files that the app just needs for one-time usage. 276b7802baSBartosz Kaszubowski */ 287e929553SEvan Baconexport const cacheDirectory = normalizeEndingSlash(ExponentFileSystem.cacheDirectory); 296b7802baSBartosz Kaszubowski// @docsMissing 307e929553SEvan Baconexport const { bundledAssets, bundleDirectory } = ExponentFileSystem; 316b7802baSBartosz Kaszubowski/** 326b7802baSBartosz Kaszubowski * Get metadata information about a file, directory or external content/asset. 336b7802baSBartosz Kaszubowski * @param fileUri URI to the file or directory. See [supported URI schemes](#supported-uri-schemes). 346b7802baSBartosz Kaszubowski * @param options A map of options represented by [`GetInfoAsyncOptions`](#getinfoasyncoptions) type. 356b7802baSBartosz Kaszubowski * @return A Promise that resolves to a `FileInfo` object. If no item exists at this URI, 366b7802baSBartosz Kaszubowski * the returned Promise resolves to `FileInfo` object in form of `{ exists: false, isDirectory: false }`. 376b7802baSBartosz Kaszubowski */ 382307aaceSEvan Baconexport async function getInfoAsync(fileUri, options = {}) { 397e929553SEvan Bacon if (!ExponentFileSystem.getInfoAsync) { 402307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'getInfoAsync'); 412307aaceSEvan Bacon } 427e929553SEvan Bacon return await ExponentFileSystem.getInfoAsync(fileUri, options); 432307aaceSEvan Bacon} 446b7802baSBartosz Kaszubowski/** 456b7802baSBartosz Kaszubowski * Read the entire contents of a file as a string. Binary will be returned in raw format, you will need to append `data:image/png;base64,` to use it as Base64. 466b7802baSBartosz Kaszubowski * @param fileUri `file://` or [SAF](#saf-uri) URI to the file or directory. 476b7802baSBartosz Kaszubowski * @param options A map of read options represented by [`ReadingOptions`](#readingoptions) type. 486b7802baSBartosz Kaszubowski * @return A Promise that resolves to a string containing the entire contents of the file. 496b7802baSBartosz Kaszubowski */ 506b7802baSBartosz Kaszubowskiexport async function readAsStringAsync(fileUri, options = {}) { 517e929553SEvan Bacon if (!ExponentFileSystem.readAsStringAsync) { 522307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'readAsStringAsync'); 532307aaceSEvan Bacon } 546b7802baSBartosz Kaszubowski return await ExponentFileSystem.readAsStringAsync(fileUri, options); 552307aaceSEvan Bacon} 566b7802baSBartosz Kaszubowski/** 576b7802baSBartosz Kaszubowski * Takes a `file://` URI and converts it into content URI (`content://`) so that it can be accessed by other applications outside of Expo. 586b7802baSBartosz Kaszubowski * @param fileUri The local URI of the file. If there is no file at this URI, an exception will be thrown. 596b7802baSBartosz Kaszubowski * @example 606b7802baSBartosz Kaszubowski * ```js 616b7802baSBartosz Kaszubowski * FileSystem.getContentUriAsync(uri).then(cUri => { 626b7802baSBartosz Kaszubowski * console.log(cUri); 636b7802baSBartosz Kaszubowski * IntentLauncher.startActivityAsync('android.intent.action.VIEW', { 646b7802baSBartosz Kaszubowski * data: cUri, 656b7802baSBartosz Kaszubowski * flags: 1, 666b7802baSBartosz Kaszubowski * }); 676b7802baSBartosz Kaszubowski * }); 686b7802baSBartosz Kaszubowski * ``` 696b7802baSBartosz Kaszubowski * @return Returns a Promise that resolves to a `string` containing a `content://` URI pointing to the file. 706b7802baSBartosz Kaszubowski * The URI is the same as the `fileUri` input parameter but in a different format. 71*ca75dd58SBartosz Kaszubowski * @platform android 726b7802baSBartosz Kaszubowski */ 73e4897761STongyu Zhuexport async function getContentUriAsync(fileUri) { 741da2f189STomasz Sapeta if (Platform.OS === 'android') { 75e4897761STongyu Zhu if (!ExponentFileSystem.getContentUriAsync) { 76e4897761STongyu Zhu throw new UnavailabilityError('expo-file-system', 'getContentUriAsync'); 77e4897761STongyu Zhu } 78e4897761STongyu Zhu return await ExponentFileSystem.getContentUriAsync(fileUri); 79e4897761STongyu Zhu } 801da2f189STomasz Sapeta else { 81*ca75dd58SBartosz Kaszubowski return fileUri; 821da2f189STomasz Sapeta } 831da2f189STomasz Sapeta} 846b7802baSBartosz Kaszubowski/** 856b7802baSBartosz Kaszubowski * Write the entire contents of a file as a string. 866b7802baSBartosz Kaszubowski * @param fileUri `file://` or [SAF](#saf-uri) URI to the file or directory. 876b7802baSBartosz Kaszubowski * > Note: when you're using SAF URI the file needs to exist. You can't create a new file. 886b7802baSBartosz Kaszubowski * @param contents The string to replace the contents of the file with. 896b7802baSBartosz Kaszubowski * @param options A map of write options represented by [`WritingOptions`](#writingoptions) type. 906b7802baSBartosz Kaszubowski */ 912307aaceSEvan Baconexport async function writeAsStringAsync(fileUri, contents, options = {}) { 927e929553SEvan Bacon if (!ExponentFileSystem.writeAsStringAsync) { 932307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'writeAsStringAsync'); 942307aaceSEvan Bacon } 957e929553SEvan Bacon return await ExponentFileSystem.writeAsStringAsync(fileUri, contents, options); 962307aaceSEvan Bacon} 976b7802baSBartosz Kaszubowski/** 986b7802baSBartosz Kaszubowski * Delete a file or directory. If the URI points to a directory, the directory and all its contents are recursively deleted. 996b7802baSBartosz Kaszubowski * @param fileUri `file://` or [SAF](#saf-uri) URI to the file or directory. 1006b7802baSBartosz Kaszubowski * @param options A map of write options represented by [`DeletingOptions`](#deletingoptions) type. 1016b7802baSBartosz Kaszubowski */ 1022307aaceSEvan Baconexport async function deleteAsync(fileUri, options = {}) { 1037e929553SEvan Bacon if (!ExponentFileSystem.deleteAsync) { 1042307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'deleteAsync'); 1052307aaceSEvan Bacon } 1067e929553SEvan Bacon return await ExponentFileSystem.deleteAsync(fileUri, options); 1072307aaceSEvan Bacon} 1080d6db115SEric Samelsonexport async function deleteLegacyDocumentDirectoryAndroid() { 1090d6db115SEric Samelson if (Platform.OS !== 'android' || documentDirectory == null) { 1100d6db115SEric Samelson return; 1110d6db115SEric Samelson } 1120d6db115SEric Samelson const legacyDocumentDirectory = `${documentDirectory}ExperienceData/`; 1130d6db115SEric Samelson return await deleteAsync(legacyDocumentDirectory, { idempotent: true }); 1140d6db115SEric Samelson} 1156b7802baSBartosz Kaszubowski/** 1166b7802baSBartosz Kaszubowski * Move a file or directory to a new location. 1176b7802baSBartosz Kaszubowski * @param options A map of move options represented by [`RelocatingOptions`](#relocatingoptions) type. 1186b7802baSBartosz Kaszubowski */ 1192307aaceSEvan Baconexport async function moveAsync(options) { 1207e929553SEvan Bacon if (!ExponentFileSystem.moveAsync) { 1212307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'moveAsync'); 1222307aaceSEvan Bacon } 1237e929553SEvan Bacon return await ExponentFileSystem.moveAsync(options); 1242307aaceSEvan Bacon} 1256b7802baSBartosz Kaszubowski/** 1266b7802baSBartosz Kaszubowski * Create a copy of a file or directory. Directories are recursively copied with all of their contents. 1276b7802baSBartosz Kaszubowski * It can be also used to copy content shared by other apps to local filesystem. 1286b7802baSBartosz Kaszubowski * @param options A map of move options represented by [`RelocatingOptions`](#relocatingoptions) type. 1296b7802baSBartosz Kaszubowski */ 1302307aaceSEvan Baconexport async function copyAsync(options) { 1317e929553SEvan Bacon if (!ExponentFileSystem.copyAsync) { 1322307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'copyAsync'); 1332307aaceSEvan Bacon } 1347e929553SEvan Bacon return await ExponentFileSystem.copyAsync(options); 1352307aaceSEvan Bacon} 1366b7802baSBartosz Kaszubowski/** 1376b7802baSBartosz Kaszubowski * Create a new empty directory. 1386b7802baSBartosz Kaszubowski * @param fileUri `file://` URI to the new directory to create. 1396b7802baSBartosz Kaszubowski * @param options A map of create directory options represented by [`MakeDirectoryOptions`](#makedirectoryoptions) type. 1406b7802baSBartosz Kaszubowski */ 1412307aaceSEvan Baconexport async function makeDirectoryAsync(fileUri, options = {}) { 1427e929553SEvan Bacon if (!ExponentFileSystem.makeDirectoryAsync) { 1432307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'makeDirectoryAsync'); 1442307aaceSEvan Bacon } 1457e929553SEvan Bacon return await ExponentFileSystem.makeDirectoryAsync(fileUri, options); 1462307aaceSEvan Bacon} 1476b7802baSBartosz Kaszubowski/** 1486b7802baSBartosz Kaszubowski * Enumerate the contents of a directory. 1496b7802baSBartosz Kaszubowski * @param fileUri `file://` URI to the directory. 1506b7802baSBartosz Kaszubowski * @return A Promise that resolves to an array of strings, each containing the name of a file or directory contained in the directory at `fileUri`. 1516b7802baSBartosz Kaszubowski */ 1522307aaceSEvan Baconexport async function readDirectoryAsync(fileUri) { 1537e929553SEvan Bacon if (!ExponentFileSystem.readDirectoryAsync) { 1542307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'readDirectoryAsync'); 1552307aaceSEvan Bacon } 1567e929553SEvan Bacon return await ExponentFileSystem.readDirectoryAsync(fileUri, {}); 1572307aaceSEvan Bacon} 1586b7802baSBartosz Kaszubowski/** 1596b7802baSBartosz Kaszubowski * Gets the available internal disk storage size, in bytes. This returns the free space on the data partition that hosts all of the internal storage for all apps on the device. 1606b7802baSBartosz Kaszubowski * @return Returns a Promise that resolves to the number of bytes available on the internal disk, or JavaScript's [`MAX_SAFE_INTEGER`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) 1616b7802baSBartosz Kaszubowski * if the capacity is greater than 2<sup>53</sup> - 1 bytes. 1626b7802baSBartosz Kaszubowski */ 163ae9a5f1aSTongyu Zhuexport async function getFreeDiskStorageAsync() { 164ae9a5f1aSTongyu Zhu if (!ExponentFileSystem.getFreeDiskStorageAsync) { 165ae9a5f1aSTongyu Zhu throw new UnavailabilityError('expo-file-system', 'getFreeDiskStorageAsync'); 166ae9a5f1aSTongyu Zhu } 167ae9a5f1aSTongyu Zhu return await ExponentFileSystem.getFreeDiskStorageAsync(); 168ae9a5f1aSTongyu Zhu} 1696b7802baSBartosz Kaszubowski/** 1706b7802baSBartosz Kaszubowski * Gets total internal disk storage size, in bytes. This is the total capacity of the data partition that hosts all the internal storage for all apps on the device. 1716b7802baSBartosz Kaszubowski * @return Returns a Promise that resolves to a number that specifies the total internal disk storage capacity in bytes, or JavaScript's [`MAX_SAFE_INTEGER`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) 1726b7802baSBartosz Kaszubowski * if the capacity is greater than 2<sup>53</sup> - 1 bytes. 1736b7802baSBartosz Kaszubowski */ 174ae9a5f1aSTongyu Zhuexport async function getTotalDiskCapacityAsync() { 175ae9a5f1aSTongyu Zhu if (!ExponentFileSystem.getTotalDiskCapacityAsync) { 176ae9a5f1aSTongyu Zhu throw new UnavailabilityError('expo-file-system', 'getTotalDiskCapacityAsync'); 177ae9a5f1aSTongyu Zhu } 178ae9a5f1aSTongyu Zhu return await ExponentFileSystem.getTotalDiskCapacityAsync(); 179ae9a5f1aSTongyu Zhu} 1806b7802baSBartosz Kaszubowski/** 1816b7802baSBartosz Kaszubowski * Download the contents at a remote URI to a file in the app's file system. The directory for a local file uri must exist prior to calling this function. 1826b7802baSBartosz Kaszubowski * @param uri The remote URI to download from. 1836b7802baSBartosz Kaszubowski * @param fileUri The local URI of the file to download to. If there is no file at this URI, a new one is created. 1846b7802baSBartosz Kaszubowski * If there is a file at this URI, its contents are replaced. The directory for the file must exist. 1856b7802baSBartosz Kaszubowski * @param options A map of download options represented by [`DownloadOptions`](#downloadoptions) type. 1866b7802baSBartosz Kaszubowski * @example 1876b7802baSBartosz Kaszubowski * ```js 1886b7802baSBartosz Kaszubowski * FileSystem.downloadAsync( 1896b7802baSBartosz Kaszubowski * 'http://techslides.com/demos/sample-videos/small.mp4', 1906b7802baSBartosz Kaszubowski * FileSystem.documentDirectory + 'small.mp4' 1916b7802baSBartosz Kaszubowski * ) 1926b7802baSBartosz Kaszubowski * .then(({ uri }) => { 1936b7802baSBartosz Kaszubowski * console.log('Finished downloading to ', uri); 1946b7802baSBartosz Kaszubowski * }) 1956b7802baSBartosz Kaszubowski * .catch(error => { 1966b7802baSBartosz Kaszubowski * console.error(error); 1976b7802baSBartosz Kaszubowski * }); 1986b7802baSBartosz Kaszubowski * ``` 1996b7802baSBartosz Kaszubowski * @return Returns a Promise that resolves to a `FileSystemDownloadResult` object. 2006b7802baSBartosz Kaszubowski */ 2012307aaceSEvan Baconexport async function downloadAsync(uri, fileUri, options = {}) { 2027e929553SEvan Bacon if (!ExponentFileSystem.downloadAsync) { 2032307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'downloadAsync'); 2042307aaceSEvan Bacon } 205da65a760SŁukasz Kosmaty return await ExponentFileSystem.downloadAsync(uri, fileUri, { 206da65a760SŁukasz Kosmaty sessionType: FileSystemSessionType.BACKGROUND, 207da65a760SŁukasz Kosmaty ...options, 208da65a760SŁukasz Kosmaty }); 209da65a760SŁukasz Kosmaty} 2106b7802baSBartosz Kaszubowski/** 2116b7802baSBartosz Kaszubowski * Upload the contents of the file pointed by `fileUri` to the remote url. 2126b7802baSBartosz Kaszubowski * @param url The remote URL, where the file will be sent. 2136b7802baSBartosz Kaszubowski * @param fileUri The local URI of the file to send. The file must exist. 2146b7802baSBartosz Kaszubowski * @param options A map of download options represented by [`FileSystemUploadOptions`](#filesystemuploadoptions) type. 2156b7802baSBartosz Kaszubowski * @example 2166b7802baSBartosz Kaszubowski * **Client** 2176b7802baSBartosz Kaszubowski * 2186b7802baSBartosz Kaszubowski * ```js 2196b7802baSBartosz Kaszubowski * import * as FileSystem from 'expo-file-system'; 2206b7802baSBartosz Kaszubowski * 2216b7802baSBartosz Kaszubowski * try { 2226b7802baSBartosz Kaszubowski * const response = await FileSystem.uploadAsync(`http://192.168.0.1:1234/binary-upload`, fileUri, { 2236b7802baSBartosz Kaszubowski * fieldName: 'file', 2246b7802baSBartosz Kaszubowski * httpMethod: 'PATCH', 2256b7802baSBartosz Kaszubowski * uploadType: FileSystem.FileSystemUploadType.BINARY_CONTENT, 2266b7802baSBartosz Kaszubowski * }); 2276b7802baSBartosz Kaszubowski * console.log(JSON.stringify(response, null, 4)); 2286b7802baSBartosz Kaszubowski * } catch (error) { 2296b7802baSBartosz Kaszubowski * console.log(error); 2306b7802baSBartosz Kaszubowski * } 2316b7802baSBartosz Kaszubowski * ``` 2326b7802baSBartosz Kaszubowski * 2336b7802baSBartosz Kaszubowski * **Server** 2346b7802baSBartosz Kaszubowski * 2356b7802baSBartosz Kaszubowski * Please refer to the "[Server: Handling multipart requests](#server-handling-multipart-requests)" example - there is code for a simple Node.js server. 2366b7802baSBartosz Kaszubowski * @return Returns a Promise that resolves to `FileSystemUploadResult` object. 2376b7802baSBartosz Kaszubowski */ 238da65a760SŁukasz Kosmatyexport async function uploadAsync(url, fileUri, options = {}) { 239da65a760SŁukasz Kosmaty if (!ExponentFileSystem.uploadAsync) { 240da65a760SŁukasz Kosmaty throw new UnavailabilityError('expo-file-system', 'uploadAsync'); 241da65a760SŁukasz Kosmaty } 242da65a760SŁukasz Kosmaty return await ExponentFileSystem.uploadAsync(url, fileUri, { 243da65a760SŁukasz Kosmaty sessionType: FileSystemSessionType.BACKGROUND, 24437630a92SŁukasz Kosmaty uploadType: FileSystemUploadType.BINARY_CONTENT, 245da65a760SŁukasz Kosmaty ...options, 246da65a760SŁukasz Kosmaty httpMethod: (options.httpMethod || 'POST').toUpperCase(), 247da65a760SŁukasz Kosmaty }); 2482307aaceSEvan Bacon} 2496b7802baSBartosz Kaszubowski/** 2506b7802baSBartosz Kaszubowski * Create a `DownloadResumable` object which can start, pause, and resume a download of contents at a remote URI to a file in the app's file system. 2516b7802baSBartosz Kaszubowski * > Note: You need to call `downloadAsync()`, on a `DownloadResumable` instance to initiate the download. 2526b7802baSBartosz Kaszubowski * The `DownloadResumable` object has a callback that provides download progress updates. 2536b7802baSBartosz Kaszubowski * Downloads can be resumed across app restarts by using `AsyncStorage` to store the `DownloadResumable.savable()` object for later retrieval. 2546b7802baSBartosz Kaszubowski * The `savable` object contains the arguments required to initialize a new `DownloadResumable` object to resume the download after an app restart. 2556b7802baSBartosz Kaszubowski * The directory for a local file uri must exist prior to calling this function. 2566b7802baSBartosz Kaszubowski * @param uri The remote URI to download from. 2576b7802baSBartosz Kaszubowski * @param fileUri The local URI of the file to download to. If there is no file at this URI, a new one is created. 2586b7802baSBartosz Kaszubowski * If there is a file at this URI, its contents are replaced. The directory for the file must exist. 2596b7802baSBartosz Kaszubowski * @param options A map of download options represented by [`DownloadOptions`](#downloadoptions) type. 2606b7802baSBartosz Kaszubowski * @param callback This function is called on each data write to update the download progress. 2616b7802baSBartosz Kaszubowski * > **Note**: When the app has been moved to the background, this callback won't be fired until it's moved to the foreground. 2626b7802baSBartosz Kaszubowski * @param resumeData The string which allows the api to resume a paused download. This is set on the `DownloadResumable` object automatically when a download is paused. 2636b7802baSBartosz Kaszubowski * When initializing a new `DownloadResumable` this should be `null`. 2646b7802baSBartosz Kaszubowski */ 2652307aaceSEvan Baconexport function createDownloadResumable(uri, fileUri, options, callback, resumeData) { 2662307aaceSEvan Bacon return new DownloadResumable(uri, fileUri, options, callback, resumeData); 2672307aaceSEvan Bacon} 26852eeb172SŁukasz Kosmatyexport function createUploadTask(url, fileUri, options, callback) { 26952eeb172SŁukasz Kosmaty return new UploadTask(url, fileUri, options, callback); 27052eeb172SŁukasz Kosmaty} 27152eeb172SŁukasz Kosmatyexport class FileSystemCancellableNetworkTask { 27252eeb172SŁukasz Kosmaty _uuid = uuidv4(); 27352eeb172SŁukasz Kosmaty taskWasCanceled = false; 27452eeb172SŁukasz Kosmaty emitter = new EventEmitter(ExponentFileSystem); 27552eeb172SŁukasz Kosmaty subscription; 2766b7802baSBartosz Kaszubowski // @docsMissing 27752eeb172SŁukasz Kosmaty async cancelAsync() { 27852eeb172SŁukasz Kosmaty if (!ExponentFileSystem.networkTaskCancelAsync) { 27952eeb172SŁukasz Kosmaty throw new UnavailabilityError('expo-file-system', 'networkTaskCancelAsync'); 28052eeb172SŁukasz Kosmaty } 28152eeb172SŁukasz Kosmaty this.removeSubscription(); 28252eeb172SŁukasz Kosmaty this.taskWasCanceled = true; 28352eeb172SŁukasz Kosmaty return await ExponentFileSystem.networkTaskCancelAsync(this.uuid); 28452eeb172SŁukasz Kosmaty } 28552eeb172SŁukasz Kosmaty isTaskCancelled() { 28652eeb172SŁukasz Kosmaty if (this.taskWasCanceled) { 28752eeb172SŁukasz Kosmaty console.warn('This task was already canceled.'); 28852eeb172SŁukasz Kosmaty return true; 28952eeb172SŁukasz Kosmaty } 29052eeb172SŁukasz Kosmaty return false; 29152eeb172SŁukasz Kosmaty } 29252eeb172SŁukasz Kosmaty get uuid() { 29352eeb172SŁukasz Kosmaty return this._uuid; 29452eeb172SŁukasz Kosmaty } 29552eeb172SŁukasz Kosmaty addSubscription() { 29652eeb172SŁukasz Kosmaty if (this.subscription) { 29752eeb172SŁukasz Kosmaty return; 29852eeb172SŁukasz Kosmaty } 29952eeb172SŁukasz Kosmaty this.subscription = this.emitter.addListener(this.getEventName(), (event) => { 30052eeb172SŁukasz Kosmaty if (event.uuid === this.uuid) { 30152eeb172SŁukasz Kosmaty const callback = this.getCallback(); 30252eeb172SŁukasz Kosmaty if (callback) { 30352eeb172SŁukasz Kosmaty callback(event.data); 30452eeb172SŁukasz Kosmaty } 30552eeb172SŁukasz Kosmaty } 30652eeb172SŁukasz Kosmaty }); 30752eeb172SŁukasz Kosmaty } 30852eeb172SŁukasz Kosmaty removeSubscription() { 30952eeb172SŁukasz Kosmaty if (!this.subscription) { 31052eeb172SŁukasz Kosmaty return; 31152eeb172SŁukasz Kosmaty } 31252eeb172SŁukasz Kosmaty this.emitter.removeSubscription(this.subscription); 31352eeb172SŁukasz Kosmaty this.subscription = null; 31452eeb172SŁukasz Kosmaty } 31552eeb172SŁukasz Kosmaty} 31652eeb172SŁukasz Kosmatyexport class UploadTask extends FileSystemCancellableNetworkTask { 31752eeb172SŁukasz Kosmaty url; 31852eeb172SŁukasz Kosmaty fileUri; 31952eeb172SŁukasz Kosmaty callback; 32052eeb172SŁukasz Kosmaty options; 32152eeb172SŁukasz Kosmaty constructor(url, fileUri, options, callback) { 32252eeb172SŁukasz Kosmaty super(); 32352eeb172SŁukasz Kosmaty this.url = url; 32452eeb172SŁukasz Kosmaty this.fileUri = fileUri; 32552eeb172SŁukasz Kosmaty this.callback = callback; 32600d910e2SLuke Brandon Farrell const httpMethod = (options?.httpMethod?.toUpperCase() || 32752eeb172SŁukasz Kosmaty 'POST'); 32852eeb172SŁukasz Kosmaty this.options = { 32952eeb172SŁukasz Kosmaty sessionType: FileSystemSessionType.BACKGROUND, 33052eeb172SŁukasz Kosmaty uploadType: FileSystemUploadType.BINARY_CONTENT, 33152eeb172SŁukasz Kosmaty ...options, 33252eeb172SŁukasz Kosmaty httpMethod, 33352eeb172SŁukasz Kosmaty }; 33452eeb172SŁukasz Kosmaty } 33552eeb172SŁukasz Kosmaty getEventName() { 33652eeb172SŁukasz Kosmaty return 'expo-file-system.uploadProgress'; 33752eeb172SŁukasz Kosmaty } 33852eeb172SŁukasz Kosmaty getCallback() { 33952eeb172SŁukasz Kosmaty return this.callback; 34052eeb172SŁukasz Kosmaty } 3416b7802baSBartosz Kaszubowski // @docsMissing 34252eeb172SŁukasz Kosmaty async uploadAsync() { 34352eeb172SŁukasz Kosmaty if (!ExponentFileSystem.uploadTaskStartAsync) { 34452eeb172SŁukasz Kosmaty throw new UnavailabilityError('expo-file-system', 'uploadTaskStartAsync'); 34552eeb172SŁukasz Kosmaty } 34652eeb172SŁukasz Kosmaty if (this.isTaskCancelled()) { 34752eeb172SŁukasz Kosmaty return; 34852eeb172SŁukasz Kosmaty } 34952eeb172SŁukasz Kosmaty this.addSubscription(); 35052eeb172SŁukasz Kosmaty const result = await ExponentFileSystem.uploadTaskStartAsync(this.url, this.fileUri, this.uuid, this.options); 35152eeb172SŁukasz Kosmaty this.removeSubscription(); 35252eeb172SŁukasz Kosmaty return result; 35352eeb172SŁukasz Kosmaty } 35452eeb172SŁukasz Kosmaty} 35552eeb172SŁukasz Kosmatyexport class DownloadResumable extends FileSystemCancellableNetworkTask { 35652eeb172SŁukasz Kosmaty url; 357896103abSandy _fileUri; 35852eeb172SŁukasz Kosmaty options; 35952eeb172SŁukasz Kosmaty callback; 36052eeb172SŁukasz Kosmaty resumeData; 36152eeb172SŁukasz Kosmaty constructor(url, _fileUri, options = {}, callback, resumeData) { 36252eeb172SŁukasz Kosmaty super(); 36352eeb172SŁukasz Kosmaty this.url = url; 36452eeb172SŁukasz Kosmaty this._fileUri = _fileUri; 36552eeb172SŁukasz Kosmaty this.options = options; 36652eeb172SŁukasz Kosmaty this.callback = callback; 36752eeb172SŁukasz Kosmaty this.resumeData = resumeData; 36852eeb172SŁukasz Kosmaty } 36952eeb172SŁukasz Kosmaty get fileUri() { 37052eeb172SŁukasz Kosmaty return this._fileUri; 37152eeb172SŁukasz Kosmaty } 37252eeb172SŁukasz Kosmaty getEventName() { 37352eeb172SŁukasz Kosmaty return 'expo-file-system.downloadProgress'; 37452eeb172SŁukasz Kosmaty } 37552eeb172SŁukasz Kosmaty getCallback() { 37652eeb172SŁukasz Kosmaty return this.callback; 3772307aaceSEvan Bacon } 3786b7802baSBartosz Kaszubowski /** 3796b7802baSBartosz Kaszubowski * Download the contents at a remote URI to a file in the app's file system. 3806b7802baSBartosz Kaszubowski * @return Returns a Promise that resolves to `FileSystemDownloadResult` object, or to `undefined` when task was cancelled. 3816b7802baSBartosz Kaszubowski */ 3822307aaceSEvan Bacon async downloadAsync() { 3837e929553SEvan Bacon if (!ExponentFileSystem.downloadResumableStartAsync) { 3842307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'downloadResumableStartAsync'); 3852307aaceSEvan Bacon } 38652eeb172SŁukasz Kosmaty if (this.isTaskCancelled()) { 38752eeb172SŁukasz Kosmaty return; 38852eeb172SŁukasz Kosmaty } 38952eeb172SŁukasz Kosmaty this.addSubscription(); 39052eeb172SŁukasz Kosmaty return await ExponentFileSystem.downloadResumableStartAsync(this.url, this._fileUri, this.uuid, this.options, this.resumeData); 3912307aaceSEvan Bacon } 3926b7802baSBartosz Kaszubowski /** 3936b7802baSBartosz Kaszubowski * Pause the current download operation. `resumeData` is added to the `DownloadResumable` object after a successful pause operation. 3946b7802baSBartosz Kaszubowski * Returns an object that can be saved with `AsyncStorage` for future retrieval (the same object that is returned from calling `FileSystem.DownloadResumable.savable()`). 3956b7802baSBartosz Kaszubowski * @return Returns a Promise that resolves to `DownloadPauseState` object. 3966b7802baSBartosz Kaszubowski */ 3972307aaceSEvan Bacon async pauseAsync() { 3987e929553SEvan Bacon if (!ExponentFileSystem.downloadResumablePauseAsync) { 3992307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'downloadResumablePauseAsync'); 4002307aaceSEvan Bacon } 40152eeb172SŁukasz Kosmaty if (this.isTaskCancelled()) { 40252eeb172SŁukasz Kosmaty return { 40352eeb172SŁukasz Kosmaty fileUri: this._fileUri, 40452eeb172SŁukasz Kosmaty options: this.options, 40552eeb172SŁukasz Kosmaty url: this.url, 40652eeb172SŁukasz Kosmaty }; 40752eeb172SŁukasz Kosmaty } 40852eeb172SŁukasz Kosmaty const pauseResult = await ExponentFileSystem.downloadResumablePauseAsync(this.uuid); 40952eeb172SŁukasz Kosmaty this.removeSubscription(); 4102307aaceSEvan Bacon if (pauseResult) { 41152eeb172SŁukasz Kosmaty this.resumeData = pauseResult.resumeData; 4122307aaceSEvan Bacon return this.savable(); 4132307aaceSEvan Bacon } 4142307aaceSEvan Bacon else { 4152307aaceSEvan Bacon throw new Error('Unable to generate a savable pause state'); 4162307aaceSEvan Bacon } 4172307aaceSEvan Bacon } 4186b7802baSBartosz Kaszubowski /** 4196b7802baSBartosz Kaszubowski * Resume a paused download operation. 4206b7802baSBartosz Kaszubowski * @return Returns a Promise that resolves to `FileSystemDownloadResult` object, or to `undefined` when task was cancelled. 4216b7802baSBartosz Kaszubowski */ 4222307aaceSEvan Bacon async resumeAsync() { 4237e929553SEvan Bacon if (!ExponentFileSystem.downloadResumableStartAsync) { 4242307aaceSEvan Bacon throw new UnavailabilityError('expo-file-system', 'downloadResumableStartAsync'); 4252307aaceSEvan Bacon } 42652eeb172SŁukasz Kosmaty if (this.isTaskCancelled()) { 42752eeb172SŁukasz Kosmaty return; 42852eeb172SŁukasz Kosmaty } 42952eeb172SŁukasz Kosmaty this.addSubscription(); 43052eeb172SŁukasz Kosmaty return await ExponentFileSystem.downloadResumableStartAsync(this.url, this.fileUri, this.uuid, this.options, this.resumeData); 4312307aaceSEvan Bacon } 4326b7802baSBartosz Kaszubowski /** 4336b7802baSBartosz Kaszubowski * Method to get the object which can be saved with `AsyncStorage` for future retrieval. 4346b7802baSBartosz Kaszubowski * @returns Returns object in shape of `DownloadPauseState` type. 4356b7802baSBartosz Kaszubowski */ 4362307aaceSEvan Bacon savable() { 4372307aaceSEvan Bacon return { 43852eeb172SŁukasz Kosmaty url: this.url, 43952eeb172SŁukasz Kosmaty fileUri: this.fileUri, 44052eeb172SŁukasz Kosmaty options: this.options, 44152eeb172SŁukasz Kosmaty resumeData: this.resumeData, 4422307aaceSEvan Bacon }; 4432307aaceSEvan Bacon } 4442307aaceSEvan Bacon} 445400de723SŁukasz Kosmatyconst baseReadAsStringAsync = readAsStringAsync; 446400de723SŁukasz Kosmatyconst baseWriteAsStringAsync = writeAsStringAsync; 447400de723SŁukasz Kosmatyconst baseDeleteAsync = deleteAsync; 448400de723SŁukasz Kosmatyconst baseMoveAsync = moveAsync; 449400de723SŁukasz Kosmatyconst baseCopyAsync = copyAsync; 450400de723SŁukasz Kosmaty/** 4516b7802baSBartosz Kaszubowski * The `StorageAccessFramework` is a namespace inside of the `expo-file-system` module, which encapsulates all functions which can be used with [SAF URIs](#saf-uri). 4526b7802baSBartosz Kaszubowski * You can read more about SAF in the [Android documentation](https://developer.android.com/guide/topics/providers/document-provider). 4536b7802baSBartosz Kaszubowski * 4546b7802baSBartosz Kaszubowski * @example 4556b7802baSBartosz Kaszubowski * # Basic Usage 4566b7802baSBartosz Kaszubowski * 4576b7802baSBartosz Kaszubowski * ```ts 4586b7802baSBartosz Kaszubowski * import { StorageAccessFramework } from 'expo-file-system'; 4596b7802baSBartosz Kaszubowski * 4606b7802baSBartosz Kaszubowski * // Requests permissions for external directory 4616b7802baSBartosz Kaszubowski * const permissions = await StorageAccessFramework.requestDirectoryPermissionsAsync(); 4626b7802baSBartosz Kaszubowski * 4636b7802baSBartosz Kaszubowski * if (permissions.granted) { 4646b7802baSBartosz Kaszubowski * // Gets SAF URI from response 4656b7802baSBartosz Kaszubowski * const uri = permissions.directoryUri; 4666b7802baSBartosz Kaszubowski * 4676b7802baSBartosz Kaszubowski * // Gets all files inside of selected directory 4686b7802baSBartosz Kaszubowski * const files = await StorageAccessFramework.readDirectoryAsync(uri); 4696b7802baSBartosz Kaszubowski * alert(`Files inside ${uri}:\n\n${JSON.stringify(files)}`); 4706b7802baSBartosz Kaszubowski * } 4716b7802baSBartosz Kaszubowski * ``` 4726b7802baSBartosz Kaszubowski * 4736b7802baSBartosz Kaszubowski * # Migrating an album 4746b7802baSBartosz Kaszubowski * 4756b7802baSBartosz Kaszubowski * ```ts 4766b7802baSBartosz Kaszubowski * import * as MediaLibrary from 'expo-media-library'; 4776b7802baSBartosz Kaszubowski * import * as FileSystem from 'expo-file-system'; 4786b7802baSBartosz Kaszubowski * const { StorageAccessFramework } = FileSystem; 4796b7802baSBartosz Kaszubowski * 4806b7802baSBartosz Kaszubowski * async function migrateAlbum(albumName: string) { 4816b7802baSBartosz Kaszubowski * // Gets SAF URI to the album 4826b7802baSBartosz Kaszubowski * const albumUri = StorageAccessFramework.getUriForDirectoryInRoot(albumName); 4836b7802baSBartosz Kaszubowski * 4846b7802baSBartosz Kaszubowski * // Requests permissions 4856b7802baSBartosz Kaszubowski * const permissions = await StorageAccessFramework.requestDirectoryPermissionsAsync(albumUri); 4866b7802baSBartosz Kaszubowski * if (!permissions.granted) { 4876b7802baSBartosz Kaszubowski * return; 4886b7802baSBartosz Kaszubowski * } 4896b7802baSBartosz Kaszubowski * 4906b7802baSBartosz Kaszubowski * const permittedUri = permissions.directoryUri; 4916b7802baSBartosz Kaszubowski * // Checks if users selected the correct folder 4926b7802baSBartosz Kaszubowski * if (!permittedUri.includes(albumName)) { 4936b7802baSBartosz Kaszubowski * return; 4946b7802baSBartosz Kaszubowski * } 4956b7802baSBartosz Kaszubowski * 4966b7802baSBartosz Kaszubowski * const mediaLibraryPermissions = await MediaLibrary.requestPermissionsAsync(); 4976b7802baSBartosz Kaszubowski * if (!mediaLibraryPermissions.granted) { 4986b7802baSBartosz Kaszubowski * return; 4996b7802baSBartosz Kaszubowski * } 5006b7802baSBartosz Kaszubowski * 5016b7802baSBartosz Kaszubowski * // Moves files from external storage to internal storage 5026b7802baSBartosz Kaszubowski * await StorageAccessFramework.moveAsync({ 5036b7802baSBartosz Kaszubowski * from: permittedUri, 5046b7802baSBartosz Kaszubowski * to: FileSystem.documentDirectory!, 5056b7802baSBartosz Kaszubowski * }); 5066b7802baSBartosz Kaszubowski * 5076b7802baSBartosz Kaszubowski * const outputDir = FileSystem.documentDirectory! + albumName; 5086b7802baSBartosz Kaszubowski * const migratedFiles = await FileSystem.readDirectoryAsync(outputDir); 5096b7802baSBartosz Kaszubowski * 5106b7802baSBartosz Kaszubowski * // Creates assets from local files 5116b7802baSBartosz Kaszubowski * const [newAlbumCreator, ...assets] = await Promise.all( 5126b7802baSBartosz Kaszubowski * migratedFiles.map<Promise<MediaLibrary.Asset>>( 5136b7802baSBartosz Kaszubowski * async fileName => await MediaLibrary.createAssetAsync(outputDir + '/' + fileName) 5146b7802baSBartosz Kaszubowski * ) 5156b7802baSBartosz Kaszubowski * ); 5166b7802baSBartosz Kaszubowski * 5176b7802baSBartosz Kaszubowski * // Album was empty 5186b7802baSBartosz Kaszubowski * if (!newAlbumCreator) { 5196b7802baSBartosz Kaszubowski * return; 5206b7802baSBartosz Kaszubowski * } 5216b7802baSBartosz Kaszubowski * 5226b7802baSBartosz Kaszubowski * // Creates a new album in the scoped directory 5236b7802baSBartosz Kaszubowski * const newAlbum = await MediaLibrary.createAlbumAsync(albumName, newAlbumCreator, false); 5246b7802baSBartosz Kaszubowski * if (assets.length) { 5256b7802baSBartosz Kaszubowski * await MediaLibrary.addAssetsToAlbumAsync(assets, newAlbum, false); 5266b7802baSBartosz Kaszubowski * } 5276b7802baSBartosz Kaszubowski * } 5286b7802baSBartosz Kaszubowski * ``` 5296b7802baSBartosz Kaszubowski * @platform Android 530400de723SŁukasz Kosmaty */ 531400de723SŁukasz Kosmatyexport var StorageAccessFramework; 532400de723SŁukasz Kosmaty(function (StorageAccessFramework) { 5336b7802baSBartosz Kaszubowski /** 5346b7802baSBartosz Kaszubowski * Gets a [SAF URI](#saf-uri) pointing to a folder in the Android root directory. You can use this function to get URI for 5356b7802baSBartosz Kaszubowski * `StorageAccessFramework.requestDirectoryPermissionsAsync()` when you trying to migrate an album. In that case, the name of the album is the folder name. 5366b7802baSBartosz Kaszubowski * @param folderName The name of the folder which is located in the Android root directory. 5376b7802baSBartosz Kaszubowski * @return Returns a [SAF URI](#saf-uri) to a folder. 5386b7802baSBartosz Kaszubowski */ 539400de723SŁukasz Kosmaty function getUriForDirectoryInRoot(folderName) { 540400de723SŁukasz Kosmaty return `content://com.android.externalstorage.documents/tree/primary:${folderName}/document/primary:${folderName}`; 541400de723SŁukasz Kosmaty } 542400de723SŁukasz Kosmaty StorageAccessFramework.getUriForDirectoryInRoot = getUriForDirectoryInRoot; 5436b7802baSBartosz Kaszubowski /** 5446b7802baSBartosz Kaszubowski * Allows users to select a specific directory, granting your app access to all of the files and sub-directories within that directory. 5456b7802baSBartosz Kaszubowski * @param initialFileUrl The [SAF URI](#saf-uri) of the directory that the file picker should display when it first loads. 5466b7802baSBartosz Kaszubowski * If URI is incorrect or points to a non-existing folder, it's ignored. 5476b7802baSBartosz Kaszubowski * @platform android 11+ 5486b7802baSBartosz Kaszubowski * @return Returns a Promise that resolves to `FileSystemRequestDirectoryPermissionsResult` object. 5496b7802baSBartosz Kaszubowski */ 550400de723SŁukasz Kosmaty async function requestDirectoryPermissionsAsync(initialFileUrl = null) { 551400de723SŁukasz Kosmaty if (!ExponentFileSystem.requestDirectoryPermissionsAsync) { 552400de723SŁukasz Kosmaty throw new UnavailabilityError('expo-file-system', 'StorageAccessFramework.requestDirectoryPermissionsAsync'); 553400de723SŁukasz Kosmaty } 554400de723SŁukasz Kosmaty return await ExponentFileSystem.requestDirectoryPermissionsAsync(initialFileUrl); 555400de723SŁukasz Kosmaty } 556400de723SŁukasz Kosmaty StorageAccessFramework.requestDirectoryPermissionsAsync = requestDirectoryPermissionsAsync; 5576b7802baSBartosz Kaszubowski /** 5586b7802baSBartosz Kaszubowski * Enumerate the contents of a directory. 5596b7802baSBartosz Kaszubowski * @param dirUri [SAF](#saf-uri) URI to the directory. 5606b7802baSBartosz Kaszubowski * @return A Promise that resolves to an array of strings, each containing the full [SAF URI](#saf-uri) of a file or directory contained in the directory at `fileUri`. 5616b7802baSBartosz Kaszubowski */ 562400de723SŁukasz Kosmaty async function readDirectoryAsync(dirUri) { 563400de723SŁukasz Kosmaty if (!ExponentFileSystem.readSAFDirectoryAsync) { 564400de723SŁukasz Kosmaty throw new UnavailabilityError('expo-file-system', 'StorageAccessFramework.readDirectoryAsync'); 565400de723SŁukasz Kosmaty } 566400de723SŁukasz Kosmaty return await ExponentFileSystem.readSAFDirectoryAsync(dirUri, {}); 567400de723SŁukasz Kosmaty } 568400de723SŁukasz Kosmaty StorageAccessFramework.readDirectoryAsync = readDirectoryAsync; 5696b7802baSBartosz Kaszubowski /** 5706b7802baSBartosz Kaszubowski * Creates a new empty directory. 5716b7802baSBartosz Kaszubowski * @param parentUri The [SAF](#saf-uri) URI to the parent directory. 5726b7802baSBartosz Kaszubowski * @param dirName The name of new directory. 5736b7802baSBartosz Kaszubowski * @return A Promise that resolves to a [SAF URI](#saf-uri) to the created directory. 5746b7802baSBartosz Kaszubowski */ 575400de723SŁukasz Kosmaty async function makeDirectoryAsync(parentUri, dirName) { 576400de723SŁukasz Kosmaty if (!ExponentFileSystem.makeSAFDirectoryAsync) { 577400de723SŁukasz Kosmaty throw new UnavailabilityError('expo-file-system', 'StorageAccessFramework.makeDirectoryAsync'); 578400de723SŁukasz Kosmaty } 579400de723SŁukasz Kosmaty return await ExponentFileSystem.makeSAFDirectoryAsync(parentUri, dirName); 580400de723SŁukasz Kosmaty } 581400de723SŁukasz Kosmaty StorageAccessFramework.makeDirectoryAsync = makeDirectoryAsync; 5826b7802baSBartosz Kaszubowski /** 5836b7802baSBartosz Kaszubowski * Creates a new empty file. 5846b7802baSBartosz Kaszubowski * @param parentUri The [SAF](#saf-uri) URI to the parent directory. 5856b7802baSBartosz Kaszubowski * @param fileName The name of new file **without the extension**. 5866b7802baSBartosz Kaszubowski * @param mimeType The MIME type of new file. 5876b7802baSBartosz Kaszubowski * @return A Promise that resolves to a [SAF URI](#saf-uri) to the created file. 5886b7802baSBartosz Kaszubowski */ 589400de723SŁukasz Kosmaty async function createFileAsync(parentUri, fileName, mimeType) { 590400de723SŁukasz Kosmaty if (!ExponentFileSystem.createSAFFileAsync) { 591400de723SŁukasz Kosmaty throw new UnavailabilityError('expo-file-system', 'StorageAccessFramework.createFileAsync'); 592400de723SŁukasz Kosmaty } 593400de723SŁukasz Kosmaty return await ExponentFileSystem.createSAFFileAsync(parentUri, fileName, mimeType); 594400de723SŁukasz Kosmaty } 595400de723SŁukasz Kosmaty StorageAccessFramework.createFileAsync = createFileAsync; 5966b7802baSBartosz Kaszubowski /** 5976b7802baSBartosz Kaszubowski * Alias for [`writeAsStringAsync`](#filesystemwriteasstringasyncfileuri-contents-options) method. 5986b7802baSBartosz Kaszubowski */ 599400de723SŁukasz Kosmaty StorageAccessFramework.writeAsStringAsync = baseWriteAsStringAsync; 6006b7802baSBartosz Kaszubowski /** 6016b7802baSBartosz Kaszubowski * Alias for [`readAsStringAsync`](#filesystemreadasstringasyncfileuri-options) method. 6026b7802baSBartosz Kaszubowski */ 603400de723SŁukasz Kosmaty StorageAccessFramework.readAsStringAsync = baseReadAsStringAsync; 6046b7802baSBartosz Kaszubowski /** 6056b7802baSBartosz Kaszubowski * Alias for [`deleteAsync`](#filesystemdeleteasyncfileuri-options) method. 6066b7802baSBartosz Kaszubowski */ 607400de723SŁukasz Kosmaty StorageAccessFramework.deleteAsync = baseDeleteAsync; 6086b7802baSBartosz Kaszubowski /** 6096b7802baSBartosz Kaszubowski * Alias for [`moveAsync`](#filesystemmoveasyncoptions) method. 6106b7802baSBartosz Kaszubowski */ 611400de723SŁukasz Kosmaty StorageAccessFramework.moveAsync = baseMoveAsync; 6126b7802baSBartosz Kaszubowski /** 6136b7802baSBartosz Kaszubowski * Alias fro [`copyAsync`](#filesystemcopyasyncoptions) method. 6146b7802baSBartosz Kaszubowski */ 615400de723SŁukasz Kosmaty StorageAccessFramework.copyAsync = baseCopyAsync; 616400de723SŁukasz Kosmaty})(StorageAccessFramework || (StorageAccessFramework = {})); 6172307aaceSEvan Bacon//# sourceMappingURL=FileSystem.js.map