@unvired/react-native-unvired-sdk 0.0.26 → 0.0.28

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/BuildNo.txt CHANGED
@@ -1 +1 @@
1
- R-0.000.0026
1
+ R-0.000.0028
@@ -31,7 +31,7 @@ export class DatabaseNative {
31
31
  try {
32
32
  const db = this.getDatabase(options.dbName);
33
33
  // FIX: Await the result properly
34
- const res = await db.execute(options.query, options.params);
34
+ const res = await db.execute(options.query, options.params || []);
35
35
  let resultToReturn = [];
36
36
  // Cast to any to avoid TS error "Property '_array' does not exist on type 'never'"
37
37
  const rawRes = res;
@@ -24,6 +24,10 @@ export class BaseDeviceInfo {
24
24
  isMobile: Platform.OS === 'ios' || Platform.OS === 'android',
25
25
  manufacturer: DeviceInfo.getManufacturerSync(),
26
26
  uuid: DeviceInfo.getUniqueIdSync(),
27
+ deviceId: DeviceInfo.getUniqueIdSync(),
28
+ deviceName: DeviceInfo.getDeviceNameSync(),
29
+ brand: DeviceInfo.getBrand(),
30
+ deviceType: DeviceInfo.getDeviceType(),
27
31
  };
28
32
  this.cachedDeviceInfo = deviceInfo;
29
33
  return deviceInfo;
@@ -36,6 +40,10 @@ export class BaseDeviceInfo {
36
40
  model: 'Unknown',
37
41
  version: Platform.Version.toString(),
38
42
  isMobile: Platform.OS === 'ios' || Platform.OS === 'android',
43
+ deviceId: 'N/A',
44
+ deviceName: 'N/A',
45
+ brand: 'N/A',
46
+ deviceType: 'N/A',
39
47
  };
40
48
  this.cachedDeviceInfo = fallback;
41
49
  return fallback;
@@ -8,4 +8,8 @@ export interface IDeviceInfo {
8
8
  isMobile: boolean;
9
9
  manufacturer?: string;
10
10
  uuid?: string;
11
+ deviceId?: string;
12
+ deviceName?: string;
13
+ brand?: string;
14
+ deviceType?: string;
11
15
  }
@@ -9,41 +9,41 @@ export declare class LocalStorage {
9
9
  * @param key - The key to retrieve
10
10
  * @returns The parsed value or null if not found
11
11
  */
12
- static getItem<T = any>(key: string): Promise<T | null>;
12
+ static getItem<T = any>(key: string): T | null;
13
13
  /**
14
14
  * Set an item in storage
15
15
  * @param key - The key to store the value under
16
16
  * @param value - The value to store (will be JSON stringified)
17
17
  */
18
- static setItem(key: string, value: any): Promise<void>;
18
+ static setItem(key: string, value: any): void;
19
19
  /**
20
20
  * Remove an item from storage
21
21
  * @param key - The key to remove
22
22
  */
23
- static removeItem(key: string): Promise<void>;
23
+ static removeItem(key: string): void;
24
24
  /**
25
25
  * Clear all items from storage
26
26
  */
27
- static clear(): Promise<void>;
27
+ static clear(): void;
28
28
  /**
29
29
  * Get all keys from storage
30
30
  * @returns Array of all keys
31
31
  */
32
- static getAllKeys(): Promise<readonly string[]>;
32
+ static getAllKeys(): readonly string[];
33
33
  /**
34
34
  * Get multiple items from storage
35
35
  * @param keys - Array of keys to retrieve
36
36
  * @returns Array of [key, value] pairs
37
37
  */
38
- static multiGet(keys: string[]): Promise<Array<[string, any]>>;
38
+ static multiGet(keys: string[]): Array<[string, any]>;
39
39
  /**
40
40
  * Set multiple items in storage
41
41
  * @param keyValuePairs - Array of [key, value] pairs to store
42
42
  */
43
- static multiSet(keyValuePairs: Array<[string, any]>): Promise<void>;
43
+ static multiSet(keyValuePairs: Array<[string, any]>): void;
44
44
  /**
45
45
  * Remove multiple items from storage
46
46
  * @param keys - Array of keys to remove
47
47
  */
48
- static multiRemove(keys: string[]): Promise<void>;
48
+ static multiRemove(keys: string[]): void;
49
49
  }
@@ -14,9 +14,9 @@ export class LocalStorage {
14
14
  * @param key - The key to retrieve
15
15
  * @returns The parsed value or null if not found
16
16
  */
17
- static async getItem(key) {
17
+ static getItem(key) {
18
18
  try {
19
- const value = await storageImpl.getItem(key);
19
+ const value = storageImpl.getItem(key);
20
20
  return value ? JSON.parse(value) : null;
21
21
  }
22
22
  catch (error) {
@@ -29,10 +29,10 @@ export class LocalStorage {
29
29
  * @param key - The key to store the value under
30
30
  * @param value - The value to store (will be JSON stringified)
31
31
  */
32
- static async setItem(key, value) {
32
+ static setItem(key, value) {
33
33
  try {
34
34
  const jsonValue = JSON.stringify(value);
35
- await storageImpl.setItem(key, jsonValue);
35
+ storageImpl.setItem(key, jsonValue);
36
36
  }
37
37
  catch (error) {
38
38
  console.error(`Error setting item with key "${key}":`, error);
@@ -43,9 +43,9 @@ export class LocalStorage {
43
43
  * Remove an item from storage
44
44
  * @param key - The key to remove
45
45
  */
46
- static async removeItem(key) {
46
+ static removeItem(key) {
47
47
  try {
48
- await storageImpl.removeItem(key);
48
+ storageImpl.removeItem(key);
49
49
  }
50
50
  catch (error) {
51
51
  console.error(`Error removing item with key "${key}":`, error);
@@ -55,9 +55,9 @@ export class LocalStorage {
55
55
  /**
56
56
  * Clear all items from storage
57
57
  */
58
- static async clear() {
58
+ static clear() {
59
59
  try {
60
- await storageImpl.clear();
60
+ storageImpl.clear();
61
61
  }
62
62
  catch (error) {
63
63
  console.error('Error clearing storage:', error);
@@ -68,9 +68,9 @@ export class LocalStorage {
68
68
  * Get all keys from storage
69
69
  * @returns Array of all keys
70
70
  */
71
- static async getAllKeys() {
71
+ static getAllKeys() {
72
72
  try {
73
- return await storageImpl.getAllKeys();
73
+ return storageImpl.getAllKeys();
74
74
  }
75
75
  catch (error) {
76
76
  console.error('Error getting all keys:', error);
@@ -82,9 +82,9 @@ export class LocalStorage {
82
82
  * @param keys - Array of keys to retrieve
83
83
  * @returns Array of [key, value] pairs
84
84
  */
85
- static async multiGet(keys) {
85
+ static multiGet(keys) {
86
86
  try {
87
- const results = await storageImpl.multiGet(keys);
87
+ const results = storageImpl.multiGet(keys);
88
88
  return results.map(([key, value]) => [
89
89
  key,
90
90
  value ? JSON.parse(value) : null
@@ -99,13 +99,13 @@ export class LocalStorage {
99
99
  * Set multiple items in storage
100
100
  * @param keyValuePairs - Array of [key, value] pairs to store
101
101
  */
102
- static async multiSet(keyValuePairs) {
102
+ static multiSet(keyValuePairs) {
103
103
  try {
104
104
  const jsonPairs = keyValuePairs.map(([key, value]) => [
105
105
  key,
106
106
  JSON.stringify(value)
107
107
  ]);
108
- await storageImpl.multiSet(jsonPairs);
108
+ storageImpl.multiSet(jsonPairs);
109
109
  }
110
110
  catch (error) {
111
111
  console.error('Error setting multiple items:', error);
@@ -116,9 +116,9 @@ export class LocalStorage {
116
116
  * Remove multiple items from storage
117
117
  * @param keys - Array of keys to remove
118
118
  */
119
- static async multiRemove(keys) {
119
+ static multiRemove(keys) {
120
120
  try {
121
- await storageImpl.multiRemove(keys);
121
+ storageImpl.multiRemove(keys);
122
122
  }
123
123
  catch (error) {
124
124
  console.error('Error removing multiple items:', error);
@@ -1,10 +1,10 @@
1
1
  export declare class StorageNative {
2
- getItem(key: string): Promise<string | null>;
3
- setItem(key: string, value: string): Promise<void>;
4
- removeItem(key: string): Promise<void>;
5
- clear(): Promise<void>;
6
- getAllKeys(): Promise<readonly string[]>;
7
- multiGet(keys: string[]): Promise<readonly [string, string | null][]>;
8
- multiSet(keyValuePairs: Array<[string, string]>): Promise<void>;
9
- multiRemove(keys: string[]): Promise<void>;
2
+ getItem(key: string): string | null;
3
+ setItem(key: string, value: string): void;
4
+ removeItem(key: string): void;
5
+ clear(): void;
6
+ getAllKeys(): readonly string[];
7
+ multiGet(keys: string[]): readonly [string, string | null][];
8
+ multiSet(keyValuePairs: Array<[string, string]>): void;
9
+ multiRemove(keys: string[]): void;
10
10
  }
@@ -1,27 +1,36 @@
1
- import AsyncStorage from '@react-native-async-storage/async-storage';
1
+ import { createMMKV } from 'react-native-mmkv';
2
+ const storage = createMMKV();
2
3
  export class StorageNative {
3
- async getItem(key) {
4
- return await AsyncStorage.getItem(key);
4
+ getItem(key) {
5
+ const val = storage.getString(key);
6
+ return val !== undefined ? val : null;
5
7
  }
6
- async setItem(key, value) {
7
- await AsyncStorage.setItem(key, value);
8
+ setItem(key, value) {
9
+ storage.set(key, value);
8
10
  }
9
- async removeItem(key) {
10
- await AsyncStorage.removeItem(key);
11
+ removeItem(key) {
12
+ storage.remove(key);
11
13
  }
12
- async clear() {
13
- await AsyncStorage.clear();
14
+ clear() {
15
+ storage.clearAll();
14
16
  }
15
- async getAllKeys() {
16
- return await AsyncStorage.getAllKeys();
17
+ getAllKeys() {
18
+ return storage.getAllKeys();
17
19
  }
18
- async multiGet(keys) {
19
- return await AsyncStorage.multiGet(keys);
20
+ multiGet(keys) {
21
+ return keys.map(key => {
22
+ const val = storage.getString(key);
23
+ return [key, val !== undefined ? val : null];
24
+ });
20
25
  }
21
- async multiSet(keyValuePairs) {
22
- await AsyncStorage.multiSet(keyValuePairs);
26
+ multiSet(keyValuePairs) {
27
+ keyValuePairs.forEach(([key, value]) => {
28
+ storage.set(key, value);
29
+ });
23
30
  }
24
- async multiRemove(keys) {
25
- await AsyncStorage.multiRemove(keys);
31
+ multiRemove(keys) {
32
+ keys.forEach(key => {
33
+ storage.remove(key);
34
+ });
26
35
  }
27
36
  }
@@ -1,10 +1,10 @@
1
1
  export declare class StorageWeb {
2
- getItem(key: string): Promise<string | null>;
3
- setItem(key: string, value: string): Promise<void>;
4
- removeItem(key: string): Promise<void>;
5
- clear(): Promise<void>;
6
- getAllKeys(): Promise<readonly string[]>;
7
- multiGet(keys: string[]): Promise<readonly [string, string | null][]>;
8
- multiSet(keyValuePairs: Array<[string, string]>): Promise<void>;
9
- multiRemove(keys: string[]): Promise<void>;
2
+ getItem(key: string): string | null;
3
+ setItem(key: string, value: string): void;
4
+ removeItem(key: string): void;
5
+ clear(): void;
6
+ getAllKeys(): readonly string[];
7
+ multiGet(keys: string[]): readonly [string, string | null][];
8
+ multiSet(keyValuePairs: Array<[string, string]>): void;
9
+ multiRemove(keys: string[]): void;
10
10
  }
@@ -1,26 +1,26 @@
1
1
  export class StorageWeb {
2
- async getItem(key) {
2
+ getItem(key) {
3
3
  return localStorage.getItem(key);
4
4
  }
5
- async setItem(key, value) {
5
+ setItem(key, value) {
6
6
  localStorage.setItem(key, value);
7
7
  }
8
- async removeItem(key) {
8
+ removeItem(key) {
9
9
  localStorage.removeItem(key);
10
10
  }
11
- async clear() {
11
+ clear() {
12
12
  localStorage.clear();
13
13
  }
14
- async getAllKeys() {
14
+ getAllKeys() {
15
15
  return Object.keys(localStorage);
16
16
  }
17
- async multiGet(keys) {
17
+ multiGet(keys) {
18
18
  return keys.map(key => [key, localStorage.getItem(key)]);
19
19
  }
20
- async multiSet(keyValuePairs) {
20
+ multiSet(keyValuePairs) {
21
21
  keyValuePairs.forEach(([key, value]) => localStorage.setItem(key, value));
22
22
  }
23
- async multiRemove(keys) {
23
+ multiRemove(keys) {
24
24
  keys.forEach(key => localStorage.removeItem(key));
25
25
  }
26
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unvired/react-native-unvired-sdk",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "description": "Unvired SDK for React Native with logging, database, notifications, and file system support",
5
5
  "main": "dist/main.js",
6
6
  "types": "dist/main.d.ts",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "peerDependencies": {
15
15
  "@op-engineering/op-sqlite": "^15.2.5",
16
- "@react-native-async-storage/async-storage": "^2.2.0",
16
+ "react-native-mmkv": "*",
17
17
  "@react-native-firebase/messaging": "^21.8.1",
18
18
  "react": ">=18",
19
19
  "react-native": ">=0.73",
@@ -34,6 +34,9 @@
34
34
  "@react-native-async-storage/async-storage": {
35
35
  "optional": true
36
36
  },
37
+ "react-native-mmkv": {
38
+ "optional": true
39
+ },
37
40
  "react-native-device-info": {
38
41
  "optional": true
39
42
  },
@@ -47,6 +50,7 @@
47
50
  "devDependencies": {
48
51
  "@op-engineering/op-sqlite": "^15.2.5",
49
52
  "@react-native-async-storage/async-storage": "^2.2.0",
53
+ "react-native-mmkv": "^4.3.2",
50
54
  "@react-native-firebase/messaging": "^21.8.1",
51
55
  "@types/pako": "^2.0.4",
52
56
  "@types/react": ">=18",
@@ -66,4 +70,4 @@
66
70
  "publishConfig": {
67
71
  "access": "public"
68
72
  }
69
- }
73
+ }
@@ -0,0 +1,107 @@
1
+ import UnviredWrapper from '@unvired/react-native-wrapper-sdk';
2
+
3
+ const wrapper = new UnviredWrapper();
4
+ const fileServiceRaw = wrapper.file();
5
+
6
+ // Helper to convert ArrayBuffer to string (Native JS - No Buffer Dependency)
7
+ function arrayBufferToString(buffer: ArrayBuffer): string {
8
+ // Handling small to medium files. For very large files, chunking is needed to avoid stack overflow.
9
+ return String.fromCharCode.apply(null, new Uint8Array(buffer) as any);
10
+ }
11
+
12
+ class SDKFileService {
13
+
14
+ // Delegate standard methods
15
+ getDocumentDirectoryPath() {
16
+ return fileServiceRaw.getDocumentDirectory();
17
+ }
18
+
19
+ async createFile(fileName: string, content: string): Promise<string> {
20
+ const dir = fileServiceRaw.getDocumentDirectory();
21
+
22
+ // Ensure dir ends with slash
23
+ const path = (dir.endsWith('/') ? dir : dir + '/') + fileName;
24
+
25
+ // FIX: React Native Blob implementation has issues with direct ArrayBuffer views in some versions.
26
+ // Passing string directly to writeExternalFile allows the underlying Blob([content]) to work
27
+ // because Blob([string]) is supported.
28
+ const data = content;
29
+
30
+ console.log(`[SDKFileService] Creating file ${fileName} at ${path}`);
31
+ await fileServiceRaw.writeExternalFile(dir, fileName, data as any);
32
+ return path;
33
+ }
34
+
35
+ async readFile(fileName: string): Promise<string> {
36
+ let path = fileName;
37
+ // If not absolute path, prepend doc dir
38
+ if (!fileName.startsWith('/') && !fileName.startsWith('file://')) {
39
+ const dir = fileServiceRaw.getDocumentDirectory();
40
+ path = (dir.endsWith('/') ? dir : dir + '/') + fileName;
41
+ }
42
+
43
+ // Cleaning file:// prefix if present
44
+ if (path.startsWith('file://')) {
45
+ path = path.replace('file://', '');
46
+ }
47
+
48
+ console.log(`[SDKFileService] Reading file: ${path}`);
49
+ const data = await fileServiceRaw.readExternalFile(path);
50
+ return arrayBufferToString(data);
51
+ }
52
+
53
+ async deleteFile(fileName: string): Promise<void> {
54
+ let path = fileName;
55
+ if (!fileName.startsWith('/') && !fileName.startsWith('file://')) {
56
+ const dir = fileServiceRaw.getDocumentDirectory();
57
+ path = (dir.endsWith('/') ? dir : dir + '/') + fileName;
58
+ }
59
+
60
+ // Cleaning file:// prefix if present
61
+ if (path.startsWith('file://')) {
62
+ path = path.replace('file://', '');
63
+ }
64
+
65
+ console.log(`[SDKFileService] Deleting file: ${path}`);
66
+ await fileServiceRaw.deleteExternalFile(path);
67
+ }
68
+
69
+ async listFiles(): Promise<any[]> {
70
+ const dir = fileServiceRaw.getDocumentDirectory();
71
+ console.log(`[SDKFileService] Listing files in: ${dir}`);
72
+
73
+ // Use resolveLocalFileSystemURL to get DirectoryEntry
74
+ let dirEntry;
75
+ try {
76
+ dirEntry = await fileServiceRaw.resolveLocalFileSystemURL(dir);
77
+ } catch (e) {
78
+ console.error('[SDKFileService] Failed to resolve directory:', e);
79
+ return [];
80
+ }
81
+
82
+ return new Promise((resolve, reject) => {
83
+ try {
84
+ const reader = dirEntry.createReader();
85
+ reader.readEntries((entries: any[]) => {
86
+ console.log(`[SDKFileService] Found ${entries.length} entries`);
87
+ const mapped = entries.map(e => ({
88
+ uri: e.nativeURL || e.fullPath,
89
+ name: e.name,
90
+ isDirectory: e.isDirectory,
91
+ size: 0,
92
+ modificationTime: Date.now() / 1000
93
+ }));
94
+ resolve(mapped);
95
+ }, (err: any) => {
96
+ console.error('[SDKFileService] Failed to list files (readEntries):', err);
97
+ resolve([]); // Don't crash UI
98
+ });
99
+ } catch (e) {
100
+ console.error('[SDKFileService] Exception in listFiles:', e);
101
+ resolve([]);
102
+ }
103
+ });
104
+ }
105
+ }
106
+
107
+ export default new SDKFileService();
@@ -38,7 +38,11 @@ export class ReactNativePlatformAdapter implements PlatformInterface {
38
38
  DatabaseManager.getDatabaseAdapter().create({ name: options.userId }, successCallback, errorCallback);
39
39
  },
40
40
  execute: (options: any, successCallback, errorCallback) => {
41
- DatabaseManager.getDatabaseAdapter().execute(options, successCallback, errorCallback);
41
+ DatabaseManager.getDatabaseAdapter().execute({
42
+ dbName: options.userId,
43
+ query: options.query,
44
+ params: options.params
45
+ }, successCallback, errorCallback);
42
46
  },
43
47
  executeStatementOnPath: (dbPath, sqlQuery, callback) => {
44
48
  DatabaseManager.getDatabaseAdapter().executeStatementOnPath(dbPath, sqlQuery, callback);
@@ -0,0 +1,313 @@
1
+ import { PlatformManager } from '@unvired/unvired-ts-core-sdk';
2
+
3
+ export interface IDirectoryReader {
4
+ readEntries(successCallback: (entries: IFileEntry[]) => void, errorCallback: (error: any) => void): void;
5
+ }
6
+
7
+ export interface IFileEntry {
8
+ fullPath: string;
9
+ nativeURL: string;
10
+ isDirectory?: boolean;
11
+ remove(callback: () => void, errorCallback: (error: any) => void): void;
12
+ removeRecursively(callback: () => void, errorCallback: (error: any) => void): void;
13
+ createReader(): IDirectoryReader;
14
+ getDirectory?(path: string, options: { create: boolean }, callback: (entry: IFileEntry) => void, errorCallback: (error: any) => void): void;
15
+ getFile?(path: string, options: { create: boolean }, callback: (entry: IFileEntry) => void, errorCallback: (error: any) => void): void;
16
+ file?(callback: (file: File) => void, errorCallback: (error: any) => void): void;
17
+ createWriter?(callback: (writer: any) => void, errorCallback: (error: any) => void): void;
18
+ }
19
+
20
+ export class FileService {
21
+
22
+ getDocumentDirectory(): string {
23
+ // @ts-ignore
24
+ return PlatformManager.getInstance().getPlatformAdapter().getDocumentDirectory();
25
+ }
26
+
27
+ resolveLocalFileSystemURL(url: string): Promise<IFileEntry> {
28
+ // @ts-ignore
29
+ return PlatformManager.getInstance().getPlatformAdapter().resolveLocalFileSystemURL(url);
30
+ }
31
+
32
+ async getFolderBasedOnUserId(userId: string): Promise<string> {
33
+ // @ts-ignore
34
+ return await PlatformManager.getInstance().getPlatformAdapter().getFolderBasedOnUserId(userId);
35
+ }
36
+
37
+ async deleteUserFolder(userId: string): Promise<void> {
38
+ // @ts-ignore
39
+ await PlatformManager.getInstance().getPlatformAdapter().deleteUserFolder(userId);
40
+ }
41
+
42
+ /**
43
+ * Reads an external file as ArrayBuffer using IFileEntry API
44
+ * @param filePath Absolute path to the file
45
+ */
46
+ async readExternalFile(filePath: string): Promise<ArrayBuffer> {
47
+ // Get the file entry
48
+ const fileEntry = await this.resolveLocalFileSystemURL(filePath);
49
+
50
+ return new Promise((resolve, reject) => {
51
+ // Use the file() method to read the file
52
+ if (!fileEntry.file) {
53
+ reject(new Error('file() method not available on entry'));
54
+ return;
55
+ }
56
+
57
+ fileEntry.file(
58
+ async (fileMetadata: any) => {
59
+ try {
60
+ // Read the file using react-native-fs
61
+ const RNFS = await import('react-native-fs');
62
+ const content = await RNFS.readFile(fileMetadata.path, 'utf8');
63
+
64
+ // Convert string to ArrayBuffer
65
+ const encoder = new TextEncoder();
66
+ resolve(encoder.encode(content).buffer);
67
+ } catch (error) {
68
+ reject(error);
69
+ }
70
+ },
71
+ (error: any) => {
72
+ reject(error);
73
+ }
74
+ );
75
+ });
76
+ }
77
+
78
+ /**
79
+ * Writes data to an external file using IFileEntry API
80
+ * @param filePath Parent directory path
81
+ * @param fileName File name
82
+ * @param data Data to write (ArrayBuffer or string)
83
+ */
84
+ async writeExternalFile(filePath: string, fileName: string, data: ArrayBuffer | string): Promise<void> {
85
+ // Convert data to string if it's ArrayBuffer
86
+ let content: string;
87
+ if (data instanceof ArrayBuffer) {
88
+ const decoder = new TextDecoder();
89
+ content = decoder.decode(data);
90
+ } else {
91
+ content = data;
92
+ }
93
+
94
+ // Get the directory entry
95
+ const dirEntry = await this.resolveLocalFileSystemURL(filePath);
96
+
97
+ return new Promise((resolve, reject) => {
98
+ // Get or create the file
99
+ if (!dirEntry.getFile) {
100
+ reject(new Error('getFile() method not available on directory entry'));
101
+ return;
102
+ }
103
+
104
+ dirEntry.getFile(
105
+ fileName,
106
+ { create: true },
107
+ (fileEntry: IFileEntry) => {
108
+ // Create a writer
109
+ if (!fileEntry.createWriter) {
110
+ reject(new Error('createWriter() method not available on file entry'));
111
+ return;
112
+ }
113
+
114
+ fileEntry.createWriter(
115
+ (writer: any) => {
116
+ writer.onwriteend = () => {
117
+ resolve();
118
+ };
119
+ writer.onerror = (error: any) => {
120
+ reject(error);
121
+ };
122
+
123
+ // Write the content
124
+ writer.write(content);
125
+ },
126
+ (error: any) => {
127
+ reject(error);
128
+ }
129
+ );
130
+ },
131
+ (error: any) => {
132
+ reject(error);
133
+ }
134
+ );
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Deletes an external file using IFileEntry API
140
+ * @param filePath Absolute path to the file
141
+ */
142
+ async deleteExternalFile(filePath: string): Promise<void> {
143
+ const fileEntry = await this.resolveLocalFileSystemURL(filePath);
144
+
145
+ return new Promise((resolve, reject) => {
146
+ fileEntry.remove(
147
+ () => resolve(),
148
+ (error: any) => reject(error)
149
+ );
150
+ });
151
+ }
152
+
153
+ /**
154
+ * Checks if a file exists using IFileEntry API
155
+ * @param filePath Absolute path to the file
156
+ */
157
+ async fileExists(filePath: string): Promise<boolean> {
158
+ try {
159
+ await this.resolveLocalFileSystemURL(filePath);
160
+ return true;
161
+ } catch (error) {
162
+ return false;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Creates a directory
168
+ * @param dirPath Parent directory path
169
+ * @param dirName Directory name to create
170
+ */
171
+ async createDirectory(dirPath: string, dirName: string): Promise<IFileEntry> {
172
+ const parentEntry = await this.resolveLocalFileSystemURL(dirPath);
173
+
174
+ return new Promise((resolve, reject) => {
175
+ if (!parentEntry.getDirectory) {
176
+ reject(new Error('getDirectory() method not available on entry'));
177
+ return;
178
+ }
179
+
180
+ parentEntry.getDirectory(
181
+ dirName,
182
+ { create: true },
183
+ (dirEntry: IFileEntry) => resolve(dirEntry),
184
+ (error: any) => reject(error)
185
+ );
186
+ });
187
+ }
188
+
189
+ /**
190
+ * Lists files and directories in a directory
191
+ * @param dirPath Directory path to list
192
+ */
193
+ async listDirectory(dirPath: string): Promise<IFileEntry[]> {
194
+ const dirEntry = await this.resolveLocalFileSystemURL(dirPath);
195
+
196
+ return new Promise((resolve, reject) => {
197
+ const reader = dirEntry.createReader();
198
+ reader.readEntries(
199
+ (entries: IFileEntry[]) => resolve(entries),
200
+ (error: any) => reject(error)
201
+ );
202
+ });
203
+ }
204
+
205
+ /**
206
+ * Deletes a directory and all its contents
207
+ * @param dirPath Directory path to delete
208
+ */
209
+ async deleteDirectory(dirPath: string): Promise<void> {
210
+ const dirEntry = await this.resolveLocalFileSystemURL(dirPath);
211
+
212
+ return new Promise((resolve, reject) => {
213
+ dirEntry.removeRecursively(
214
+ () => resolve(),
215
+ (error: any) => reject(error)
216
+ );
217
+ });
218
+ }
219
+
220
+ /**
221
+ * Copies a file
222
+ * @param sourcePath Source file path
223
+ * @param destDir Destination directory path
224
+ * @param newName New file name (optional, keeps original name if not provided)
225
+ */
226
+ async copyFile(sourcePath: string, destDir: string, newName?: string): Promise<void> {
227
+ // Read source file
228
+ const content = await this.readExternalFile(sourcePath);
229
+
230
+ // Get source file name if newName not provided
231
+ const fileName = newName || sourcePath.split('/').pop() || 'file';
232
+
233
+ // Write to destination
234
+ await this.writeExternalFile(destDir, fileName, content);
235
+ }
236
+
237
+ /**
238
+ * Moves/renames a file
239
+ * @param sourcePath Source file path
240
+ * @param destDir Destination directory path
241
+ * @param newName New file name (optional, keeps original name if not provided)
242
+ */
243
+ async moveFile(sourcePath: string, destDir: string, newName?: string): Promise<void> {
244
+ // Copy file to destination
245
+ await this.copyFile(sourcePath, destDir, newName);
246
+
247
+ // Delete source file
248
+ await this.deleteExternalFile(sourcePath);
249
+ }
250
+
251
+ /**
252
+ * Gets file information (size, modification date, etc.)
253
+ * @param filePath File path
254
+ */
255
+ async getFileInfo(filePath: string): Promise<any> {
256
+ const fileEntry = await this.resolveLocalFileSystemURL(filePath);
257
+
258
+ return new Promise((resolve, reject) => {
259
+ if (!fileEntry.file) {
260
+ reject(new Error('file() method not available on entry'));
261
+ return;
262
+ }
263
+
264
+ fileEntry.file(
265
+ (fileMetadata: any) => resolve(fileMetadata),
266
+ (error: any) => reject(error)
267
+ );
268
+ });
269
+ }
270
+
271
+ /**
272
+ * Appends data to an existing file
273
+ * @param filePath File path
274
+ * @param data Data to append
275
+ */
276
+ async appendToFile(filePath: string, data: ArrayBuffer | string): Promise<void> {
277
+ // Convert data to string if it's ArrayBuffer
278
+ let content: string;
279
+ if (data instanceof ArrayBuffer) {
280
+ const decoder = new TextDecoder();
281
+ content = decoder.decode(data);
282
+ } else {
283
+ content = data;
284
+ }
285
+
286
+ const fileEntry = await this.resolveLocalFileSystemURL(filePath);
287
+
288
+ return new Promise((resolve, reject) => {
289
+ if (!fileEntry.createWriter) {
290
+ reject(new Error('createWriter() method not available on file entry'));
291
+ return;
292
+ }
293
+
294
+ fileEntry.createWriter(
295
+ (writer: any) => {
296
+ writer.onwriteend = () => {
297
+ resolve();
298
+ };
299
+ writer.onerror = (error: any) => {
300
+ reject(error);
301
+ };
302
+
303
+ // Append the content
304
+ writer.append(content);
305
+ },
306
+ (error: any) => {
307
+ reject(error);
308
+ }
309
+ );
310
+ });
311
+ }
312
+
313
+ }