@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 +1 -1
- package/dist/database/services/DatabaseNative.js +1 -1
- package/dist/device-info/BaseDeviceInfo.js +8 -0
- package/dist/device-info/DeviceInfo.types.d.ts +4 -0
- package/dist/local-storage/localStorage.d.ts +8 -8
- package/dist/local-storage/localStorage.js +16 -16
- package/dist/local-storage/services/StorageNative.d.ts +8 -8
- package/dist/local-storage/services/StorageNative.js +26 -17
- package/dist/local-storage/services/StorageWeb.d.ts +8 -8
- package/dist/local-storage/services/StorageWeb.js +8 -8
- package/package.json +7 -3
- package/test-app/filepath.ts +107 -0
- package/ts-core/ReactNativePlatformAdapter.ts +5 -1
- package/wrapper/fileService.ts +313 -0
package/BuildNo.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
R-0.000.
|
|
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;
|
|
@@ -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):
|
|
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):
|
|
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):
|
|
23
|
+
static removeItem(key: string): void;
|
|
24
24
|
/**
|
|
25
25
|
* Clear all items from storage
|
|
26
26
|
*/
|
|
27
|
-
static clear():
|
|
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():
|
|
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[]):
|
|
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]>):
|
|
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[]):
|
|
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
|
|
17
|
+
static getItem(key) {
|
|
18
18
|
try {
|
|
19
|
-
const value =
|
|
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
|
|
32
|
+
static setItem(key, value) {
|
|
33
33
|
try {
|
|
34
34
|
const jsonValue = JSON.stringify(value);
|
|
35
|
-
|
|
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
|
|
46
|
+
static removeItem(key) {
|
|
47
47
|
try {
|
|
48
|
-
|
|
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
|
|
58
|
+
static clear() {
|
|
59
59
|
try {
|
|
60
|
-
|
|
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
|
|
71
|
+
static getAllKeys() {
|
|
72
72
|
try {
|
|
73
|
-
return
|
|
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
|
|
85
|
+
static multiGet(keys) {
|
|
86
86
|
try {
|
|
87
|
-
const results =
|
|
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
|
|
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
|
-
|
|
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
|
|
119
|
+
static multiRemove(keys) {
|
|
120
120
|
try {
|
|
121
|
-
|
|
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):
|
|
3
|
-
setItem(key: string, value: string):
|
|
4
|
-
removeItem(key: string):
|
|
5
|
-
clear():
|
|
6
|
-
getAllKeys():
|
|
7
|
-
multiGet(keys: string[]):
|
|
8
|
-
multiSet(keyValuePairs: Array<[string, string]>):
|
|
9
|
-
multiRemove(keys: string[]):
|
|
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
|
|
1
|
+
import { createMMKV } from 'react-native-mmkv';
|
|
2
|
+
const storage = createMMKV();
|
|
2
3
|
export class StorageNative {
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
getItem(key) {
|
|
5
|
+
const val = storage.getString(key);
|
|
6
|
+
return val !== undefined ? val : null;
|
|
5
7
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
setItem(key, value) {
|
|
9
|
+
storage.set(key, value);
|
|
8
10
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
removeItem(key) {
|
|
12
|
+
storage.remove(key);
|
|
11
13
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
clear() {
|
|
15
|
+
storage.clearAll();
|
|
14
16
|
}
|
|
15
|
-
|
|
16
|
-
return
|
|
17
|
+
getAllKeys() {
|
|
18
|
+
return storage.getAllKeys();
|
|
17
19
|
}
|
|
18
|
-
|
|
19
|
-
return
|
|
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
|
-
|
|
22
|
-
|
|
26
|
+
multiSet(keyValuePairs) {
|
|
27
|
+
keyValuePairs.forEach(([key, value]) => {
|
|
28
|
+
storage.set(key, value);
|
|
29
|
+
});
|
|
23
30
|
}
|
|
24
|
-
|
|
25
|
-
|
|
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):
|
|
3
|
-
setItem(key: string, value: string):
|
|
4
|
-
removeItem(key: string):
|
|
5
|
-
clear():
|
|
6
|
-
getAllKeys():
|
|
7
|
-
multiGet(keys: string[]):
|
|
8
|
-
multiSet(keyValuePairs: Array<[string, string]>):
|
|
9
|
-
multiRemove(keys: string[]):
|
|
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
|
-
|
|
2
|
+
getItem(key) {
|
|
3
3
|
return localStorage.getItem(key);
|
|
4
4
|
}
|
|
5
|
-
|
|
5
|
+
setItem(key, value) {
|
|
6
6
|
localStorage.setItem(key, value);
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
removeItem(key) {
|
|
9
9
|
localStorage.removeItem(key);
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
clear() {
|
|
12
12
|
localStorage.clear();
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
getAllKeys() {
|
|
15
15
|
return Object.keys(localStorage);
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
multiGet(keys) {
|
|
18
18
|
return keys.map(key => [key, localStorage.getItem(key)]);
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
multiSet(keyValuePairs) {
|
|
21
21
|
keyValuePairs.forEach(([key, value]) => localStorage.setItem(key, value));
|
|
22
22
|
}
|
|
23
|
-
|
|
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.
|
|
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
|
-
"
|
|
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(
|
|
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
|
+
}
|