@unvired/react-native-unvired-sdk 0.0.45 → 0.0.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/BuildNo.txt +1 -1
  2. package/dist/database/DatabaseManager.d.ts +10 -1
  3. package/dist/database/DatabaseManager.js +22 -2
  4. package/dist/database/DatabaseManager.web.d.ts +7 -0
  5. package/dist/database/DatabaseManager.web.js +8 -1
  6. package/dist/database/index.d.ts +3 -0
  7. package/dist/database/index.js +3 -0
  8. package/dist/database/services/DatabaseExpo.d.ts +14 -0
  9. package/dist/database/services/DatabaseExpo.js +284 -0
  10. package/dist/database/services/DatabaseNative.d.ts +2 -0
  11. package/dist/database/services/DatabaseNative.js +134 -41
  12. package/dist/database/services/DatabaseWeb.d.ts +1 -0
  13. package/dist/database/services/DatabaseWeb.js +138 -34
  14. package/dist/device-info/services/DeviceInfoNative.js +50 -3
  15. package/dist/file-system/FileSystem.d.ts +12 -3
  16. package/dist/file-system/FileSystem.js +34 -6
  17. package/dist/file-system/index.d.ts +4 -1
  18. package/dist/file-system/index.js +3 -0
  19. package/dist/file-system/services/FileSystemExpo.d.ts +22 -0
  20. package/dist/file-system/services/FileSystemExpo.js +336 -0
  21. package/dist/file-system/services/FileSystemNative.d.ts +24 -3
  22. package/dist/file-system/services/FileSystemNative.js +127 -36
  23. package/dist/file-system/services/FileSystemWeb.d.ts +1 -1
  24. package/dist/file-system/services/FileSystemWeb.js +86 -94
  25. package/dist/local-storage/services/StorageNative.d.ts +1 -0
  26. package/dist/local-storage/services/StorageNative.js +51 -12
  27. package/dist/logger/BaseLogger.js +4 -0
  28. package/dist/main.d.ts +3 -3
  29. package/dist/main.js +2 -2
  30. package/dist/push-notification/services/PushNotificationNative.js +182 -68
  31. package/package.json +21 -1
@@ -1,16 +1,26 @@
1
- import * as RNFS from 'react-native-fs';
1
+ let RNFS = null;
2
+ try {
3
+ RNFS = require('react-native-fs');
4
+ }
5
+ catch (e) {
6
+ RNFS = null;
7
+ }
2
8
  /**
3
9
  * DirectoryReader implementation for React Native
4
10
  * Wraps RNFS.readDir to match the Cordova DirectoryReader interface
5
11
  */
