11import { decode as decodeBase64 , encode as encodeBase64 } from 'base64-arraybuffer' ;
22import { AttachmentData , EncodingType , LocalStorageAdapter } from '@powersync/common' ;
33
4- try {
5- var rnfs = require ( '@dr.pogodin/react-native-fs' ) ;
6- } catch ( e ) {
7- throw new Error ( `Could not resolve @dr.pogodin/react-native-fs.
8- To use the React Native File System attachment adapter please install @dr.pogodin/react-native-fs.` ) ;
9- }
4+ type ReactNativeFsModule = {
5+ DocumentDirectoryPath : string ;
6+ exists ( path : string ) : Promise < boolean > ;
7+ mkdir ( path : string ) : Promise < void > ;
8+ unlink ( path : string ) : Promise < void > ;
9+ writeFile ( path : string , contents : string , encoding ?: 'base64' | 'utf8' ) : Promise < void > ;
10+ readFile ( path : string , encoding ?: 'base64' | 'utf8' ) : Promise < string > ;
11+ } ;
1012
1113export class ReactNativeFileSystemStorageAdapter implements LocalStorageAdapter {
14+ private rnfs : ReactNativeFsModule ;
1215 private storageDirectory : string ;
1316
1417 constructor ( storageDirectory ?: string ) {
18+ let rnfs : ReactNativeFsModule ;
19+ try {
20+ rnfs = require ( '@dr.pogodin/react-native-fs' ) ;
21+ } catch ( e ) {
22+ throw new Error ( `Could not resolve @dr.pogodin/react-native-fs.
23+ To use the React Native File System attachment adapter please install @dr.pogodin/react-native-fs.` ) ;
24+ }
25+
26+ this . rnfs = rnfs ;
1527 // Default to a subdirectory in the document directory
16- this . storageDirectory = storageDirectory ?? `${ rnfs . DocumentDirectoryPath } /attachments/` ;
28+ this . storageDirectory = storageDirectory ?? `${ this . rnfs . DocumentDirectoryPath } /attachments/` ;
1729 }
1830
1931 async initialize ( ) : Promise < void > {
20- const dirExists = await rnfs . exists ( this . storageDirectory ) ;
32+ const dirExists = await this . rnfs . exists ( this . storageDirectory ) ;
2133 if ( ! dirExists ) {
22- await rnfs . mkdir ( this . storageDirectory ) ;
34+ await this . rnfs . mkdir ( this . storageDirectory ) ;
2335 }
2436 }
2537
2638 async clear ( ) : Promise < void > {
27- const dirExists = await rnfs . exists ( this . storageDirectory ) ;
39+ const dirExists = await this . rnfs . exists ( this . storageDirectory ) ;
2840 if ( dirExists ) {
29- await rnfs . unlink ( this . storageDirectory ) ;
41+ await this . rnfs . unlink ( this . storageDirectory ) ;
42+ await this . rnfs . mkdir ( this . storageDirectory ) ;
3043 }
3144 }
3245
3346 getLocalUri ( filename : string ) : string {
34- return `${ this . storageDirectory } ${ filename } ` ;
47+ const separator = this . storageDirectory . endsWith ( '/' ) ? '' : '/' ;
48+ return `${ this . storageDirectory } ${ separator } ${ filename } ` ;
3549 }
3650
3751 async saveFile (
@@ -43,7 +57,7 @@ export class ReactNativeFileSystemStorageAdapter implements LocalStorageAdapter
4357
4458 if ( typeof data === 'string' ) {
4559 const encoding = options ?. encoding ?? EncodingType . Base64 ;
46- await rnfs . writeFile ( filePath , data , encoding === EncodingType . Base64 ? 'base64' : 'utf8' ) ;
60+ await this . rnfs . writeFile ( filePath , data , encoding ) ;
4761
4862 // Calculate size based on encoding
4963 if ( encoding === EncodingType . Base64 ) {
@@ -54,7 +68,7 @@ export class ReactNativeFileSystemStorageAdapter implements LocalStorageAdapter
5468 }
5569 } else {
5670 const base64 = encodeBase64 ( data ) ;
57- await rnfs . WriteFile ( filePath , base64 , 'base64' ) ;
71+ await this . rnfs . writeFile ( filePath , base64 , 'base64' ) ;
5872 size = data . byteLength ;
5973 }
6074
@@ -64,7 +78,7 @@ export class ReactNativeFileSystemStorageAdapter implements LocalStorageAdapter
6478 async readFile ( filePath : string , options ?: { encoding ?: EncodingType ; mediaType ?: string } ) : Promise < ArrayBuffer > {
6579 const encoding = options ?. encoding ?? EncodingType . Base64 ;
6680
67- const content = await rnfs . readFile ( filePath , encoding === EncodingType . Base64 ? 'base64' : 'utf8' ) ;
81+ const content = await this . rnfs . readFile ( filePath , encoding ) ;
6882
6983 if ( encoding === EncodingType . UTF8 ) {
7084 const encoder = new TextEncoder ( ) ;
@@ -75,27 +89,34 @@ export class ReactNativeFileSystemStorageAdapter implements LocalStorageAdapter
7589 }
7690
7791 async deleteFile ( filePath : string , options ?: { filename ?: string } ) : Promise < void > {
78- await rnfs . unlink ( filePath ) . catch ( ( error : any ) => {
79- if ( error ?. message ?. includes ( 'not exist' ) || error ?. message ?. includes ( 'ENOENT' ) ) {
92+ try {
93+ await this . rnfs . unlink ( filePath ) ;
94+ } catch ( error : any ) {
95+ // Ignore file not found errors
96+ if ( error ?. code === 'ENOENT' || error ?. message ?. includes ( 'ENOENT' ) || error ?. message ?. includes ( 'not exist' ) ) {
8097 return ;
8198 }
8299 throw error ;
83- } ) ;
100+ }
84101 }
85102
86103 async fileExists ( filePath : string ) : Promise < boolean > {
87104 try {
88- return await rnfs . exists ( filePath ) ;
89- } catch {
90- return false ;
105+ return await this . rnfs . exists ( filePath ) ;
106+ } catch ( error : any ) {
107+ // Only return false for file-not-found errors
108+ if ( error ?. code === 'ENOENT' || error ?. message ?. includes ( 'ENOENT' ) ) {
109+ return false ;
110+ }
111+ throw error ;
91112 }
92113 }
93114
94115 async makeDir ( path : string ) : Promise < void > {
95- await rnfs . mkdir ( path ) ;
116+ await this . rnfs . mkdir ( path ) ;
96117 }
97118
98119 async rmDir ( path : string ) : Promise < void > {
99- await rnfs . unlink ( path ) ;
120+ await this . rnfs . unlink ( path ) ;
100121 }
101122}
0 commit comments