6
12
  class RNDirectoryReader {
7
13
  constructor(dirPath) {
8
- this.dirPath = dirPath;
14
+ this.dirPath = dirPath.replace(/\/+$/, '');
9
15
  }
10
16
  readEntries(callback, errorCallback) {
17
+ if (!RNFS) {
18
+ errorCallback(new Error('react-native-fs is not available'));
19
+ return;
20
+ }
11
21
  RNFS.readDir(this.dirPath)
12
- .then(items => {
13
- const entries = items.map(item => new RNFileEntry(item.path, item.isDirectory()));
22
+ .then((items) => {
23
+ const entries = items.map((item) => new RNFileEntry(item.path, item.isDirectory()));
14
24
  callback(entries);
15
25
  })
16
26
  .catch(errorCallback);
@@ -22,18 +32,25 @@ class RNDirectoryReader {
22
32
  */
23
33
  class RNFileEntry {
24
34
  constructor(path, isDirectory = false) {
25
- this.fullPath = path;
26
- this.nativeURL = `file://${path}`;
35
+ const cleanPath = path.replace(/\/+$/, '');
27
36
  this.isDirectory = isDirectory;
28
37
  this.isFile = !isDirectory;
29
- this.name = path.split('/').pop() || '';
38
+ // Cordova spec: directories must end with trailing slash in fullPath and nativeURL
39
+ this.fullPath = isDirectory ? `${cleanPath}/` : cleanPath;
40
+ this.nativeURL = `file://${this.fullPath}`;
41
+ this.name = cleanPath.split('/').pop() || '';
30
42
  this.filesystem = null;
31
43
  }
32
44
  /**
33
45
  * Remove a file or empty directory
34
46
  */
35
47
  remove(callback, errorCallback) {
36
- RNFS.unlink(this.fullPath)
48
+ if (!RNFS) {
49
+ errorCallback(new Error('react-native-fs is not available'));
50
+ return;
51
+ }
52
+ const targetPath = this.fullPath.replace(/\/+$/, '');
53
+ RNFS.unlink(targetPath)
37
54
  .then(() => callback())
38
55
  .catch(errorCallback);
39
56
  }
@@ -41,8 +58,12 @@ class RNFileEntry {
41
58
  * Remove a directory and all its contents recursively
42
59
  */
43
60
  removeRecursively(callback, errorCallback) {
44
- // RNFS.unlink works recursively for directories
45
- RNFS.unlink(this.fullPath)
61
+ if (!RNFS) {
62
+ errorCallback(new Error('react-native-fs is not available'));
63
+ return;
64
+ }
65
+ const targetPath = this.fullPath.replace(/\/+$/, '');
66
+ RNFS.unlink(targetPath)
46
67
  .then(() => callback())
47
68
  .catch(errorCallback);
48
69
  }
@@ -56,11 +77,17 @@ class RNFileEntry {
56
77
  * Get or create a subdirectory
57
78
  */
58
79
  getDirectory(path, options, callback, errorCallback) {
59
- const dirPath = `${this.fullPath}/${path}`;
80
+ if (!RNFS) {
81
+ errorCallback(new Error('react-native-fs is not available'));
82
+ return;
83
+ }
84
+ const basePath = this.fullPath.replace(/\/+$/, '');
85
+ const relPath = path.replace(/^\/+/, '').replace(/\/+$/, '');
86
+ const dirPath = `${basePath}/${relPath}`;
60
87
  RNFS.exists(dirPath)
61
- .then(exists => {
88
+ .then((exists) => {
62
89
  if (exists) {
63
- return RNFS.stat(dirPath).then(stats => {
90
+ return RNFS.stat(dirPath).then((stats) => {
64
91
  if (stats.isDirectory()) {
65
92
  callback(new RNFileEntry(dirPath, true));
66
93
  }
@@ -84,11 +111,17 @@ class RNFileEntry {
84
111
  * Get or create a file
85
112
  */
86
113
  getFile(path, options, callback, errorCallback) {
87
- const filePath = `${this.fullPath}/${path}`;
114
+ if (!RNFS) {
115
+ errorCallback(new Error('react-native-fs is not available'));
116
+ return;
117
+ }
118
+ const basePath = this.fullPath.replace(/\/+$/, '');
119
+ const relPath = path.replace(/^\/+/, '');
120
+ const filePath = `${basePath}/${relPath}`;
88
121
  RNFS.exists(filePath)
89
- .then(exists => {
122
+ .then((exists) => {
90
123
  if (exists) {
91
- return RNFS.stat(filePath).then(stats => {
124
+ return RNFS.stat(filePath).then((stats) => {
92
125
  if (!stats.isDirectory()) {
93
126
  callback(new RNFileEntry(filePath, false));
94
127
  }
@@ -113,16 +146,21 @@ class RNFileEntry {
113
146
  * Get file metadata
114
147
  */
115
148
  file(callback, errorCallback) {
116
- RNFS.stat(this.fullPath)
117
- .then(stats => {
149
+ if (!RNFS) {
150
+ errorCallback(new Error('react-native-fs is not available'));
151
+ return;
152
+ }
153
+ const targetPath = this.fullPath.replace(/\/+$/, '');
154
+ RNFS.stat(targetPath)
155
+ .then((stats) => {
118
156
  // Create a File-like object with metadata
119
157
  const fileObject = {
120
- name: this.fullPath.split('/').pop() || '',
158
+ name: targetPath.split('/').pop() || '',
121
159
  size: stats.size,
122
160
  type: '', // RNFS doesn't provide MIME type directly
123
161
  lastModified: new Date(stats.mtime).getTime(),
124
162
  lastModifiedDate: new Date(stats.mtime),
125
- path: this.fullPath,
163
+ path: targetPath,
126
164
  };
127
165
  callback(fileObject);
128
166
  })
@@ -132,29 +170,35 @@ class RNFileEntry {
132
170
  * Create a file writer for writing to the file
133
171
  */
134
172
  createWriter(callback, errorCallback) {
135
- // Create a FileWriter-like object
173
+ const filePath = this.fullPath.replace(/\/+$/, '');
136
174
  const writer = {
137
- filePath: this.fullPath,
175
+ filePath: filePath,
138
176
  write: (data) => {
139
- return RNFS.writeFile(this.fullPath, data, 'utf8')
177
+ if (!RNFS)
178
+ return Promise.reject(new Error('react-native-fs is not available'));
179
+ return RNFS.writeFile(filePath, data, 'utf8')
140
180
  .then(() => { if (writer.onwriteend)
141
181
  writer.onwriteend(); })
142
182
  .catch((err) => { if (writer.onerror)
143
183
  writer.onerror(err); });
144
184
  },
145
185
  append: (data) => {
146
- return RNFS.appendFile(this.fullPath, data, 'utf8')
186
+ if (!RNFS)
187
+ return Promise.reject(new Error('react-native-fs is not available'));
188
+ return RNFS.appendFile(filePath, data, 'utf8')
147
189
  .then(() => { if (writer.onwriteend)
148
190
  writer.onwriteend(); })
149
191
  .catch((err) => { if (writer.onerror)
150
192
  writer.onerror(err); });
151
193
  },
152
194
  truncate: (size) => {
195
+ if (!RNFS)
196
+ return Promise.reject(new Error('react-native-fs is not available'));
153
197
  // Read file, truncate content, and write back
154
- return RNFS.readFile(this.fullPath, 'utf8')
155
- .then(content => {
198
+ return RNFS.readFile(filePath, 'utf8')
199
+ .then((content) => {
156
200
  const truncated = content.substring(0, size);
157
- return RNFS.writeFile(this.fullPath, truncated, 'utf8')
201
+ return RNFS.writeFile(filePath, truncated, 'utf8')
158
202
  .then(() => { if (writer.onwriteend)
159
203
  writer.onwriteend(); });
160
204
  })
@@ -162,8 +206,6 @@ class RNFileEntry {
162
206
  writer.onerror(err); });
163
207
  },
164
208
  seek: (offset) => {
165
- // Not directly supported in RNFS
166
- // This would need to be implemented with read/write operations
167
209
  return Promise.resolve();
168
210
  },
169
211
  onwriteend: null,
@@ -178,20 +220,35 @@ class RNFileEntry {
178
220
  }
179
221
  }
180
222
  export class FileSystemNative {
223
+ /**
224
+ * Check if react-native-fs is available in runtime
225
+ */
226
+ static isAvailable() {
227
+ return !!RNFS && !!RNFS.DocumentDirectoryPath;
228
+ }
181
229
  getDocumentDirectory() {
182
- return RNFS.DocumentDirectoryPath;
230
+ return (RNFS === null || RNFS === void 0 ? void 0 : RNFS.DocumentDirectoryPath) || '';
183
231
  }
184
232
  async resolveLocalFileSystemURL(url) {
233
+ if (!RNFS) {
234
+ throw new Error('react-native-fs is not available');
235
+ }
185
236
  return new Promise((resolve, reject) => {
186
- // Remove file:// prefix if present
187
- const path = url.replace('file://', '');
237
+ // Remove file:// prefix, decode URI components if encoded, and normalize multiple slashes
238
+ let path = url.replace(/^file:\/\//, '');
239
+ try {
240
+ path = decodeURIComponent(path);
241
+ }
242
+ catch (e) { }
243
+ // Normalize internal multiple slashes to single slash, and strip trailing slash for RNFS.stat/exists
244
+ path = path.replace(/\/+/g, '/').replace(/\/+$/, '');
188
245
  RNFS.exists(path)
189
- .then(exists => {
246
+ .then((exists) => {
190
247
  if (!exists) {
191
248
  reject(new Error(`Path does not exist: ${path}`));
192
249
  return;
193
250
  }
194
- return RNFS.stat(path).then(stats => {
251
+ return RNFS.stat(path).then((stats) => {
195
252
  resolve(new RNFileEntry(path, stats.isDirectory()));
196
253
  });
197
254
  })
@@ -199,6 +256,9 @@ export class FileSystemNative {
199
256
  });
200
257
  }
201
258
  async getFolderBasedOnUserId(userId) {
259
+ if (!RNFS) {
260
+ throw new Error('react-native-fs is not available');
261
+ }
202
262
  const userPath = `${RNFS.DocumentDirectoryPath}/${userId}`;
203
263
  try {
204
264
  const exists = await RNFS.exists(userPath);
@@ -206,14 +266,18 @@ export class FileSystemNative {
206
266
  // Create the directory if it doesn't exist
207
267
  await RNFS.mkdir(userPath);
208
268
  }
209
- // Return the native URL format
210
- return `file://${userPath}`;
269
+ // Return the native URL format with trailing slash!
270
+ // Crucial: Core SDK appends 'Attachment/' or 'Inbox/' without a leading slash.
271
+ return `file://${userPath}/`;
211
272
  }
212
273
  catch (error) {
213
274
  throw new Error(`Failed to get/create folder for user ${userId}: ${error}`);
214
275
  }
215
276
  }
216
277
  async deleteUserFolder(userId) {
278
+ if (!RNFS) {
279
+ throw new Error('react-native-fs is not available');
280
+ }
217
281
  const userPath = `${RNFS.DocumentDirectoryPath}/${userId}`;
218
282
  try {
219
283
  const exists = await RNFS.exists(userPath);
@@ -227,36 +291,63 @@ export class FileSystemNative {
227
291
  }
228
292
  }
229
293
  async createDirectory(path) {
294
+ if (!RNFS) {
295
+ throw new Error('react-native-fs is not available');
296
+ }
230
297
  const exists = await RNFS.exists(path);
231
298
  if (!exists) {
232
299
  await RNFS.mkdir(path);
233
300
  }
234
301
  }
235
302
  async readFile(path, encoding = 'utf8') {
303
+ if (!RNFS) {
304
+ throw new Error('react-native-fs is not available');
305
+ }
236
306
  return await RNFS.readFile(path, encoding);
237
307
  }
238
308
  async writeFile(path, content, encoding = 'utf8') {
309
+ if (!RNFS) {
310
+ throw new Error('react-native-fs is not available');
311
+ }
239
312
  await RNFS.writeFile(path, content, encoding);
240
313
  }
241
314
  async deleteFile(path) {
315
+ if (!RNFS) {
316
+ throw new Error('react-native-fs is not available');
317
+ }
242
318
  const exists = await RNFS.exists(path);
243
319
  if (exists) {
244
320
  await RNFS.unlink(path);
245
321
  }
246
322
  }
247
323
  async exists(path) {
324
+ if (!RNFS) {
325
+ return false;
326
+ }
248
327
  return await RNFS.exists(path);
249
328
  }
250
329
  async stat(path) {
330
+ if (!RNFS) {
331
+ throw new Error('react-native-fs is not available');
332
+ }
251
333
  return await RNFS.stat(path);
252
334
  }
253
335
  async readDir(path) {
336
+ if (!RNFS) {
337
+ throw new Error('react-native-fs is not available');
338
+ }
254
339
  return await RNFS.readDir(path);
255
340
  }
256
341
  async copyFile(source, destination) {
342
+ if (!RNFS) {
343
+ throw new Error('react-native-fs is not available');
344
+ }
257
345
  await RNFS.copyFile(source, destination);
258
346
  }
259
347
  async moveFile(source, destination) {
348
+ if (!RNFS) {
349
+ throw new Error('react-native-fs is not available');
350
+ }
260
351
  await RNFS.moveFile(source, destination);
261
352
  }
262
353
  }
@@ -1,6 +1,6 @@
1
1
  import type { IFileEntry, IFileSystem, FileSystemEncoding } from "../FileSystem";
2
2
  /**
3
- * FileSystemWeb - Virtual browser-backed file system with localStorage persistence
3
+ * FileSystem implementation for Web using localStorage
4
4
  */
5
5
  export declare class FileSystemWeb implements IFileSystem {
6
6
  private baseDir;
@@ -1,26 +1,26 @@
1
1
  class WebDirectoryReader {
2
- constructor(fullPath) {
3
- this.fullPath = fullPath;
2
+ constructor(dirPath) {
3
+ this.dirPath = dirPath.replace(/\/+$/, "");
4
4
  }
5
- readEntries(successCallback, errorCallback) {
5
+ readEntries(callback, errorCallback) {
6
6
  try {
7
7
  const entries = [];
8
- const prefix = `__vfs_${this.fullPath}/`;
8
+ const prefix = `__vfs_${this.dirPath}/`;
9
9
  if (typeof localStorage !== "undefined") {
10
10
  for (let i = 0; i < localStorage.length; i++) {
11
11
  const key = localStorage.key(i);
12
12
  if (key && key.startsWith(prefix)) {
13
13
  const relPath = key.substring(prefix.length);
14
- const segment = relPath.split("/")[0];
15
- const entryFullPath = `${this.fullPath}/${segment}`;
16
- const isDir = relPath.includes("/");
17
- if (!entries.find((e) => e.fullPath === entryFullPath)) {
18
- entries.push(new WebFileEntry(entryFullPath, isDir));
14
+ const name = relPath.split("/")[0];
15
+ const fullPath = `${this.dirPath}/${name}`;
16
+ if (!entries.find((e) => e.name === name)) {
17
+ const isDir = relPath.includes("/");
18
+ entries.push(new WebFileEntry(fullPath, isDir));
19
19
  }
20
20
  }
21
21
  }
22
22
  }
23
- successCallback(entries);
23
+ callback(entries);
24
24
  }
25
25
  catch (e) {
26
26
  errorCallback(e);
@@ -29,16 +29,19 @@ class WebDirectoryReader {
29
29
  }
30
30
  class WebFileEntry {
31
31
  constructor(fullPath, isDirectory) {
32
- this.fullPath = fullPath.replace(/\/+/g, "/");
33
- this.name = this.fullPath.split("/").filter(Boolean).pop() || "root";
32
+ const cleanPath = fullPath.replace(/\/+/g, "/").replace(/\/+$/, "");
33
+ this.name = cleanPath.split("/").filter(Boolean).pop() || "root";
34
34
  this.isFile = !isDirectory;
35
35
  this.isDirectory = isDirectory;
36
+ // Cordova spec: directories must end with trailing slash in fullPath and nativeURL
37
+ this.fullPath = isDirectory ? `${cleanPath}/` : cleanPath;
36
38
  this.nativeURL = `file://${this.fullPath}`;
37
39
  }
38
40
  remove(callback, errorCallback) {
39
41
  try {
40
42
  if (typeof localStorage !== "undefined") {
41
- localStorage.removeItem(`__vfs_${this.fullPath}`);
43
+ const targetPath = this.fullPath.replace(/\/+$/, "");
44
+ localStorage.removeItem(`__vfs_${targetPath}`);
42
45
  }
43
46
  callback();
44
47
  }
@@ -49,7 +52,8 @@ class WebFileEntry {
49
52
  removeRecursively(callback, errorCallback) {
50
53
  try {
51
54
  if (typeof localStorage !== "undefined") {
52
- const prefix = `__vfs_${this.fullPath}`;
55
+ const targetPath = this.fullPath.replace(/\/+$/, "");
56
+ const prefix = `__vfs_${targetPath}`;
53
57
  const keysToRemove = [];
54
58
  for (let i = 0; i < localStorage.length; i++) {
55
59
  const key = localStorage.key(i);
@@ -69,96 +73,71 @@ class WebFileEntry {
69
73
  return new WebDirectoryReader(this.fullPath);
70
74
  }
71
75
  getDirectory(path, options, callback, errorCallback) {
72
- const dirPath = `${this.fullPath}/${path}`.replace(/\/+/g, "/");
73
- const entry = new WebFileEntry(dirPath, true);
74
- if ((options === null || options === void 0 ? void 0 : options.create) && typeof localStorage !== "undefined") {
75
- localStorage.setItem(`__vfs_${dirPath}`, JSON.stringify({ isDir: true }));
76
+ const basePath = this.fullPath.replace(/\/+$/, "");
77
+ const relPath = path.replace(/^\/+/, "").replace(/\/+$/, "");
78
+ const dirPath = `${basePath}/${relPath}`;
79
+ if (options.create) {
80
+ if (typeof localStorage !== "undefined") {
81
+ localStorage.setItem(`__vfs_${dirPath}`, JSON.stringify({ isDir: true }));
82
+ }
76
83
  }
77
- callback(entry);
84
+ callback(new WebFileEntry(dirPath, true));
78
85
  }
79
86
  getFile(path, options, callback, errorCallback) {
80
- const filePath = `${this.fullPath}/${path}`.replace(/\/+/g, "/");
81
- const key = `__vfs_${filePath}`;
82
- if ((options === null || options === void 0 ? void 0 : options.create) && typeof localStorage !== "undefined") {
83
- if (localStorage.getItem(key) === null) {
84
- localStorage.setItem(key, "");
87
+ const basePath = this.fullPath.replace(/\/+$/, "");
88
+ const relPath = path.replace(/^\/+/, "");
89
+ const filePath = `${basePath}/${relPath}`;
90
+ if (options.create) {
91
+ if (typeof localStorage !== "undefined") {
92
+ if (localStorage.getItem(`__vfs_${filePath}`) === null) {
93
+ localStorage.setItem(`__vfs_${filePath}`, "");
94
+ }
85
95
  }
86
96
  }
87
- const entry = new WebFileEntry(filePath, false);
88
- callback(entry);
97
+ callback(new WebFileEntry(filePath, false));
89
98
  }
90
99
  file(callback, errorCallback) {
91
100
  try {
92
- let content = "";
93
- if (typeof localStorage !== "undefined") {
94
- content = localStorage.getItem(`__vfs_${this.fullPath}`) || "";
95
- }
96
- const fileObj = {
97
- name: this.name,
98
- size: content.length,
99
- type: "text/plain",
100
- lastModified: Date.now(),
101
- lastModifiedDate: new Date(),
102
- path: this.fullPath,
103
- };
104
- callback(fileObj);
101
+ const targetPath = this.fullPath.replace(/\/+$/, "");
102
+ const content = typeof localStorage !== "undefined"
103
+ ? localStorage.getItem(`__vfs_${targetPath}`) || ""
104
+ : "";
105
+ const blob = new Blob([content], { type: "text/plain" });
106
+ callback(blob);
105
107
  }
106
108
  catch (e) {
107
109
  errorCallback(e);
108
110
  }
109
111
  }
110
112
  createWriter(callback, errorCallback) {
111
- const filePath = this.fullPath;
113
+ const filePath = this.fullPath.replace(/\/+$/, "");
112
114
  const writer = {
113
- filePath,
114
- write: (data) => {
115
- try {
116
- if (typeof localStorage !== "undefined") {
117
- localStorage.setItem(`__vfs_${filePath}`, data);
118
- }
119
- if (writer.onwriteend)
120
- writer.onwriteend();
121
- return Promise.resolve();
122
- }
123
- catch (err) {
124
- if (writer.onerror)
125
- writer.onerror(err);
126
- return Promise.reject(err);
127
- }
128
- },
129
- append: (data) => {
115
+ write: (blob) => {
130
116
  try {
131
- if (typeof localStorage !== "undefined") {
132
- const existing = localStorage.getItem(`__vfs_${filePath}`) || "";
133
- localStorage.setItem(`__vfs_${filePath}`, existing + data);
117
+ if (blob instanceof Blob) {
118
+ const reader = new FileReader();
119
+ reader.onloadend = () => {
120
+ if (typeof localStorage !== "undefined") {
121
+ localStorage.setItem(`__vfs_${filePath}`, reader.result);
122
+ }
123
+ if (writer.onwriteend)
124
+ writer.onwriteend();
125
+ };
126
+ reader.readAsText(blob);
134
127
  }
135
- if (writer.onwriteend)
136
- writer.onwriteend();
137
- return Promise.resolve();
138
- }
139
- catch (err) {
140
- if (writer.onerror)
141
- writer.onerror(err);
142
- return Promise.reject(err);
143
- }
144
- },
145
- truncate: (size) => {
146
- try {
147
- if (typeof localStorage !== "undefined") {
148
- const existing = localStorage.getItem(`__vfs_${filePath}`) || "";
149
- localStorage.setItem(`__vfs_${filePath}`, existing.substring(0, size));
128
+ else {
129
+ if (typeof localStorage !== "undefined") {
130
+ localStorage.setItem(`__vfs_${filePath}`, String(blob));
131
+ }
132
+ if (writer.onwriteend)
133
+ writer.onwriteend();
150
134
  }
151
- if (writer.onwriteend)
152
- writer.onwriteend();
153
- return Promise.resolve();
154
135
  }
155
- catch (err) {
136
+ catch (e) {
156
137
  if (writer.onerror)
157
- writer.onerror(err);
158
- return Promise.reject(err);
138
+ writer.onerror(e);
159
139
  }
160
140
  },
161
- seek: () => Promise.resolve(),
162
141
  onwriteend: null,
163
142
  onerror: null,
164
143
  };
@@ -166,23 +145,29 @@ class WebFileEntry {
166
145
  }
167
146
  }
168
147
  /**
169
- * FileSystemWeb - Virtual browser-backed file system with localStorage persistence
148
+ * FileSystem implementation for Web using localStorage
170
149
  */
171
150
  export class FileSystemWeb {
172
151
  constructor() {
173
- this.baseDir = "/virtual-fs";
152
+ this.baseDir = "/unvired_app_fs";
174
153
  }
175
154
  getDocumentDirectory() {
176
155
  return this.baseDir;
177
156
  }
178
157
  async resolveLocalFileSystemURL(url) {
179
- const path = url.replace(/^file:\/\//, "");
158
+ let path = url.replace(/^file:\/\//, "");
159
+ try {
160
+ path = decodeURIComponent(path);
161
+ }
162
+ catch (e) { }
163
+ path = path.replace(/\/+/g, "/").replace(/\/+$/, "");
180
164
  return new WebFileEntry(path, false);
181
165
  }
182
166
  async getFolderBasedOnUserId(userId) {
183
167
  const folder = `${this.baseDir}/users/${userId}`;
184
168
  await this.createDirectory(folder);
185
- return `file://${folder}`;
169
+ // Return native URL with trailing slash!
170
+ return `file://${folder}/`;
186
171
  }
187
172
  async deleteUserFolder(userId) {
188
173
  const prefix = `__vfs_${this.baseDir}/users/${userId}`;
@@ -198,38 +183,44 @@ export class FileSystemWeb {
198
183
  }
199
184
  }
200
185
  async createDirectory(path) {
186
+ const cleanPath = path.replace(/\/+$/, "");
201
187
  if (typeof localStorage !== "undefined") {
202
- localStorage.setItem(`__vfs_${path}`, JSON.stringify({ isDir: true }));
188
+ localStorage.setItem(`__vfs_${cleanPath}`, JSON.stringify({ isDir: true }));
203
189
  }
204
190
  }
205
191
  async readFile(path, encoding = "utf8") {
192
+ const cleanPath = path.replace(/\/+$/, "");
206
193
  if (typeof localStorage !== "undefined") {
207
- const val = localStorage.getItem(`__vfs_${path}`);
194
+ const val = localStorage.getItem(`__vfs_${cleanPath}`);
208
195
  if (val !== null)
209
196
  return val;
210
197
  }
211
198
  throw new Error(`File not found: ${path}`);
212
199
  }
213
200
  async writeFile(path, content, encoding = "utf8") {
201
+ const cleanPath = path.replace(/\/+$/, "");
214
202
  if (typeof localStorage !== "undefined") {
215
- localStorage.setItem(`__vfs_${path}`, content);
203
+ localStorage.setItem(`__vfs_${cleanPath}`, content);
216
204
  }
217
205
  }
218
206
  async deleteFile(path) {
207
+ const cleanPath = path.replace(/\/+$/, "");
219
208
  if (typeof localStorage !== "undefined") {
220
- localStorage.removeItem(`__vfs_${path}`);
209
+ localStorage.removeItem(`__vfs_${cleanPath}`);
221
210
  }
222
211
  }
223
212
  async exists(path) {
213
+ const cleanPath = path.replace(/\/+$/, "");
224
214
  if (typeof localStorage !== "undefined") {
225
- return localStorage.getItem(`__vfs_${path}`) !== null;
215
+ return localStorage.getItem(`__vfs_${cleanPath}`) !== null;
226
216
  }
227
217
  return false;
228
218
  }
229
219
  async stat(path) {
220
+ const cleanPath = path.replace(/\/+$/, "");
230
221
  let size = 0;
231
222
  if (typeof localStorage !== "undefined") {
232
- const val = localStorage.getItem(`__vfs_${path}`);
223
+ const val = localStorage.getItem(`__vfs_${cleanPath}`);
233
224
  if (val !== null)
234
225
  size = val.length;
235
226
  }
@@ -242,7 +233,8 @@ export class FileSystemWeb {
242
233
  };
243
234
  }
244
235
  async readDir(path) {
245
- const prefix = `__vfs_${path}/`;
236
+ const cleanPath = path.replace(/\/+$/, "");
237
+ const prefix = `__vfs_${cleanPath}/`;
246
238
  const results = [];
247
239
  if (typeof localStorage !== "undefined") {
248
240
  for (let i = 0; i < localStorage.length; i++) {
@@ -252,7 +244,7 @@ export class FileSystemWeb {
252
244
  if (!results.find((r) => r.name === name)) {
253
245
  results.push({
254
246
  name,
255
- path: `${path}/${name}`,
247
+ path: `${cleanPath}/${name}`,
256
248
  size: (localStorage.getItem(key) || "").length,
257
249
  isFile: () => true,
258
250
  isDirectory: () => false,
@@ -1,4 +1,5 @@
1
1
  export declare class StorageNative {
2
+ static isMMKVAvailable(): boolean;
2
3
  getItem(key: string): string | null;
3
4
  setItem(key: string, value: string): void;
4
5
  removeItem(key: string): void;